From f29f6946cd47ca8a54a484c6d548abb02e777564 Mon Sep 17 00:00:00 2001 From: B <6723574+louisgv@users.noreply.github.com> Date: Wed, 11 Feb 2026 00:28:50 +0000 Subject: [PATCH] refactor: Remove 8 GPU cloud providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spawn agents use remote LLM APIs for inference — they need cheap CPU instances, not expensive GPU VMs. Removed: - Lambda Cloud - RunPod - Vast.ai - Hyperstack - FluidStack - Genesis Cloud - Paperspace - Crusoe Cloud This removes 112 matrix entries and ~8700 lines of GPU-specific code. Remaining: 25 clouds, 350 matrix entries — all affordable CPU compute. Co-Authored-By: Claude Opus 4.6 (1M context) --- crusoe/README.md | 108 ----------- crusoe/aider.sh | 66 ------- crusoe/claude.sh | 76 -------- crusoe/lib/common.sh | 262 -------------------------- crusoe/openclaw.sh | 66 ------- fluidstack/README.md | 56 ------ fluidstack/aider.sh | 55 ------ fluidstack/amazonq.sh | 59 ------ fluidstack/claude.sh | 71 ------- fluidstack/cline.sh | 59 ------ fluidstack/codex.sh | 59 ------ fluidstack/gemini.sh | 60 ------ fluidstack/goose.sh | 65 ------- fluidstack/gptme.sh | 54 ------ fluidstack/interpreter.sh | 59 ------ fluidstack/kilocode.sh | 59 ------ fluidstack/lib/common.sh | 308 ------------------------------ fluidstack/nanoclaw.sh | 74 -------- fluidstack/openclaw.sh | 67 ------- fluidstack/opencode.sh | 58 ------ fluidstack/plandex.sh | 64 ------- genesiscloud/README.md | 73 -------- genesiscloud/aider.sh | 53 ------ genesiscloud/amazonq.sh | 48 ----- genesiscloud/claude.sh | 58 ------ genesiscloud/cline.sh | 48 ----- genesiscloud/codex.sh | 48 ----- genesiscloud/gemini.sh | 49 ----- genesiscloud/goose.sh | 53 ------ genesiscloud/gptme.sh | 54 ------ genesiscloud/interpreter.sh | 48 ----- genesiscloud/kilocode.sh | 48 ----- genesiscloud/lib/common.sh | 276 --------------------------- genesiscloud/nanoclaw.sh | 61 ------ genesiscloud/openclaw.sh | 55 ------ genesiscloud/opencode.sh | 46 ----- genesiscloud/plandex.sh | 52 ------ hyperstack/README.md | 200 -------------------- hyperstack/aider.sh | 68 ------- hyperstack/amazonq.sh | 43 ----- hyperstack/claude.sh | 75 -------- hyperstack/cline.sh | 51 ----- hyperstack/codex.sh | 49 ----- hyperstack/gemini.sh | 48 ----- hyperstack/goose.sh | 62 ------ hyperstack/gptme.sh | 67 ------- hyperstack/interpreter.sh | 49 ----- hyperstack/kilocode.sh | 51 ----- hyperstack/lib/common.sh | 297 ----------------------------- hyperstack/nanoclaw.sh | 75 -------- hyperstack/openclaw.sh | 71 ------- hyperstack/opencode.sh | 46 ----- hyperstack/plandex.sh | 63 ------- lambda/README.md | 94 ---------- lambda/aider.sh | 67 ------- lambda/amazonq.sh | 62 ------ lambda/claude.sh | 73 -------- lambda/cline.sh | 62 ------ lambda/codex.sh | 62 ------ lambda/gemini.sh | 63 ------- lambda/goose.sh | 60 ------ lambda/gptme.sh | 65 ------- lambda/interpreter.sh | 62 ------ lambda/kilocode.sh | 62 ------ lambda/lib/common.sh | 246 ------------------------ lambda/nanoclaw.sh | 75 -------- lambda/openclaw.sh | 69 ------- lambda/opencode.sh | 60 ------ lambda/plandex.sh | 60 ------ manifest.json | 241 +----------------------- paperspace/README.md | 56 ------ paperspace/aider.sh | 69 ------- paperspace/claude.sh | 79 -------- paperspace/lib/common.sh | 307 ------------------------------ paperspace/openclaw.sh | 69 ------- runpod/README.md | 118 ------------ runpod/aider.sh | 55 ------ runpod/amazonq.sh | 49 ----- runpod/claude.sh | 71 ------- runpod/cline.sh | 49 ----- runpod/codex.sh | 49 ----- runpod/gemini.sh | 50 ----- runpod/goose.sh | 54 ------ runpod/gptme.sh | 54 ------ runpod/interpreter.sh | 49 ----- runpod/kilocode.sh | 49 ----- runpod/lib/common.sh | 321 -------------------------------- runpod/nanoclaw.sh | 63 ------- runpod/openclaw.sh | 56 ------ runpod/opencode.sh | 47 ----- runpod/plandex.sh | 53 ------ vastai/README.md | 56 ------ vastai/aider.sh | 55 ------ vastai/amazonq.sh | 58 ------ vastai/claude.sh | 69 ------- vastai/cline.sh | 58 ------ vastai/codex.sh | 49 ----- vastai/gemini.sh | 59 ------ vastai/goose.sh | 57 ------ vastai/gptme.sh | 65 ------- vastai/interpreter.sh | 58 ------ vastai/kilocode.sh | 58 ------ vastai/lib/common.sh | 362 ------------------------------------ vastai/nanoclaw.sh | 73 -------- vastai/openclaw.sh | 66 ------- vastai/opencode.sh | 56 ------ vastai/plandex.sh | 62 ------ 107 files changed, 2 insertions(+), 8699 deletions(-) delete mode 100644 crusoe/README.md delete mode 100755 crusoe/aider.sh delete mode 100755 crusoe/claude.sh delete mode 100644 crusoe/lib/common.sh delete mode 100755 crusoe/openclaw.sh delete mode 100644 fluidstack/README.md delete mode 100755 fluidstack/aider.sh delete mode 100644 fluidstack/amazonq.sh delete mode 100755 fluidstack/claude.sh delete mode 100644 fluidstack/cline.sh delete mode 100644 fluidstack/codex.sh delete mode 100644 fluidstack/gemini.sh delete mode 100644 fluidstack/goose.sh delete mode 100755 fluidstack/gptme.sh delete mode 100644 fluidstack/interpreter.sh delete mode 100644 fluidstack/kilocode.sh delete mode 100644 fluidstack/lib/common.sh delete mode 100644 fluidstack/nanoclaw.sh delete mode 100644 fluidstack/openclaw.sh delete mode 100644 fluidstack/opencode.sh delete mode 100644 fluidstack/plandex.sh delete mode 100644 genesiscloud/README.md delete mode 100644 genesiscloud/aider.sh delete mode 100644 genesiscloud/amazonq.sh delete mode 100644 genesiscloud/claude.sh delete mode 100644 genesiscloud/cline.sh delete mode 100644 genesiscloud/codex.sh delete mode 100644 genesiscloud/gemini.sh delete mode 100644 genesiscloud/goose.sh delete mode 100644 genesiscloud/gptme.sh delete mode 100644 genesiscloud/interpreter.sh delete mode 100644 genesiscloud/kilocode.sh delete mode 100644 genesiscloud/lib/common.sh delete mode 100644 genesiscloud/nanoclaw.sh delete mode 100644 genesiscloud/openclaw.sh delete mode 100644 genesiscloud/opencode.sh delete mode 100644 genesiscloud/plandex.sh delete mode 100644 hyperstack/README.md delete mode 100644 hyperstack/aider.sh delete mode 100644 hyperstack/amazonq.sh delete mode 100644 hyperstack/claude.sh delete mode 100644 hyperstack/cline.sh delete mode 100644 hyperstack/codex.sh delete mode 100644 hyperstack/gemini.sh delete mode 100644 hyperstack/goose.sh delete mode 100644 hyperstack/gptme.sh delete mode 100644 hyperstack/interpreter.sh delete mode 100644 hyperstack/kilocode.sh delete mode 100644 hyperstack/lib/common.sh delete mode 100644 hyperstack/nanoclaw.sh delete mode 100644 hyperstack/openclaw.sh delete mode 100644 hyperstack/opencode.sh delete mode 100644 hyperstack/plandex.sh delete mode 100644 lambda/README.md delete mode 100644 lambda/aider.sh delete mode 100644 lambda/amazonq.sh delete mode 100644 lambda/claude.sh delete mode 100644 lambda/cline.sh delete mode 100644 lambda/codex.sh delete mode 100644 lambda/gemini.sh delete mode 100644 lambda/goose.sh delete mode 100644 lambda/gptme.sh delete mode 100644 lambda/interpreter.sh delete mode 100644 lambda/kilocode.sh delete mode 100644 lambda/lib/common.sh delete mode 100644 lambda/nanoclaw.sh delete mode 100755 lambda/openclaw.sh delete mode 100644 lambda/opencode.sh delete mode 100644 lambda/plandex.sh delete mode 100644 paperspace/README.md delete mode 100644 paperspace/aider.sh delete mode 100644 paperspace/claude.sh delete mode 100644 paperspace/lib/common.sh delete mode 100644 paperspace/openclaw.sh delete mode 100644 runpod/README.md delete mode 100644 runpod/aider.sh delete mode 100644 runpod/amazonq.sh delete mode 100644 runpod/claude.sh delete mode 100644 runpod/cline.sh delete mode 100644 runpod/codex.sh delete mode 100644 runpod/gemini.sh delete mode 100644 runpod/goose.sh delete mode 100644 runpod/gptme.sh delete mode 100644 runpod/interpreter.sh delete mode 100644 runpod/kilocode.sh delete mode 100644 runpod/lib/common.sh delete mode 100644 runpod/nanoclaw.sh delete mode 100644 runpod/openclaw.sh delete mode 100644 runpod/opencode.sh delete mode 100644 runpod/plandex.sh delete mode 100644 vastai/README.md delete mode 100644 vastai/aider.sh delete mode 100644 vastai/amazonq.sh delete mode 100644 vastai/claude.sh delete mode 100644 vastai/cline.sh delete mode 100644 vastai/codex.sh delete mode 100644 vastai/gemini.sh delete mode 100644 vastai/goose.sh delete mode 100644 vastai/gptme.sh delete mode 100644 vastai/interpreter.sh delete mode 100644 vastai/kilocode.sh delete mode 100644 vastai/lib/common.sh delete mode 100644 vastai/nanoclaw.sh delete mode 100644 vastai/openclaw.sh delete mode 100644 vastai/opencode.sh delete mode 100644 vastai/plandex.sh diff --git a/crusoe/README.md b/crusoe/README.md deleted file mode 100644 index 0d67eed7..00000000 --- a/crusoe/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# Crusoe Cloud - -Crusoe Cloud GPU instances via CLI. [Crusoe Cloud](https://crusoecloud.com/) - -## Prerequisites - -1. Install the Crusoe CLI: - -```bash -# Debian/Ubuntu -echo "deb [trusted=yes] https://apt.fury.io/crusoe/ * *" | sudo tee /etc/apt/sources.list.d/fury.list -sudo apt update && sudo apt install crusoe - -# macOS/Other -# Visit: https://docs.crusoecloud.com/quickstart/install-cli -``` - -2. Generate API credentials at [Crusoe Console](https://console.crusoecloud.com/): - - Navigate to: Security → API Access → Create Access Key - - Save the Access Key ID and Secret Key - -3. Create config file at `~/.crusoe/config`: - -```ini -[default] -default_project="default" -access_key_id="YOUR_ACCESS_KEY_ID" -secret_key="YOUR_SECRET_KEY" -``` - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/crusoe/claude.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/crusoe/aider.sh) -``` - -#### OpenClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/crusoe/openclaw.sh) -``` - -## Non-Interactive Mode - -```bash -CRUSOE_VM_NAME=dev-mk1 \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/crusoe/claude.sh) -``` - -## Environment Variables - -- `CRUSOE_VM_NAME` - VM name (default: prompts) -- `CRUSOE_VM_TYPE` - VM type (default: `a40.1x`) -- `CRUSOE_LOCATION` - Location (default: `us-east1-a`) -- `OPENROUTER_API_KEY` - OpenRouter API key (default: prompts or OAuth) - -## Available VM Types - -List available VM types: - -```bash -crusoe compute vm-types list -``` - -Common GPU types: -- `a40.1x` - NVIDIA A40 (default, 1 GPU) -- `l40s-48gb.8x` - NVIDIA L40S (8 GPUs) -- `h100-80gb-sxm-ib.8x` - NVIDIA H100 (8 GPUs) - -## Pricing - -Crusoe Cloud offers competitive GPU pricing starting at $1.45/GPU-hr for on-demand L40S instances. They also offer: - -- **On-demand pricing** - Pay-per-hour, no commitment -- **Spot pricing** - Up to 90% discount vs hyperscalers -- **Reserved pricing** - 6-month to 3-year commitments for additional savings - -View pricing: [https://crusoecloud.com/pricing](https://crusoecloud.com/pricing) - -## Locations - -List available locations: - -```bash -crusoe compute datacenter-regions list -``` - -Common regions: -- `us-east1-a` - US East (default) -- `us-southcentral1-a` - US South Central -- `us-northcentral1-a` - US North Central - -## Notes - -- GPU-focused cloud provider with carbon-reducing infrastructure -- Supports NVIDIA H200/H100/L40S/A100 and AMD MI300X GPUs -- VMs run Ubuntu 22.04 by default -- Uses `root` user for SSH access -- Startup scripts support cloud-init format diff --git a/crusoe/aider.sh b/crusoe/aider.sh deleted file mode 100755 index 0122e4af..00000000 --- a/crusoe/aider.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=crusoe/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/crusoe/lib/common.sh)" -fi - -log_info "Aider on Crusoe Cloud" -echo "" - -# 1. Ensure Crusoe CLI is installed and configured -ensure_crusoe_cli - -# 2. Generate SSH key (no registration needed, passed at creation) -ensure_ssh_key - -# 3. Get VM name and create VM -VM_NAME=$(get_vm_name) -create_vm "${VM_NAME}" - -# 4. Wait for SSH and cloud-init -verify_server_connectivity "${CRUSOE_VM_IP}" -wait_for_cloud_init "${CRUSOE_VM_IP}" 60 - -# 5. Install Aider -log_warn "Installing Aider..." -run_server "${CRUSOE_VM_IP}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -# Verify installation succeeded -if ! run_server "${CRUSOE_VM_IP}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - log_error "The 'aider' command is not available or not working properly on VM ${CRUSOE_VM_IP}" - exit 1 -fi -log_info "Aider installation verified successfully" - -# 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${CRUSOE_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Crusoe VM setup completed successfully!" -log_info "VM: ${VM_NAME} (IP: ${CRUSOE_VM_IP})" -echo "" - -# 7. Start Aider interactively -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${CRUSOE_VM_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/crusoe/claude.sh b/crusoe/claude.sh deleted file mode 100755 index 9d8342a6..00000000 --- a/crusoe/claude.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=crusoe/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/crusoe/lib/common.sh)" -fi - -log_info "Claude Code on Crusoe Cloud" -echo "" - -# 1. Ensure Crusoe CLI is installed and configured -ensure_crusoe_cli - -# 2. Generate SSH key (no registration needed, passed at creation) -ensure_ssh_key - -# 3. Get VM name and create VM -VM_NAME=$(get_vm_name) -create_vm "${VM_NAME}" - -# 4. Wait for SSH and cloud-init (already done in create_vm, but verify) -verify_server_connectivity "${CRUSOE_VM_IP}" -wait_for_cloud_init "${CRUSOE_VM_IP}" 60 - -# 5. Verify Claude Code is installed (fallback to manual install) -log_warn "Verifying Claude Code installation..." -if ! run_server "${CRUSOE_VM_IP}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${CRUSOE_VM_IP}" "curl -fsSL https://claude.ai/install.sh | bash" -fi - -# Verify installation succeeded -if ! run_server "${CRUSOE_VM_IP}" "command -v claude &> /dev/null && claude --version &> /dev/null"; then - log_error "Claude Code installation verification failed" - log_error "The 'claude' command is not available or not working properly on VM ${CRUSOE_VM_IP}" - exit 1 -fi -log_info "Claude Code installation verified successfully" - -# 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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${CRUSOE_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 7. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${CRUSOE_VM_IP}" \ - "run_server ${CRUSOE_VM_IP}" - -echo "" -log_info "Crusoe VM setup completed successfully!" -log_info "VM: ${VM_NAME} (IP: ${CRUSOE_VM_IP})" -echo "" - -# 8. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${CRUSOE_VM_IP}" "source ~/.zshrc && claude" diff --git a/crusoe/lib/common.sh b/crusoe/lib/common.sh deleted file mode 100644 index 334f339d..00000000 --- a/crusoe/lib/common.sh +++ /dev/null @@ -1,262 +0,0 @@ -#!/bin/bash -# Common bash functions for Crusoe Cloud spawn scripts -# Uses Crusoe CLI — requires `crusoe` CLI configured with credentials - -# Bash safety flags -set -eo pipefail - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "${SCRIPT_DIR}" && -f "${SCRIPT_DIR}/../../shared/common.sh" ]]; then - source "${SCRIPT_DIR}/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, nc_listen) are now in shared/common.sh - -# ============================================================ -# Crusoe Cloud specific functions -# ============================================================ - -# SSH_OPTS is now defined in shared/common.sh - -# Configurable timeout/delay constants -VM_STATUS_POLL_DELAY=${VM_STATUS_POLL_DELAY:-5} # Delay between VM status checks - -ensure_crusoe_cli() { - if ! command -v crusoe &>/dev/null; then - log_error "Crusoe CLI is required but not installed" - log_error "" - log_error "Install instructions:" - log_error " Debian/Ubuntu:" - log_error " echo \"deb [trusted=yes] https://apt.fury.io/crusoe/ * *\" | sudo tee /etc/apt/sources.list.d/fury.list" - log_error " sudo apt update && sudo apt install crusoe" - log_error "" - log_error " macOS/Other:" - log_error " Visit: https://docs.crusoecloud.com/quickstart/install-cli" - log_error "" - return 1 - fi - - # Check if configured - if [[ ! -f "${HOME}/.crusoe/config" ]]; then - log_error "Crusoe CLI not configured" - log_error "" - log_error "Configuration required:" - log_error " 1. Generate API key at: https://console.crusoecloud.com/" - log_error " Navigate to: Security → API Access → Create Access Key" - log_error "" - log_error " 2. Create config file at: ~/.crusoe/config" - log_error "" - log_error " Config format:" - log_error " [default]" - log_error " default_project=\"default\"" - log_error " access_key_id=\"YOUR_ACCESS_KEY_ID\"" - log_error " secret_key=\"YOUR_SECRET_KEY\"" - log_error "" - return 1 - fi - - # Verify credentials work by listing VMs - if ! crusoe compute vms list &>/dev/null; then - log_error "Crusoe CLI credentials invalid or expired" - log_error "" - log_error "Please regenerate credentials at: https://console.crusoecloud.com/" - log_error "Then update: ~/.crusoe/config" - return 1 - fi - - log_info "Crusoe CLI configured" -} - -ensure_ssh_key() { - local key_path="${HOME}/.ssh/id_ed25519" - local pub_path="${key_path}.pub" - - # Generate key if needed - generate_ssh_key_if_missing "${key_path}" - - # Crusoe CLI uses --keyfile flag or CRUSOE_SSH_PUBLIC_KEY_FILE env var - # No registration needed - key is passed at VM creation time - export CRUSOE_SSH_PUBLIC_KEY_FILE="${pub_path}" - log_info "SSH key ready: ${pub_path}" -} - -get_vm_name() { - get_resource_name "CRUSOE_VM_NAME" "Enter Crusoe VM name: " -} - -get_cloud_init_userdata() { - cat << 'CLOUD_INIT_EOF' -#!/bin/bash -apt-get update -y -apt-get install -y curl unzip git zsh -# Install Bun -curl -fsSL https://bun.sh/install | bash -# Install Claude Code -curl -fsSL https://claude.ai/install.sh | bash -# Configure PATH in root's bashrc and zshrc -echo 'export PATH="${HOME}/.claude/local/bin:${HOME}/.bun/bin:${PATH}"' >> /root/.bashrc -echo 'export PATH="${HOME}/.claude/local/bin:${HOME}/.bun/bin:${PATH}"' >> /root/.zshrc -touch /root/.cloud-init-complete -CLOUD_INIT_EOF -} - -# Wait for Crusoe VM to become running and get its public IP -# Sets: CRUSOE_VM_IP -# Usage: _wait_for_crusoe_vm NAME [MAX_ATTEMPTS] -_wait_for_crusoe_vm() { - local name="${1}" - local max_attempts=${2:-60} - local attempt=1 - - log_warn "Waiting for VM to become running..." - while [[ ${attempt} -le ${max_attempts} ]]; do - local state - state=$(crusoe compute vms get "${name}" --output json 2>/dev/null | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('state','unknown'))" 2>/dev/null || echo "unknown") - - if [[ "${state}" == "RUNNING" ]]; then - CRUSOE_VM_IP=$(crusoe compute vms get "${name}" --output json | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('network_interfaces',[{}])[0].get('public_ipv4',{}).get('address',''))") - export CRUSOE_VM_IP - - if [[ -z "${CRUSOE_VM_IP}" ]]; then - log_error "VM is running but has no public IP" - return 1 - fi - - log_info "VM running: IP=${CRUSOE_VM_IP}" - return 0 - fi - log_warn "VM state: ${state} (${attempt}/${max_attempts})" - sleep "${VM_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - done - - log_error "VM did not become running in time" - return 1 -} - -create_vm() { - local name="${1}" - local vm_type="${CRUSOE_VM_TYPE:-a40.1x}" - local location="${CRUSOE_LOCATION:-us-east1-a}" - local image="ubuntu22.04:latest" - - # Validate env var inputs to prevent command injection - validate_resource_name "${vm_type}" || { log_error "Invalid CRUSOE_VM_TYPE"; return 1; } - validate_region_name "${location}" || { log_error "Invalid CRUSOE_LOCATION"; return 1; } - - log_warn "Creating Crusoe VM '${name}' (type: ${vm_type}, location: ${location})..." - - local userdata - userdata=$(get_cloud_init_userdata) - - # Write userdata to temp file for --startup-script flag - local userdata_file - userdata_file=$(mktemp) - echo "${userdata}" > "${userdata_file}" - - if ! crusoe compute vms create \ - --name "${name}" \ - --type "${vm_type}" \ - --location "${location}" \ - --image "${image}" \ - --keyfile "${CRUSOE_SSH_PUBLIC_KEY_FILE}" \ - --startup-script "${userdata_file}" \ - >/dev/null 2>&1; then - rm -f "${userdata_file}" - log_error "Failed to create Crusoe VM" - log_error "" - log_error "Common causes:" - log_error " - VM name already exists" - log_error " - Invalid VM type (use: crusoe compute vm-types list)" - log_error " - Invalid location (use: crusoe compute datacenter-regions list)" - log_error " - Insufficient quota or credits" - return 1 - fi - - rm -f "${userdata_file}" - export CRUSOE_VM_NAME="${name}" - log_info "VM creation initiated: ${name}" - - # Wait for VM to be running - if ! _wait_for_crusoe_vm "${name}"; then - return 1 - fi - - # Wait for SSH to be ready - log_warn "Waiting for SSH to become available..." - if ! generic_ssh_wait "root" "${CRUSOE_VM_IP}" 300; then - log_error "SSH did not become available in time" - return 1 - fi - - # Wait for cloud-init to complete - log_warn "Waiting for cloud-init setup to complete..." - local init_wait=0 - while [[ ${init_wait} -lt 300 ]]; do - if ssh ${SSH_OPTS} -o ConnectTimeout=5 "root@${CRUSOE_VM_IP}" "test -f /root/.cloud-init-complete" 2>/dev/null; then - log_info "Cloud-init setup complete" - return 0 - fi - sleep 5 - init_wait=$((init_wait + 5)) - done - - log_error "Cloud-init did not complete in time" - return 1 -} - -cleanup_vm() { - local name="${1:-${CRUSOE_VM_NAME}}" - if [[ -z "${name}" ]]; then - log_warn "No VM name provided, skipping cleanup" - return 0 - fi - - log_warn "Cleaning up Crusoe VM: ${name}" - if crusoe compute vms delete "${name}" --confirm &>/dev/null; then - log_info "VM deleted: ${name}" - else - log_warn "Failed to delete VM (may not exist): ${name}" - fi -} - -# Verify SSH connectivity to VM -verify_server_connectivity() { - local ip="$1" - local max_attempts=${2:-30} - # SSH_OPTS is defined in shared/common.sh - # shellcheck disable=SC2154 - generic_ssh_wait "root" "$ip" "$SSH_OPTS -o ConnectTimeout=5" "echo ok" "SSH connectivity" "$max_attempts" 5 -} - -# Run a command on the VM -run_server() { - local ip="$1" - local cmd="$2" - # shellcheck disable=SC2086 - ssh $SSH_OPTS "root@$ip" "$cmd" -} - -# Upload a file to the VM -upload_file() { - local ip="$1" - local local_path="$2" - local remote_path="$3" - # shellcheck disable=SC2086 - scp $SSH_OPTS "$local_path" "root@$ip:$remote_path" -} - -# Start an interactive SSH session -interactive_session() { - local ip="$1" - local cmd="$2" - # shellcheck disable=SC2086 - ssh -t $SSH_OPTS "root@$ip" "$cmd" -} diff --git a/crusoe/openclaw.sh b/crusoe/openclaw.sh deleted file mode 100755 index c6740a22..00000000 --- a/crusoe/openclaw.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=crusoe/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/crusoe/lib/common.sh)" -fi - -log_info "OpenClaw on Crusoe Cloud" -echo "" - -# 1. Ensure Crusoe CLI is installed and configured -ensure_crusoe_cli - -# 2. Generate SSH key (no registration needed, passed at creation) -ensure_ssh_key - -# 3. Get VM name and create VM -VM_NAME=$(get_vm_name) -create_vm "${VM_NAME}" - -# 4. Wait for SSH and cloud-init -verify_server_connectivity "${CRUSOE_VM_IP}" -wait_for_cloud_init "${CRUSOE_VM_IP}" 60 - -# 5. Install openclaw via bun -log_warn "Installing openclaw..." -run_server "${CRUSOE_VM_IP}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${CRUSOE_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 7. Configure openclaw -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${CRUSOE_VM_IP}" \ - "run_server ${CRUSOE_VM_IP}" - -echo "" -log_info "Crusoe VM setup completed successfully!" -log_info "VM: ${VM_NAME} (IP: ${CRUSOE_VM_IP})" -echo "" - -# 8. Start openclaw gateway in background and launch TUI -log_warn "Starting openclaw..." -run_server "${CRUSOE_VM_IP}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${CRUSOE_VM_IP}" "source ~/.zshrc && openclaw tui" diff --git a/fluidstack/README.md b/fluidstack/README.md deleted file mode 100644 index 538ce37a..00000000 --- a/fluidstack/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# FluidStack - -FluidStack GPU cloud via REST API. [FluidStack](https://www.fluidstack.io/) - -## Prerequisites - -1. A FluidStack account with API key from [Dashboard API Keys](https://platform.fluidstack.io/dashboard/api-keys) -2. SSH public key (will be registered automatically) - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/fluidstack/claude.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/fluidstack/aider.sh) -``` - -#### gptme - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/fluidstack/gptme.sh) -``` - -## Non-Interactive Mode - -```bash -FLUIDSTACK_SERVER_NAME=dev-gpu \ -FLUIDSTACK_API_KEY=your-api-key \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/fluidstack/claude.sh) -``` - -## Environment Variables - -| Variable | Description | Default | -|---|---|---| -| `FLUIDSTACK_API_KEY` | FluidStack API key | _(prompted)_ | -| `FLUIDSTACK_SERVER_NAME` | Instance name | _(prompted)_ | -| `FLUIDSTACK_GPU_TYPE` | GPU type (e.g., `RTX_4090`, `A100`, `H100`) | `RTX_4090` | -| `FLUIDSTACK_SSH_KEY_NAME` | SSH key name | `spawn-${USER}` | -| `OPENROUTER_API_KEY` | OpenRouter API key | _(prompted via OAuth)_ | - -## Notes - -- FluidStack is a GPU cloud provider with A100s and H100s starting at $1.35/hr -- Up to 70% cheaper than traditional hyperscalers -- Zero egress fees for data transfer -- Simple REST API with Python SDK available -- SSH keys are automatically registered via the API -- Instances use the `root` user for SSH access diff --git a/fluidstack/aider.sh b/fluidstack/aider.sh deleted file mode 100755 index 5a59c99d..00000000 --- a/fluidstack/aider.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Aider on FluidStack" -echo "" - -ensure_fluidstack_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Aider..." -run_server "${FLUIDSTACK_SERVER_IP}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -if ! run_server "${FLUIDSTACK_SERVER_IP}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - exit 1 -fi -log_info "Aider installation verified successfully" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/fluidstack/amazonq.sh b/fluidstack/amazonq.sh deleted file mode 100644 index 3f90dfb9..00000000 --- a/fluidstack/amazonq.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Amazon Q CLI on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Amazon Q CLI -log_warn "Installing Amazon Q CLI..." -run_server "${FLUIDSTACK_SERVER_IP}" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" - -# 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start Amazon Q interactively -log_warn "Starting Amazon Q..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && q chat" diff --git a/fluidstack/claude.sh b/fluidstack/claude.sh deleted file mode 100755 index 40cd1281..00000000 --- a/fluidstack/claude.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Claude Code on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Verify Claude Code is installed (fallback to manual install) -log_warn "Verifying Claude Code installation..." -if ! run_server "${FLUIDSTACK_SERVER_IP}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${FLUIDSTACK_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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 8. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${FLUIDSTACK_SERVER_IP}" \ - "run_server ${FLUIDSTACK_SERVER_IP}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 9. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && claude" diff --git a/fluidstack/cline.sh b/fluidstack/cline.sh deleted file mode 100644 index ca6c439c..00000000 --- a/fluidstack/cline.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Cline on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Cline -log_warn "Installing Cline..." -run_server "${FLUIDSTACK_SERVER_IP}" "npm install -g cline" - -# 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start Cline interactively -log_warn "Starting Cline..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && cline" diff --git a/fluidstack/codex.sh b/fluidstack/codex.sh deleted file mode 100644 index 30e653e7..00000000 --- a/fluidstack/codex.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Codex CLI on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Codex CLI -log_warn "Installing Codex CLI..." -run_server "${FLUIDSTACK_SERVER_IP}" "npm install -g @openai/codex" - -# 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start Codex interactively -log_warn "Starting Codex..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && codex" diff --git a/fluidstack/gemini.sh b/fluidstack/gemini.sh deleted file mode 100644 index 48d239af..00000000 --- a/fluidstack/gemini.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Gemini CLI on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Gemini CLI -log_warn "Installing Gemini CLI..." -run_server "${FLUIDSTACK_SERVER_IP}" "npm install -g @google/gemini-cli" - -# 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "GEMINI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start Gemini interactively -log_warn "Starting Gemini..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && gemini" diff --git a/fluidstack/goose.sh b/fluidstack/goose.sh deleted file mode 100644 index 71f23c54..00000000 --- a/fluidstack/goose.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Goose on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Goose -log_warn "Installing Goose..." -run_server "${FLUIDSTACK_SERVER_IP}" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" - -# 6. Verify installation succeeded -if ! run_server "${FLUIDSTACK_SERVER_IP}" "command -v goose &> /dev/null && goose --version &> /dev/null"; then - log_error "Goose installation verification failed" - exit 1 -fi -log_info "Goose installation verified successfully" - -# 7. 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 - -# 8. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "GOOSE_PROVIDER=openrouter" \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 9. Start Goose interactively -log_warn "Starting Goose..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && goose" diff --git a/fluidstack/gptme.sh b/fluidstack/gptme.sh deleted file mode 100755 index 7b31a379..00000000 --- a/fluidstack/gptme.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# 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 - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "gptme on FluidStack" -echo "" - -ensure_fluidstack_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing gptme..." -run_server "${FLUIDSTACK_SERVER_IP}" "pip install gptme 2>/dev/null || pip3 install gptme" - -if ! run_server "${FLUIDSTACK_SERVER_IP}" "command -v gptme &> /dev/null && gptme --version &> /dev/null"; then - log_error "gptme installation verification failed" - exit 1 -fi -log_info "gptme installation verified successfully" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -log_warn "Starting gptme..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}" diff --git a/fluidstack/interpreter.sh b/fluidstack/interpreter.sh deleted file mode 100644 index 09a283d5..00000000 --- a/fluidstack/interpreter.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Open Interpreter on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Open Interpreter -log_warn "Installing Open Interpreter..." -run_server "${FLUIDSTACK_SERVER_IP}" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter" - -# 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start Open Interpreter interactively -log_warn "Starting Open Interpreter..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && interpreter" diff --git a/fluidstack/kilocode.sh b/fluidstack/kilocode.sh deleted file mode 100644 index ef52b7cd..00000000 --- a/fluidstack/kilocode.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Kilo Code on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Kilo Code CLI -log_warn "Installing Kilo Code CLI..." -run_server "${FLUIDSTACK_SERVER_IP}" "npm install -g @kilocode/cli" - -# 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "KILO_PROVIDER_TYPE=openrouter" \ - "KILO_OPEN_ROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start Kilo Code interactively -log_warn "Starting Kilo Code..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && kilocode" diff --git a/fluidstack/lib/common.sh b/fluidstack/lib/common.sh deleted file mode 100644 index 1cefd9b5..00000000 --- a/fluidstack/lib/common.sh +++ /dev/null @@ -1,308 +0,0 @@ -#!/bin/bash -# Common bash functions for FluidStack spawn scripts -# Uses FluidStack REST API — https://docs.fluidstack.io/ - -# Bash safety flags -set -eo pipefail - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "${SCRIPT_DIR}" && -f "${SCRIPT_DIR}/../../shared/common.sh" ]]; then - source "${SCRIPT_DIR}/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, nc_listen) are now in shared/common.sh - -# ============================================================ -# FluidStack specific functions -# ============================================================ - -readonly FLUIDSTACK_API_BASE="https://platform.fluidstack.io/v1" -# SSH_OPTS is defined in shared/common.sh - -# Configurable timeout/delay constants -INSTANCE_STATUS_POLL_DELAY=${INSTANCE_STATUS_POLL_DELAY:-10} # Delay between instance status checks -SSH_RETRY_DELAY=${SSH_RETRY_DELAY:-5} # Delay between SSH connection retry attempts - -# FluidStack API wrapper -# Usage: fluidstack_api METHOD ENDPOINT [BODY] -fluidstack_api() { - local method="${1}" - local endpoint="${2}" - local body="${3:-}" - - if [[ -n "${body}" ]]; then - curl -s -X "${method}" \ - -H "Content-Type: application/json" \ - -H "api-key: ${FLUIDSTACK_API_KEY}" \ - "${FLUIDSTACK_API_BASE}${endpoint}" \ - -d "${body}" - else - curl -s -X "${method}" \ - -H "api-key: ${FLUIDSTACK_API_KEY}" \ - "${FLUIDSTACK_API_BASE}${endpoint}" - fi -} - -test_fluidstack_token() { - local response - response=$(fluidstack_api GET "/ssh_keys") - if echo "${response}" | grep -q '"ssh_keys"'; then - log_info "API key validated" - return 0 - else - local error_msg - error_msg=$(echo "${response}" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error','No details available'))" 2>/dev/null || echo "Unable to parse error") - log_error "API Error: ${error_msg}" - log_warn "Remediation steps:" - log_warn " 1. Verify API key at: https://platform.fluidstack.io/dashboard/api-keys" - log_warn " 2. Ensure the key has appropriate permissions" - log_warn " 3. Check key hasn't been revoked" - return 1 - fi -} - -# Ensure FLUIDSTACK_API_KEY is available (env var -> config file -> prompt+save) -ensure_fluidstack_token() { - ensure_api_token_with_provider \ - "FluidStack" \ - "FLUIDSTACK_API_KEY" \ - "${HOME}/.config/spawn/fluidstack.json" \ - "https://platform.fluidstack.io/dashboard/api-keys" \ - "test_fluidstack_token" -} - -# Check if SSH key is registered with FluidStack -fluidstack_check_ssh_key() { - local fingerprint="${1}" - local existing_keys - existing_keys=$(fluidstack_api GET "/ssh_keys") - # FluidStack returns SSH key fingerprints in MD5 format in "public_key_fingerprint" field - echo "${existing_keys}" | _SPAWN_FINGERPRINT="${fingerprint}" python3 -c " -import json, sys, os -fingerprint = os.environ.get('_SPAWN_FINGERPRINT', '') -data = json.loads(sys.stdin.read()) -for key in data.get('ssh_keys', []): - if fingerprint in key.get('public_key_fingerprint', '') or fingerprint in key.get('name', ''): - sys.exit(0) -sys.exit(1) -" -} - -# Register SSH key with FluidStack -fluidstack_register_ssh_key() { - local key_name="${1}" - local pub_path="${2}" - - local register_body - register_body=$(python3 -c " -import json, sys -pub_key = sys.stdin.read().strip() -print(json.dumps({ - 'name': sys.argv[1], - 'public_key': pub_key -})) -" "${key_name}" < "${pub_path}") - - local register_response - register_response=$(fluidstack_api POST "/ssh_keys" "${register_body}") - - if echo "${register_response}" | grep -q '"ssh_key_name"'; then - return 0 - else - local error_msg - error_msg=$(echo "${register_response}" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error','Unknown error'))" 2>/dev/null || echo "${register_response}") - log_error "API Error: ${error_msg}" - log_warn "Common causes:" - log_warn " - SSH key already registered" - log_warn " - Invalid SSH key format" - log_warn " - API key lacks write permissions" - return 1 - fi -} - -ensure_ssh_key() { - ensure_ssh_key_with_provider fluidstack_check_ssh_key fluidstack_register_ssh_key "FluidStack" -} - -get_server_name() { - local server_name - server_name=$(get_resource_name "FLUIDSTACK_SERVER_NAME" "Enter instance name: ") || return 1 - - if ! validate_server_name "${server_name}"; then - return 1 - fi - - echo "${server_name}" -} - -# Wait for FluidStack instance to become running and get its IP -# Sets: FLUIDSTACK_SERVER_IP -# Usage: wait_for_instance_ready INSTANCE_ID [MAX_ATTEMPTS] -wait_for_instance_ready() { - local instance_id="${1}" - local max_attempts=${2:-60} - local attempt=1 - - log_warn "Waiting for instance to become ready..." - while [[ "${attempt}" -le "${max_attempts}" ]]; do - local status_response - status_response=$(fluidstack_api GET "/instances/${instance_id}") - - local status - status=$(echo "${status_response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read()).get('status','unknown'))" 2>/dev/null || echo "unknown") - - if [[ "${status}" == "running" ]]; then - FLUIDSTACK_SERVER_IP=$(echo "${status_response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read()).get('ip_address',''))" 2>/dev/null || echo "") - export FLUIDSTACK_SERVER_IP - - if [[ -z "${FLUIDSTACK_SERVER_IP}" ]]; then - log_error "Instance running but no IP address assigned" - return 1 - fi - - log_info "Instance ready: ${FLUIDSTACK_SERVER_IP}" - return 0 - fi - - log_warn "Instance status: ${status} (${attempt}/${max_attempts})" - sleep "${INSTANCE_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - done - - log_error "Instance did not become ready in time" - return 1 -} - -create_server() { - local name="${1}" - local gpu_type="${FLUIDSTACK_GPU_TYPE:-RTX_4090}" - local ssh_key_name="${FLUIDSTACK_SSH_KEY_NAME:-spawn-${USER}}" - - # Block injection chars in string values (quotes, backslashes) - if [[ "${gpu_type}" =~ [\"\'\`\$\\] ]]; then log_error "Invalid FLUIDSTACK_GPU_TYPE: contains unsafe characters"; return 1; fi - if [[ "${ssh_key_name}" =~ [\"\'\`\$\\] ]]; then log_error "Invalid FLUIDSTACK_SSH_KEY_NAME: contains unsafe characters"; return 1; fi - - log_warn "Creating FluidStack instance '${name}' (GPU: ${gpu_type})..." - - # Build instance creation request safely via stdin - local create_body - create_body=$(python3 -c " -import json, sys -parts = sys.stdin.read().strip().split('\n') -print(json.dumps({ - 'gpu_type': parts[0], - 'ssh_key': parts[1] -})) -" <<< "${gpu_type} -${ssh_key_name}") - - local response - response=$(fluidstack_api POST "/instances" "${create_body}") - - if echo "${response}" | grep -q '"instance_id"'; then - FLUIDSTACK_INSTANCE_ID=$(echo "${response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read()).get('instance_id',''))") - export FLUIDSTACK_INSTANCE_ID - log_info "Instance created: ID=${FLUIDSTACK_INSTANCE_ID}" - - wait_for_instance_ready "${FLUIDSTACK_INSTANCE_ID}" - else - log_error "Failed to create FluidStack instance" - local error_msg - error_msg=$(echo "${response}" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error','Unknown error'))" 2>/dev/null || echo "${response}") - log_error "API Error: ${error_msg}" - log_warn "Common issues:" - log_warn " - Insufficient account balance" - log_warn " - GPU type unavailable (try different FLUIDSTACK_GPU_TYPE)" - log_warn " - SSH key not found (check FLUIDSTACK_SSH_KEY_NAME)" - log_warn "Remediation: Check https://platform.fluidstack.io/dashboard" - return 1 - fi -} - -verify_server_connectivity() { - local max_attempts=${1:-30} - generic_ssh_wait "${FLUIDSTACK_SERVER_IP}" "root" "${max_attempts}" -} - -# Install base tools via SSH -install_base_tools() { - log_warn "Installing base tools..." - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "root@${FLUIDSTACK_SERVER_IP}" "apt-get update -y && apt-get install -y curl unzip git zsh npm" >/dev/null 2>&1 || true - - # Install Bun - log_warn "Installing Bun..." - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "root@${FLUIDSTACK_SERVER_IP}" "curl -fsSL https://bun.sh/install | bash" >/dev/null 2>&1 || true - - # Install Claude Code - log_warn "Installing Claude Code..." - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "root@${FLUIDSTACK_SERVER_IP}" "curl -fsSL https://claude.ai/install.sh | bash" >/dev/null 2>&1 || true - - # Configure PATH in .bashrc and .zshrc - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "root@${FLUIDSTACK_SERVER_IP}" "grep -q '.bun/bin' ~/.bashrc 2>/dev/null || printf '%s\n' 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.bashrc; grep -q '.bun/bin' ~/.zshrc 2>/dev/null || printf '%s\n' 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.zshrc" >/dev/null 2>&1 || true - - log_info "Base tools installed" -} - -# FluidStack uses root user for SSH access -run_server() { - local ip="${1}" - local cmd="${2}" - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "root@${ip}" "${cmd}" -} - -upload_file() { - local ip="${1}" - local local_path="${2}" - local remote_path="${3}" - # shellcheck disable=SC2086 - scp ${SSH_OPTS} "${local_path}" "root@${ip}:${remote_path}" -} - -interactive_session() { - local ip="${1}" - local cmd="${2}" - # shellcheck disable=SC2086 - ssh -t ${SSH_OPTS} "root@${ip}" "${cmd}" -} - -destroy_server() { - local instance_id="${1}" - log_warn "Terminating instance ${instance_id}..." - fluidstack_api DELETE "/instances/${instance_id}" >/dev/null - log_info "Instance ${instance_id} terminated" -} - -list_servers() { - local response - response=$(fluidstack_api GET "/instances") - - python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -instances = data.get('instances', []) -if not instances: - print('No instances found') - sys.exit(0) -print(f\"{'NAME':<25} {'ID':<30} {'STATUS':<12} {'IP':<15} {'GPU':<15}\") -print('-' * 97) -for inst in instances: - name = inst.get('hostname', inst.get('instance_id', 'N/A'))[:24] - iid = inst.get('instance_id', 'N/A')[:29] - status = inst.get('status', 'N/A')[:11] - ip = inst.get('ip_address', 'N/A')[:14] - gpu = inst.get('gpu_type', 'N/A')[:14] - print(f'{name:<25} {iid:<30} {status:<12} {ip:<15} {gpu:<15}') -" <<< "${response}" -} diff --git a/fluidstack/nanoclaw.sh b/fluidstack/nanoclaw.sh deleted file mode 100644 index a9f91f82..00000000 --- a/fluidstack/nanoclaw.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "NanoClaw on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Node.js dependencies -log_warn "Installing tsx..." -run_server "${FLUIDSTACK_SERVER_IP}" "/.bun/bin/bun install -g tsx" - -# 6. Clone nanoclaw -log_warn "Cloning nanoclaw..." -run_server "${FLUIDSTACK_SERVER_IP}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build" - -# 7. 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 - -# 8. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 9. Create nanoclaw .env file -log_warn "Configuring nanoclaw..." -DOTENV_TEMP=$(mktemp) -trap 'rm -f "${DOTENV_TEMP}"' EXIT -chmod 600 "${DOTENV_TEMP}" -cat > "${DOTENV_TEMP}" << EOF -ANTHROPIC_API_KEY=${OPENROUTER_API_KEY} -EOF - -upload_file "${FLUIDSTACK_SERVER_IP}" "${DOTENV_TEMP}" "/tmp/nanoclaw_env" -run_server "${FLUIDSTACK_SERVER_IP}" "mv /tmp/nanoclaw_env ~/nanoclaw/.env" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -log_warn "You will need to scan a WhatsApp QR code to authenticate." -echo "" - -# 10. Start nanoclaw -log_warn "Starting nanoclaw..." -interactive_session "${FLUIDSTACK_SERVER_IP}" "cd ~/nanoclaw && source ~/.zshrc && npm run dev" diff --git a/fluidstack/openclaw.sh b/fluidstack/openclaw.sh deleted file mode 100644 index d54fd558..00000000 --- a/fluidstack/openclaw.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "OpenClaw on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install openclaw using bun -log_warn "Installing openclaw..." -run_server "${FLUIDSTACK_SERVER_IP}" "/.bun/bin/bun install -g openclaw" - -# 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 -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -# 8. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 9. Setup openclaw config -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${FLUIDSTACK_SERVER_IP}" \ - "run_server ${FLUIDSTACK_SERVER_IP}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 10. Start openclaw gateway in background and run openclaw tui -log_warn "Starting openclaw..." -run_server "${FLUIDSTACK_SERVER_IP}" "nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && openclaw tui" diff --git a/fluidstack/opencode.sh b/fluidstack/opencode.sh deleted file mode 100644 index 646bd252..00000000 --- a/fluidstack/opencode.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "OpenCode on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install OpenCode -log_warn "Installing OpenCode..." -run_server "${FLUIDSTACK_SERVER_IP}" "$(opencode_install_cmd)" -log_info "OpenCode 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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 8. Start OpenCode interactively -log_warn "Starting OpenCode..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && opencode" diff --git a/fluidstack/plandex.sh b/fluidstack/plandex.sh deleted file mode 100644 index f9e647f6..00000000 --- a/fluidstack/plandex.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=fluidstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/fluidstack/lib/common.sh)" -fi - -log_info "Plandex on FluidStack" -echo "" - -# 1. Ensure FluidStack API key is configured -ensure_fluidstack_token - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Install Plandex -log_warn "Installing Plandex..." -run_server "${FLUIDSTACK_SERVER_IP}" "curl -sL https://plandex.ai/install.sh | bash" - -# 6. Verify installation succeeded -if ! run_server "${FLUIDSTACK_SERVER_IP}" "command -v plandex &> /dev/null && plandex version &> /dev/null"; then - log_error "Plandex installation verification failed" - exit 1 -fi -log_info "Plandex installation verified successfully" - -# 7. 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 - -# 8. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${FLUIDSTACK_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "FluidStack instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${FLUIDSTACK_SERVER_IP})" -echo "" - -# 9. Start Plandex interactively -log_warn "Starting Plandex..." -sleep 1 -clear -interactive_session "${FLUIDSTACK_SERVER_IP}" "source ~/.zshrc && plandex" diff --git a/genesiscloud/README.md b/genesiscloud/README.md deleted file mode 100644 index 2208b9a4..00000000 --- a/genesiscloud/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# Genesis Cloud - -Genesis Cloud GPU instances via REST API. [Genesis Cloud](https://www.genesiscloud.com/) - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/claude.sh) -``` - -#### OpenClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/openclaw.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/aider.sh) -``` - -#### Amazon Q CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/amazonq.sh) -``` - -#### Cline - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/cline.sh) -``` - -#### gptme - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/gptme.sh) -``` - -#### OpenCode - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/opencode.sh) -``` - -#### Plandex - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/plandex.sh) -``` - -## Non-Interactive Mode - -```bash -GENESIS_SERVER_NAME=dev-gpu \ -GENESIS_API_KEY=your-api-key \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/genesiscloud/claude.sh) -``` - -## Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `GENESIS_API_KEY` | Genesis Cloud API key | _(prompted)_ | -| `GENESIS_SERVER_NAME` | Instance name | _(prompted)_ | -| `GENESIS_INSTANCE_TYPE` | Instance type | `vcpu-4_memory-12g_nvidia-rtx-3080-1` | -| `GENESIS_REGION` | Datacenter region | `ARC-IS-HAF-1` | -| `GENESIS_IMAGE` | OS image | `Ubuntu 24.04` | -| `OPENROUTER_API_KEY` | OpenRouter API key | _(OAuth or prompted)_ | diff --git a/genesiscloud/aider.sh b/genesiscloud/aider.sh deleted file mode 100644 index b9cf48cb..00000000 --- a/genesiscloud/aider.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Aider on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Aider..." -run_server "${GENESIS_SERVER_IP}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -if ! run_server "${GENESIS_SERVER_IP}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - exit 1 -fi -log_info "Aider installed" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/genesiscloud/amazonq.sh b/genesiscloud/amazonq.sh deleted file mode 100644 index b4cf4188..00000000 --- a/genesiscloud/amazonq.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Amazon Q on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Amazon Q CLI..." -run_server "${GENESIS_SERVER_IP}" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" -log_info "Amazon Q CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Amazon Q..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && q chat" diff --git a/genesiscloud/claude.sh b/genesiscloud/claude.sh deleted file mode 100644 index 44d14267..00000000 --- a/genesiscloud/claude.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Claude Code on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Verifying Claude Code installation..." -if ! run_server "${GENESIS_SERVER_IP}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${GENESIS_SERVER_IP}" "curl -fsSL https://claude.ai/install.sh | bash" -fi -log_info "Claude Code is installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${GENESIS_SERVER_IP}" \ - "run_server ${GENESIS_SERVER_IP}" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && claude" diff --git a/genesiscloud/cline.sh b/genesiscloud/cline.sh deleted file mode 100644 index 3776b15f..00000000 --- a/genesiscloud/cline.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Cline on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Cline..." -run_server "${GENESIS_SERVER_IP}" "npm install -g cline" -log_info "Cline installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Cline..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && cline" diff --git a/genesiscloud/codex.sh b/genesiscloud/codex.sh deleted file mode 100644 index 8b250280..00000000 --- a/genesiscloud/codex.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Codex CLI on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Codex CLI..." -run_server "${GENESIS_SERVER_IP}" "npm install -g @openai/codex" -log_info "Codex CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Codex..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && codex" diff --git a/genesiscloud/gemini.sh b/genesiscloud/gemini.sh deleted file mode 100644 index dc2c7f26..00000000 --- a/genesiscloud/gemini.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Gemini CLI on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Gemini CLI..." -run_server "${GENESIS_SERVER_IP}" "npm install -g @google/gemini-cli" -log_info "Gemini CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "GEMINI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Gemini..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && gemini" diff --git a/genesiscloud/goose.sh b/genesiscloud/goose.sh deleted file mode 100644 index d7378f37..00000000 --- a/genesiscloud/goose.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Goose on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Goose..." -run_server "${GENESIS_SERVER_IP}" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" - -log_warn "Verifying Goose installation..." -if ! run_server "${GENESIS_SERVER_IP}" "command -v goose" >/dev/null 2>&1; then - log_error "Goose installation failed" - exit 1 -fi -log_info "Goose is installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "GOOSE_PROVIDER=openrouter" \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Goose..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && goose" diff --git a/genesiscloud/gptme.sh b/genesiscloud/gptme.sh deleted file mode 100644 index c4826799..00000000 --- a/genesiscloud/gptme.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -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 - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "gptme on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing gptme..." -run_server "${GENESIS_SERVER_IP}" "pip install gptme 2>/dev/null || pip3 install gptme" - -if ! run_server "${GENESIS_SERVER_IP}" "command -v gptme &> /dev/null && gptme --version &> /dev/null"; then - log_error "gptme installation verification failed" - log_error "The 'gptme' command is not available or not working properly on server ${GENESIS_SERVER_IP}" - exit 1 -fi -log_info "gptme installed" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Genesis Cloud instance setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting gptme..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}" diff --git a/genesiscloud/interpreter.sh b/genesiscloud/interpreter.sh deleted file mode 100644 index e75043e2..00000000 --- a/genesiscloud/interpreter.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Open Interpreter on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Open Interpreter..." -run_server "${GENESIS_SERVER_IP}" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter" -log_info "Open Interpreter installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Open Interpreter..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && interpreter" diff --git a/genesiscloud/kilocode.sh b/genesiscloud/kilocode.sh deleted file mode 100644 index ed2e6ac5..00000000 --- a/genesiscloud/kilocode.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Kilo Code on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Kilo Code CLI..." -run_server "${GENESIS_SERVER_IP}" "npm install -g @kilocode/cli" -log_info "Kilo Code CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "KILO_PROVIDER_TYPE=openrouter" \ - "KILO_OPEN_ROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Kilo Code..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && kilocode" diff --git a/genesiscloud/lib/common.sh b/genesiscloud/lib/common.sh deleted file mode 100644 index 2f362e84..00000000 --- a/genesiscloud/lib/common.sh +++ /dev/null @@ -1,276 +0,0 @@ -#!/bin/bash -# Common bash functions for Genesis Cloud spawn scripts - -# Bash safety flags -set -eo pipefail - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../shared/common.sh" ]]; then - source "$SCRIPT_DIR/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, etc) are now in shared/common.sh - -# ============================================================ -# Genesis Cloud specific functions -# ============================================================ - -readonly GENESIS_API_BASE="https://api.genesiscloud.com/compute/v1" -# SSH_OPTS is now defined in shared/common.sh - -# Configurable timeout/delay constants -INSTANCE_STATUS_POLL_DELAY=${INSTANCE_STATUS_POLL_DELAY:-5} - -# Centralized curl wrapper for Genesis Cloud API -genesis_api() { - local method="$1" - local endpoint="$2" - local body="${3:-}" - generic_cloud_api "$GENESIS_API_BASE" "$GENESIS_API_KEY" "$method" "$endpoint" "$body" -} - -test_genesis_token() { - local response - response=$(genesis_api GET "/instances?per_page=1") - if echo "$response" | grep -q '"error"'; then - local error_msg - error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error',{}).get('message', d.get('message','No details available')))" 2>/dev/null || echo "Unable to parse error") - log_error "API Error: $error_msg" - log_warn "Remediation steps:" - log_warn " 1. Verify API key at: https://developers.genesiscloud.com/" - log_warn " 2. Ensure the key has read/write permissions" - log_warn " 3. Check key hasn't been revoked" - return 1 - fi - return 0 -} - -ensure_genesis_token() { - ensure_api_token_with_provider \ - "Genesis Cloud" \ - "GENESIS_API_KEY" \ - "$HOME/.config/spawn/genesiscloud.json" \ - "https://developers.genesiscloud.com/ → API Keys" \ - "test_genesis_token" -} - -# Check if SSH key is registered with Genesis Cloud -genesis_check_ssh_key() { - local fingerprint="$1" - local existing_keys - existing_keys=$(genesis_api GET "/ssh-keys") - echo "$existing_keys" | grep -q "$fingerprint" -} - -# Register SSH key with Genesis Cloud -genesis_register_ssh_key() { - local key_name="$1" - local pub_path="$2" - local pub_key - pub_key=$(cat "$pub_path") - local json_pub_key - json_pub_key=$(json_escape "$pub_key") - local register_body="{\"name\":\"$key_name\",\"value\":$json_pub_key}" - local register_response - register_response=$(genesis_api POST "/ssh-keys" "$register_body") - - if echo "$register_response" | grep -q '"ssh_key"'; then - return 0 - else - local error_msg - error_msg=$(echo "$register_response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error',{}).get('message', d.get('message','Unknown error')))" 2>/dev/null || echo "$register_response") - log_error "API Error: $error_msg" - - log_warn "Common causes:" - log_warn " - SSH key already registered with this name" - log_warn " - Invalid SSH key format (must be valid ed25519 public key)" - log_warn " - API key lacks write permissions" - return 1 - fi -} - -ensure_ssh_key() { - ensure_ssh_key_with_provider genesis_check_ssh_key genesis_register_ssh_key "Genesis Cloud" -} - -get_server_name() { - local server_name - server_name=$(get_resource_name "GENESIS_SERVER_NAME" "Enter instance name: ") || return 1 - - if ! validate_server_name "$server_name"; then - return 1 - fi - - echo "$server_name" -} - -# Fetch all SSH key IDs from Genesis Cloud account -_genesis_fetch_ssh_key_ids() { - local ssh_keys_response - ssh_keys_response=$(genesis_api GET "/ssh-keys") - echo "$ssh_keys_response" | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -keys = data.get('ssh_keys', []) -ids = [k['id'] for k in keys] -print(json.dumps(ids)) -" -} - -# Build the JSON request body for Genesis Cloud instance creation -_genesis_build_create_payload() { - local name="$1" instance_type="$2" region="$3" image="$4" ssh_key_ids="$5" - - local userdata - userdata=$(get_cloud_init_userdata) - local userdata_json - userdata_json=$(echo "$userdata" | python3 -c "import json,sys; print(json.dumps(sys.stdin.read()))") - - python3 -c " -import json -body = { - 'name': '$name', - 'type': '$instance_type', - 'region': '$region', - 'image': '$image', - 'ssh_key_ids': $ssh_key_ids, - 'startup_script': json.loads($userdata_json) -} -print(json.dumps(body)) -" -} - -# Poll Genesis Cloud API until instance is active, sets GENESIS_SERVER_IP -_genesis_wait_for_active() { - local server_id="$1" - log_warn "Waiting for instance to become active..." - local max_attempts=60 - local attempt=1 - while [[ "$attempt" -le "$max_attempts" ]]; do - local status_response - status_response=$(genesis_api GET "/instances/$server_id") - local status - status=$(echo "$status_response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['instance']['status'])") - - if [[ "$status" == "active" ]]; then - GENESIS_SERVER_IP=$(echo "$status_response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['instance']['public_ip'])") - export GENESIS_SERVER_IP - log_info "Instance active: IP=$GENESIS_SERVER_IP" - return 0 - fi - - log_warn "Instance status: $status ($attempt/$max_attempts)" - sleep "${INSTANCE_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - done - - log_error "Instance did not become active in time" - return 1 -} - -create_server() { - local name="$1" - local instance_type="${GENESIS_INSTANCE_TYPE:-vcpu-4_memory-12g_nvidia-rtx-3080-1}" - local region="${GENESIS_REGION:-ARC-IS-HAF-1}" - local image="${GENESIS_IMAGE:-Ubuntu 24.04}" - - # Validate env var inputs to prevent injection into Python code - validate_resource_name "$instance_type" || { log_error "Invalid GENESIS_INSTANCE_TYPE"; return 1; } - validate_region_name "$region" || { log_error "Invalid GENESIS_REGION"; return 1; } - # Image names may contain spaces (e.g. "Ubuntu 24.04") but must not contain quotes or shell metacharacters - if [[ "$image" =~ [\'\"\`\$\;\\] ]]; then log_error "Invalid GENESIS_IMAGE: contains unsafe characters"; return 1; fi - - log_warn "Creating Genesis Cloud instance '$name' (type: $instance_type, region: $region)..." - - local ssh_key_ids - ssh_key_ids=$(_genesis_fetch_ssh_key_ids) - - local body - body=$(_genesis_build_create_payload "$name" "$instance_type" "$region" "$image" "$ssh_key_ids") - - local response - response=$(genesis_api POST "/instances" "$body") - - if echo "$response" | grep -q '"instance"'; then - GENESIS_SERVER_ID=$(echo "$response" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['instance']['id'])") - export GENESIS_SERVER_ID - log_info "Instance created: ID=$GENESIS_SERVER_ID" - else - log_error "Failed to create Genesis Cloud instance" - - local error_msg - error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('error',{}).get('message', d.get('message','Unknown error')))" 2>/dev/null || echo "$response") - log_error "API Error: $error_msg" - - log_warn "Common issues:" - log_warn " - Insufficient account balance" - log_warn " - Instance type unavailable in region (try different GENESIS_INSTANCE_TYPE or GENESIS_REGION)" - log_warn " - Instance limit reached" - log_warn "Remediation: Check https://console.genesiscloud.com/" - return 1 - fi - - _genesis_wait_for_active "$GENESIS_SERVER_ID" -} - -verify_server_connectivity() { - local ip="$1" - local max_attempts=${2:-30} - # SSH_OPTS is defined in shared/common.sh - # shellcheck disable=SC2154 - generic_ssh_wait "root" "$ip" "$SSH_OPTS -o ConnectTimeout=5" "echo ok" "SSH connectivity" "$max_attempts" 5 -} - -run_server() { - local ip="$1"; local cmd="$2" - # shellcheck disable=SC2086 - ssh $SSH_OPTS "root@$ip" "$cmd" -} - -upload_file() { - local ip="$1"; local local_path="$2"; local remote_path="$3" - # shellcheck disable=SC2086 - scp $SSH_OPTS "$local_path" "root@$ip:$remote_path" -} - -interactive_session() { - local ip="$1"; local cmd="$2" - # shellcheck disable=SC2086 - ssh -t $SSH_OPTS "root@$ip" "$cmd" -} - -destroy_server() { - local server_id="$1" - log_warn "Destroying instance $server_id..." - genesis_api DELETE "/instances/$server_id" - log_info "Instance $server_id destroyed" -} - -list_servers() { - local response - response=$(genesis_api GET "/instances") - python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -instances = data.get('instances', []) -if not instances: - print('No instances found') - sys.exit(0) -print(f\"{'NAME':<25} {'ID':<40} {'STATUS':<12} {'IP':<16} {'TYPE':<40}\") -print('-' * 133) -for i in instances: - name = i.get('name', 'N/A') - iid = i['id'] - status = i['status'] - ip = i.get('public_ip', 'N/A') - itype = i.get('type', 'N/A') - print(f'{name:<25} {iid:<40} {status:<12} {ip:<16} {itype:<40}') -" <<< "$response" -} diff --git a/genesiscloud/nanoclaw.sh b/genesiscloud/nanoclaw.sh deleted file mode 100644 index e5a95dc3..00000000 --- a/genesiscloud/nanoclaw.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "NanoClaw on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing tsx..." -run_server "${GENESIS_SERVER_IP}" "source ~/.bashrc && bun install -g tsx" - -log_warn "Cloning and building nanoclaw..." -run_server "${GENESIS_SERVER_IP}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build" -log_info "NanoClaw installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -log_warn "Configuring nanoclaw..." -DOTENV_TEMP=$(mktemp) -trap 'rm -f "${DOTENV_TEMP}"' EXIT -chmod 600 "${DOTENV_TEMP}" -cat > "${DOTENV_TEMP}" << EOF -ANTHROPIC_API_KEY=${OPENROUTER_API_KEY} -EOF - -upload_file "${GENESIS_SERVER_IP}" "${DOTENV_TEMP}" "/root/nanoclaw/.env" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting nanoclaw..." -log_warn "You will need to scan a WhatsApp QR code to authenticate." -echo "" -interactive_session "${GENESIS_SERVER_IP}" "cd ~/nanoclaw && source ~/.zshrc && npm run dev" diff --git a/genesiscloud/openclaw.sh b/genesiscloud/openclaw.sh deleted file mode 100644 index abefa701..00000000 --- a/genesiscloud/openclaw.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "OpenClaw on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing openclaw..." -run_server "${GENESIS_SERVER_IP}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw installed" - -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 -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${GENESIS_SERVER_IP}" \ - "run_server ${GENESIS_SERVER_IP}" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting openclaw..." -run_server "${GENESIS_SERVER_IP}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && openclaw tui" diff --git a/genesiscloud/opencode.sh b/genesiscloud/opencode.sh deleted file mode 100644 index 0b67f318..00000000 --- a/genesiscloud/opencode.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -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 - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "OpenCode on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing OpenCode..." -run_server "${GENESIS_SERVER_IP}" "curl -fsSL https://raw.githubusercontent.com/opencode-ai/opencode/refs/heads/main/install | bash" -log_info "OpenCode installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Genesis Cloud instance setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting OpenCode..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && opencode" diff --git a/genesiscloud/plandex.sh b/genesiscloud/plandex.sh deleted file mode 100644 index 637ec406..00000000 --- a/genesiscloud/plandex.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=genesiscloud/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/genesiscloud/lib/common.sh)" -fi - -log_info "Plandex on Genesis Cloud" -echo "" - -ensure_genesis_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity "${GENESIS_SERVER_IP}" -wait_for_cloud_init "${GENESIS_SERVER_IP}" 60 - -log_warn "Installing Plandex..." -run_server "${GENESIS_SERVER_IP}" "curl -sL https://plandex.ai/install.sh | bash" - -log_warn "Verifying Plandex installation..." -if ! run_server "${GENESIS_SERVER_IP}" "command -v plandex" >/dev/null 2>&1; then - log_error "Plandex installation failed" - exit 1 -fi -log_info "Plandex is installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${GENESIS_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Genesis Cloud server setup completed successfully!" -log_info "Server: ${SERVER_NAME} (ID: ${GENESIS_SERVER_ID}, IP: ${GENESIS_SERVER_IP})" -echo "" - -log_warn "Starting Plandex..." -sleep 1 -clear -interactive_session "${GENESIS_SERVER_IP}" "source ~/.zshrc && plandex" diff --git a/hyperstack/README.md b/hyperstack/README.md deleted file mode 100644 index 0420bdbf..00000000 --- a/hyperstack/README.md +++ /dev/null @@ -1,200 +0,0 @@ -# Hyperstack - -Hyperstack GPU cloud via REST API. [Hyperstack](https://www.hyperstack.cloud/) - -> Hyperstack (formerly NexGen Cloud) offers NVIDIA GPUs with pay-per-minute billing. - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/claude.sh) -``` - -#### OpenClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/openclaw.sh) -``` - -#### NanoClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/nanoclaw.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/aider.sh) -``` - -#### Goose - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/goose.sh) -``` - -#### Codex CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/codex.sh) -``` - -#### Open Interpreter - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/interpreter.sh) -``` - -#### Gemini CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/gemini.sh) -``` - -#### Amazon Q CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/amazonq.sh) -``` - -#### Cline - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/cline.sh) -``` - -#### gptme - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/gptme.sh) -``` - -#### OpenCode - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/opencode.sh) -``` - -#### Plandex - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/plandex.sh) -``` - -#### Kilo Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/kilocode.sh) -``` - -## Setup - -### 1. Get Hyperstack API Key - -1. Sign up at [Hyperstack Infrahub](https://infrahub.hyperstack.cloud) -2. Navigate to **Settings -> API Keys** -3. Create a new API key -4. Copy the API key - -### 2. Set Environment Variable - -```bash -export HYPERSTACK_API_KEY="your-api-key-here" -``` - -Or the script will prompt you and save it to `~/.config/spawn/hyperstack.json`. - -### 3. Choose an Environment - -Hyperstack organizes resources by "environments" (e.g., `default-CANADA-1`, `default-EU-1`). The script will: -- Use `HYPERSTACK_ENVIRONMENT` if set -- Otherwise, fetch available environments and prompt you to choose - -List available environments: -```bash -curl -H "api_key: YOUR_API_KEY" \ - https://infrahub-api.nexgencloud.com/v1/core/environments | jq '.environments[] | {name, region}' -``` - -## Non-Interactive Mode - -```bash -HYPERSTACK_API_KEY=your-key \ -HYPERSTACK_ENVIRONMENT=default-CANADA-1 \ -HYPERSTACK_VM_NAME=my-vm \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/hyperstack/claude.sh) -``` - -## Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `HYPERSTACK_API_KEY` | API key from Hyperstack Infrahub | _(required)_ | -| `HYPERSTACK_ENVIRONMENT` | Environment name | _(prompted)_ | -| `HYPERSTACK_FLAVOR` | VM flavor/size | `n1-cpu-small` | -| `HYPERSTACK_IMAGE` | OS image | `Ubuntu Server 24.04 LTS R5504 UEFI` | -| `HYPERSTACK_VM_NAME` | Custom VM name | _(prompted)_ | -| `HYPERSTACK_SSH_KEY_NAME` | SSH key name | `spawn-key-$(whoami)` | -| `OPENROUTER_API_KEY` | OpenRouter API key | _(OAuth or prompted)_ | - -## Available Flavors - -To list available VM flavors: - -```bash -curl -H "api_key: YOUR_API_KEY" \ - https://infrahub-api.nexgencloud.com/v1/core/flavors | jq '.flavors[] | {name, cpu, ram, gpu}' -``` - -Common flavors: -- `n1-cpu-small` - 1 vCPU, 2GB RAM -- `n1-cpu-medium` - 2 vCPU, 4GB RAM -- `n1-cpu-large` - 4 vCPU, 8GB RAM -- GPU flavors with RTX A6000, A100, H100, etc. - -## Available Images - -To list available OS images: - -```bash -curl -H "api_key: YOUR_API_KEY" \ - https://infrahub-api.nexgencloud.com/v1/core/images | jq '.images[] | {name, version}' -``` - -## Pricing - -Hyperstack uses pay-per-minute billing for on-demand instances. Pricing is calculated per GPU per hour. - -**Example pricing** (subject to change): -- RTX A6000 (48GB): $0.50/hour on-demand, $0.35/hour reserved -- Reserved instances offer ~30% savings over on-demand - -Check current pricing at [Hyperstack Pricing](https://www.hyperstack.cloud/pricing) or via the API pricebook endpoints. - -## Troubleshooting - -### API Key Invalid - -If you see authentication errors: -1. Verify your API key at https://infrahub.hyperstack.cloud -2. Ensure the key has proper permissions (not read-only) -3. Check that the key hasn't been revoked - -### Environment Not Found - -If the environment name is invalid: -1. List available environments: `curl -H "api_key: KEY" https://infrahub-api.nexgencloud.com/v1/core/environments` -2. Use the exact name from the API response (case-sensitive) -3. Set `HYPERSTACK_ENVIRONMENT` to the correct name - -### VM Creation Fails - -Common issues: -- Insufficient quota in the selected environment -- Flavor not available in the selected region -- SSH key name conflicts with existing key -- Invalid security rules diff --git a/hyperstack/aider.sh b/hyperstack/aider.sh deleted file mode 100644 index a6559139..00000000 --- a/hyperstack/aider.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Aider on Hyperstack" -echo "" - -# 1. Resolve Hyperstack API key -ensure_hyperstack_api_key - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get VM name and environment -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -# 4. Create VM -create_vm "${VM_NAME}" "${ENVIRONMENT}" - -# 5. Wait for SSH -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -# 6. Install Aider -log_warn "Installing Aider..." -run_server "${HYPERSTACK_VM_IP}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -# Verify installation succeeded -if ! run_server "${HYPERSTACK_VM_IP}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - log_error "The 'aider' command is not available or not working properly on VM ${HYPERSTACK_VM_IP}" - exit 1 -fi -log_info "Aider installation verified successfully" - -# 7. 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -# 8. Start Aider interactively -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/hyperstack/amazonq.sh b/hyperstack/amazonq.sh deleted file mode 100644 index 7542b022..00000000 --- a/hyperstack/amazonq.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/lib/common.sh" ]]; then - source "$SCRIPT_DIR/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Amazon Q on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -create_vm "$VM_NAME" "$ENVIRONMENT" -verify_server_connectivity "$HYPERSTACK_VM_IP" - -log_warn "Installing Amazon Q CLI..." -run_server "$HYPERSTACK_VM_IP" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" - -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 - -log_warn "Setting up environment variables..." -run_server "$HYPERSTACK_VM_IP" "printf '\nexport OPENROUTER_API_KEY=%s\nexport OPENAI_API_KEY=%s\nexport OPENAI_BASE_URL=%s\n' '$OPENROUTER_API_KEY' '$OPENROUTER_API_KEY' 'https://openrouter.ai/api/v1' >> ~/.bashrc" - -echo "" -log_info "VM setup completed successfully!" -echo "" - -log_warn "Starting Amazon Q..." -sleep 1 -clear -interactive_session "$HYPERSTACK_VM_IP" "bash -c 'source ~/.bashrc && q chat'" diff --git a/hyperstack/claude.sh b/hyperstack/claude.sh deleted file mode 100644 index 5c45bcef..00000000 --- a/hyperstack/claude.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Claude Code on Hyperstack" -echo "" - -# 1. Resolve Hyperstack API key -ensure_hyperstack_api_key - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get VM name and environment -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -# 4. Create VM -create_vm "${VM_NAME}" "${ENVIRONMENT}" - -# 5. Wait for SSH -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -# 6. Install Claude Code -log_warn "Installing Claude Code..." -run_server "${HYPERSTACK_VM_IP}" "curl -fsSL https://claude.ai/install.sh | bash" - -# Verify installation succeeded -if ! run_server "${HYPERSTACK_VM_IP}" "command -v claude &> /dev/null && claude --version &> /dev/null"; then - log_error "Claude Code installation verification failed" - log_error "The 'claude' command is not available or not working properly on VM ${HYPERSTACK_VM_IP}" - exit 1 -fi -log_info "Claude Code installation verified successfully" - -# 7. 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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 8. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${HYPERSTACK_VM_IP}" \ - "run_server ${HYPERSTACK_VM_IP}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -# 9. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && claude" diff --git a/hyperstack/cline.sh b/hyperstack/cline.sh deleted file mode 100644 index 56d9fd28..00000000 --- a/hyperstack/cline.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Cline on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) -create_vm "${VM_NAME}" "${ENVIRONMENT}" -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -log_warn "Installing Cline..." -run_server "${HYPERSTACK_VM_IP}" "npm install -g cline" -log_info "Cline installed" - -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 - -log_warn "Setting up environment variables..." - -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -log_warn "Starting Cline..." -sleep 1 -clear -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && cline" diff --git a/hyperstack/codex.sh b/hyperstack/codex.sh deleted file mode 100644 index e955e337..00000000 --- a/hyperstack/codex.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/lib/common.sh" ]]; then - source "$SCRIPT_DIR/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Codex CLI on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -create_vm "$VM_NAME" "$ENVIRONMENT" -verify_server_connectivity "$HYPERSTACK_VM_IP" - -log_warn "Installing Node.js and npm..." -run_server "$HYPERSTACK_VM_IP" "curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs" - -log_warn "Installing Codex CLI..." -run_server "$HYPERSTACK_VM_IP" "npm install -g @openai/codex" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "$HYPERSTACK_VM_IP" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -echo "" - -log_warn "Starting Codex..." -sleep 1 -clear -interactive_session "$HYPERSTACK_VM_IP" "source ~/.zshrc && codex" diff --git a/hyperstack/gemini.sh b/hyperstack/gemini.sh deleted file mode 100644 index 49da466a..00000000 --- a/hyperstack/gemini.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/lib/common.sh" ]]; then - source "$SCRIPT_DIR/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Gemini CLI on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -create_vm "$VM_NAME" "$ENVIRONMENT" -verify_server_connectivity "$HYPERSTACK_VM_IP" - -log_warn "Installing Gemini CLI..." -run_server "$HYPERSTACK_VM_IP" "apt-get update && apt-get install -y curl && curl -fsSL https://bun.sh/install | bash" -run_server "$HYPERSTACK_VM_IP" "export BUN_INSTALL=\"\$HOME/.bun\" && export PATH=\"\$BUN_INSTALL/bin:\$PATH\" && bun install -g npm && npm install -g @google/gemini-cli" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "$HYPERSTACK_VM_IP" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "GEMINI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Hyperstack setup completed successfully!" -echo "" - -log_warn "Starting Gemini..." -sleep 1 -clear -interactive_session "$HYPERSTACK_VM_IP" "source ~/.zshrc && gemini" diff --git a/hyperstack/goose.sh b/hyperstack/goose.sh deleted file mode 100644 index a51837bd..00000000 --- a/hyperstack/goose.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/lib/common.sh" ]]; then - source "$SCRIPT_DIR/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Goose on Hyperstack" -echo "" - -# Authenticate with Hyperstack -ensure_hyperstack_api_key -ensure_ssh_key - -# Get VM configuration -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -# Create VM -create_vm "$VM_NAME" "$ENVIRONMENT" -verify_server_connectivity "$HYPERSTACK_VM_IP" - -log_warn "Setting up Hyperstack VM..." - -# Install Goose -log_warn "Installing Goose..." -run_server "$HYPERSTACK_VM_IP" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" - -# Verify installation succeeded -if ! run_server "$HYPERSTACK_VM_IP" "command -v goose &> /dev/null && goose --version &> /dev/null"; then - log_error "Goose installation verification failed" - log_error "The 'goose' command is not available or not working properly" - exit 1 -fi -log_info "Goose installation verified successfully" - -# 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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "$HYPERSTACK_VM_IP" upload_file run_server \ - "GOOSE_PROVIDER=openrouter" \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -echo "" - -# Start Goose interactively -log_warn "Starting Goose..." -sleep 1 -clear -interactive_session "$HYPERSTACK_VM_IP" "source ~/.zshrc && goose" diff --git a/hyperstack/gptme.sh b/hyperstack/gptme.sh deleted file mode 100644 index 5099ec83..00000000 --- a/hyperstack/gptme.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# 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 - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "gptme on Hyperstack" -echo "" - -# 1. Resolve Hyperstack API key -ensure_hyperstack_api_key - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get VM name and environment -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -# 4. Create VM -create_vm "$VM_NAME" "$ENVIRONMENT" - -# 5. Wait for SSH -verify_server_connectivity "$HYPERSTACK_VM_IP" - -# 6. Install gptme -log_warn "Installing gptme..." -run_server "$HYPERSTACK_VM_IP" "pip install gptme 2>/dev/null || pip3 install gptme" - -# Verify installation succeeded -if ! run_server "$HYPERSTACK_VM_IP" "command -v gptme &> /dev/null && gptme --version &> /dev/null"; then - log_error "gptme installation verification failed" - log_error "The 'gptme' command is not available or not working properly on server $HYPERSTACK_VM_IP" - exit 1 -fi -log_info "gptme installation verified successfully" - -# 7. 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 5181) -fi - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "$HYPERSTACK_VM_IP" upload_file run_server \ - "OPENROUTER_API_KEY=$OPENROUTER_API_KEY" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: $VM_NAME (ID: $HYPERSTACK_VM_ID, IP: $HYPERSTACK_VM_IP)" -echo "" - -# 8. Start gptme interactively -log_warn "Starting gptme..." -sleep 1 -clear -interactive_session "$HYPERSTACK_VM_IP" "source ~/.bashrc && gptme -m openrouter/${MODEL_ID}" diff --git a/hyperstack/interpreter.sh b/hyperstack/interpreter.sh deleted file mode 100644 index e600bd09..00000000 --- a/hyperstack/interpreter.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/lib/common.sh" ]]; then - source "$SCRIPT_DIR/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Open Interpreter on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -create_vm "$VM_NAME" "$ENVIRONMENT" -verify_server_connectivity "$HYPERSTACK_VM_IP" - -log_warn "Installing Python and pip..." -run_server "$HYPERSTACK_VM_IP" "apt-get update && apt-get install -y python3 python3-pip" - -log_warn "Installing Open Interpreter..." -run_server "$HYPERSTACK_VM_IP" "pip3 install open-interpreter --break-system-packages 2>/dev/null || pip3 install open-interpreter" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "$HYPERSTACK_VM_IP" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -echo "" - -log_warn "Starting Open Interpreter..." -sleep 1 -clear -interactive_session "$HYPERSTACK_VM_IP" "source ~/.zshrc && interpreter" diff --git a/hyperstack/kilocode.sh b/hyperstack/kilocode.sh deleted file mode 100644 index 8d0b1fba..00000000 --- a/hyperstack/kilocode.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Kilo Code on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) -create_vm "${VM_NAME}" "${ENVIRONMENT}" -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -log_warn "Installing Kilo Code..." -run_server "${HYPERSTACK_VM_IP}" "npm install -g @kilocode/cli" -log_info "Kilo Code installed" - -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 - -log_warn "Setting up environment variables..." - -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "KILO_PROVIDER_TYPE=openrouter" \ - "KILO_OPEN_ROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -log_warn "Starting Kilo Code..." -sleep 1 -clear -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && kilocode" diff --git a/hyperstack/lib/common.sh b/hyperstack/lib/common.sh deleted file mode 100644 index ca1f4d54..00000000 --- a/hyperstack/lib/common.sh +++ /dev/null @@ -1,297 +0,0 @@ -#!/bin/bash -set -eo pipefail -# Common bash functions for Hyperstack spawn scripts - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../shared/common.sh" ]]; then - source "$SCRIPT_DIR/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, nc_listen) are now in shared/common.sh - -# ============================================================ -# Hyperstack specific functions -# ============================================================ - -readonly HYPERSTACK_API_BASE="https://infrahub-api.nexgencloud.com/v1" -# SSH_OPTS is now defined in shared/common.sh - -# Centralized curl wrapper for Hyperstack API -hyperstack_api() { - local method="$1" - local endpoint="$2" - local body="${3:-}" - # shellcheck disable=SC2154 - generic_cloud_api "$HYPERSTACK_API_BASE" "$HYPERSTACK_API_KEY" "$method" "$endpoint" "$body" -} - -test_hyperstack_api_key() { - local response - response=$(hyperstack_api GET "/core/virtual-machines?per_page=1") - if echo "$response" | grep -q '"status".*4[0-9][0-9]'; then - # Parse error details - local error_msg - error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('message','No details available'))" 2>/dev/null || echo "Unable to parse error") - log_error "API Error: $error_msg" - log_error "" - log_error "How to fix:" - log_error " 1. Verify your API key at: https://infrahub.hyperstack.cloud" - log_error " 2. Ensure the API key has proper permissions" - log_error " 3. Check the key hasn't been revoked" - return 1 - fi - return 0 -} - -# Ensure HYPERSTACK_API_KEY is available (env var → config file → prompt+save) -ensure_hyperstack_api_key() { - ensure_api_token_with_provider \ - "Hyperstack" \ - "HYPERSTACK_API_KEY" \ - "$HOME/.config/spawn/hyperstack.json" \ - "https://infrahub.hyperstack.cloud → Settings → API Keys" \ - "test_hyperstack_api_key" -} - -# Check if SSH key is registered with Hyperstack -hyperstack_check_ssh_key() { - local fingerprint="$1" - local existing_keys - existing_keys=$(hyperstack_api GET "/core/keypairs") - echo "$existing_keys" | grep -q "$fingerprint" -} - -# Register SSH key with Hyperstack -hyperstack_register_ssh_key() { - local key_name="$1" - local pub_path="$2" - local pub_key - pub_key=$(cat "$pub_path") - local json_pub_key - json_pub_key=$(json_escape "$pub_key") - local register_body="{\"name\":\"$key_name\",\"public_key\":$json_pub_key}" - local register_response - register_response=$(hyperstack_api POST "/core/keypairs" "$register_body") - - if echo "$register_response" | grep -q '"status".*4[0-9][0-9]'; then - # Parse error details - local error_msg - error_msg=$(echo "$register_response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('message','Unknown error'))" 2>/dev/null || echo "$register_response") - log_error "API Error: $error_msg" - log_error "" - log_error "Common causes:" - log_error " - SSH key already registered with this name" - log_error " - Invalid SSH key format (must be valid ed25519 or RSA public key)" - log_error " - API key lacks write permissions" - return 1 - fi - - return 0 -} - -# Ensure SSH key exists locally and is registered with Hyperstack -ensure_ssh_key() { - ensure_ssh_key_with_provider hyperstack_check_ssh_key hyperstack_register_ssh_key "Hyperstack" -} - -# Get VM name from env var or prompt -get_vm_name() { - local vm_name - vm_name=$(get_resource_name "HYPERSTACK_VM_NAME" "Enter VM name: ") || return 1 - - if ! validate_server_name "$vm_name"; then - return 1 - fi - - echo "$vm_name" -} - -# Get environment name (required for VM creation) -get_environment_name() { - local env_name="${HYPERSTACK_ENVIRONMENT:-}" - - if [[ -z "$env_name" ]]; then - log_warn "Fetching available environments..." - local envs_response - envs_response=$(hyperstack_api GET "/core/environments") - local env_list - env_list=$(echo "$envs_response" | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -envs = data.get('environments', []) -if envs: - for env in envs[:5]: - print(f\" - {env['name']} (region: {env.get('region', 'N/A')})\") -" 2>/dev/null) - - if [[ -n "$env_list" ]]; then - log_info "Available environments:" - echo "$env_list" >&2 - fi - - env_name=$(safe_read "Enter environment name (e.g., default-CANADA-1): ") - fi - - echo "$env_name" -} - -# Build the JSON request body for Hyperstack VM creation (uses stdin to prevent injection) -# Usage: _build_vm_request_body NAME ENVIRONMENT KEY_NAME IMAGE FLAVOR -_build_vm_request_body() { - local name="$1" environment="$2" key_name="$3" image="$4" flavor="$5" - printf '%s\n%s\n%s\n%s\n%s' "$name" "$environment" "$key_name" "$image" "$flavor" | python3 -c " -import json, sys -lines = sys.stdin.read().split('\n') -body = { - 'name': lines[0], - 'environment_name': lines[1], - 'key_name': lines[2], - 'image_name': lines[3], - 'flavor_name': lines[4], - 'count': 1, - 'assign_floating_ip': True, - 'security_rules': [ - { - 'direction': 'ingress', - 'ethertype': 'IPv4', - 'protocol': 'tcp', - 'remote_ip_prefix': '0.0.0.0/0', - 'port_range_min': 22, - 'port_range_max': 22 - } - ] -} -print(json.dumps(body)) -" -} - -# Wait for a Hyperstack VM to become active and set its IP -# Sets: HYPERSTACK_VM_IP, HYPERSTACK_VM_ID (exported) -# Usage: _wait_for_vm_active VM_ID [MAX_WAIT_SECONDS] -_wait_for_vm_active() { - local vm_id="$1" - local max_wait="${2:-300}" - local elapsed=0 - - log_warn "Waiting for VM to become active..." - while [[ $elapsed -lt $max_wait ]]; do - local vm_info - vm_info=$(hyperstack_api GET "/core/virtual-machines/$vm_id") - - local status - status=$(echo "$vm_info" | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -print(data.get('status', '')) -" 2>/dev/null) - - if [[ "$status" == "ACTIVE" ]]; then - HYPERSTACK_VM_IP=$(echo "$vm_info" | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -print(data.get('floating_ip', '')) -" 2>/dev/null) - - if [[ -n "$HYPERSTACK_VM_IP" ]]; then - log_info "VM is active with IP: $HYPERSTACK_VM_IP" - export HYPERSTACK_VM_IP - export HYPERSTACK_VM_ID="$vm_id" - return 0 - fi - fi - - sleep 5 - elapsed=$((elapsed + 5)) - done - - log_error "VM did not become active within ${max_wait}s" - return 1 -} - -# Create a Hyperstack VM -create_vm() { - local name="$1" - local environment="${2:-}" - local flavor="${HYPERSTACK_FLAVOR:-n1-cpu-small}" - local image="${HYPERSTACK_IMAGE:-Ubuntu Server 24.04 LTS R5504 UEFI}" - local key_name="${HYPERSTACK_SSH_KEY_NAME:-spawn-key-$(whoami)}" - - # Validate env var inputs to prevent injection - validate_resource_name "$flavor" || { log_error "Invalid HYPERSTACK_FLAVOR"; return 1; } - validate_resource_name "$key_name" || { log_error "Invalid HYPERSTACK_SSH_KEY_NAME"; return 1; } - - log_warn "Creating Hyperstack VM '$name' (flavor: $flavor, env: $environment)..." - - local body - body=$(_build_vm_request_body "$name" "$environment" "$key_name" "$image" "$flavor") - - local response - response=$(hyperstack_api POST "/core/virtual-machines" "$body") - - # Check for errors - if echo "$response" | grep -q '"status".*4[0-9][0-9]'; then - local error_msg - error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('message','Unknown error'))" 2>/dev/null || echo "$response") - log_error "Failed to create VM: $error_msg" - return 1 - fi - - # Extract VM ID from response - HYPERSTACK_VM_ID=$(echo "$response" | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -vms = data.get('virtual_machines', []) -if vms: - print(vms[0].get('id', '')) -") - - if [[ -z "$HYPERSTACK_VM_ID" ]]; then - log_error "Failed to extract VM ID from response" - return 1 - fi - - log_info "VM created with ID: $HYPERSTACK_VM_ID" - - _wait_for_vm_active "$HYPERSTACK_VM_ID" -} - -# Verify server connectivity via SSH -verify_server_connectivity() { - local ip="$1" - generic_ssh_wait "$ip" "root" 180 -} - -# Run command on Hyperstack VM via SSH -run_server() { - local ip="$1" - shift - # shellcheck disable=SC2086 - ssh $SSH_OPTS "root@$ip" "$@" -} - -# Upload file to Hyperstack VM via SCP -upload_file() { - local ip="$1" - local src="$2" - local dst="$3" - # shellcheck disable=SC2086 - scp $SSH_OPTS "$src" "root@$ip:$dst" -} - -# Start interactive session on Hyperstack VM -interactive_session() { - local ip="$1" - local cmd="${2:-bash}" - # shellcheck disable=SC2086 - ssh $SSH_OPTS -t "root@$ip" "$cmd" -} - -# Ensure Python 3 is available on local machine -check_python_available diff --git a/hyperstack/nanoclaw.sh b/hyperstack/nanoclaw.sh deleted file mode 100644 index 26ceb892..00000000 --- a/hyperstack/nanoclaw.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "NanoClaw on Hyperstack" -echo "" - -# 1. Resolve Hyperstack API key -ensure_hyperstack_api_key - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get VM name and environment -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -# 4. Create VM -create_vm "${VM_NAME}" "${ENVIRONMENT}" - -# 5. Wait for SSH connectivity -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -# 6. Install Node.js deps and clone nanoclaw -log_warn "Installing tsx..." -run_server "${HYPERSTACK_VM_IP}" "source ~/.bashrc && bun install -g tsx" - -log_warn "Cloning and building nanoclaw..." -run_server "${HYPERSTACK_VM_IP}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build" -log_info "NanoClaw installed" - -# 7. 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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 8. Create nanoclaw .env file -log_warn "Configuring nanoclaw..." - -DOTENV_TEMP=$(mktemp) -trap 'rm -f "${DOTENV_TEMP}"' EXIT -chmod 600 "${DOTENV_TEMP}" -cat > "${DOTENV_TEMP}" << EOF -ANTHROPIC_API_KEY=${OPENROUTER_API_KEY} -EOF - -upload_file "${HYPERSTACK_VM_IP}" "${DOTENV_TEMP}" "/root/nanoclaw/.env" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -# 9. Start nanoclaw -log_warn "Starting nanoclaw..." -log_warn "You will need to scan a WhatsApp QR code to authenticate." -echo "" -interactive_session "${HYPERSTACK_VM_IP}" "cd ~/nanoclaw && source ~/.zshrc && npm run dev" diff --git a/hyperstack/openclaw.sh b/hyperstack/openclaw.sh deleted file mode 100644 index 48c0c267..00000000 --- a/hyperstack/openclaw.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "OpenClaw on Hyperstack" -echo "" - -# 1. Resolve Hyperstack API key -ensure_hyperstack_api_key - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get VM name and environment -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) - -# 4. Create VM -create_vm "${VM_NAME}" "${ENVIRONMENT}" - -# 5. Wait for SSH -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -# 6. Install Bun and openclaw -log_warn "Installing Bun..." -run_server "${HYPERSTACK_VM_IP}" "curl -fsSL https://bun.sh/install | bash" - -log_warn "Installing openclaw..." -run_server "${HYPERSTACK_VM_IP}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw installed" - -# 7. 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 8. Configure openclaw -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${HYPERSTACK_VM_IP}" \ - "run_server ${HYPERSTACK_VM_IP}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -# 9. Start openclaw gateway in background and launch TUI -log_warn "Starting openclaw..." -run_server "${HYPERSTACK_VM_IP}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && openclaw tui" diff --git a/hyperstack/opencode.sh b/hyperstack/opencode.sh deleted file mode 100644 index eca39929..00000000 --- a/hyperstack/opencode.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "OpenCode on Hyperstack" -echo "" - -ensure_hyperstack_api_key -ensure_ssh_key - -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) -create_vm "${VM_NAME}" "${ENVIRONMENT}" -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -log_warn "Installing OpenCode..." -run_server "${HYPERSTACK_VM_IP}" "$(opencode_install_cmd)" -log_info "OpenCode installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -log_warn "Starting OpenCode..." -sleep 1 -clear -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && opencode" diff --git a/hyperstack/plandex.sh b/hyperstack/plandex.sh deleted file mode 100644 index 93f3a0f5..00000000 --- a/hyperstack/plandex.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=hyperstack/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hyperstack/lib/common.sh)" -fi - -log_info "Plandex on Hyperstack" -echo "" - -# 1. Resolve Hyperstack API key -ensure_hyperstack_api_key - -# 2. Generate + register SSH key -ensure_ssh_key - -# 3. Get VM name and create VM -VM_NAME=$(get_vm_name) -ENVIRONMENT=$(get_environment_name) -create_vm "${VM_NAME}" "${ENVIRONMENT}" - -# 4. Wait for SSH -verify_server_connectivity "${HYPERSTACK_VM_IP}" - -# 5. Install Plandex -log_warn "Installing Plandex..." -run_server "${HYPERSTACK_VM_IP}" "curl -sL https://plandex.ai/install.sh | bash" - -# Verify installation succeeded -if ! run_server "${HYPERSTACK_VM_IP}" "command -v plandex &> /dev/null && plandex version &> /dev/null"; then - log_error "Plandex installation verification failed" - log_error "The 'plandex' command is not available or not working properly on server ${HYPERSTACK_VM_IP}" - exit 1 -fi -log_info "Plandex installation verified successfully" - -# 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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${HYPERSTACK_VM_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Hyperstack VM setup completed successfully!" -log_info "VM: ${VM_NAME} (ID: ${HYPERSTACK_VM_ID}, IP: ${HYPERSTACK_VM_IP})" -echo "" - -# 7. Start Plandex interactively -log_warn "Starting Plandex..." -sleep 1 -clear -interactive_session "${HYPERSTACK_VM_IP}" "source ~/.zshrc && plandex" diff --git a/lambda/README.md b/lambda/README.md deleted file mode 100644 index 00d1eeca..00000000 --- a/lambda/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# Lambda Cloud - -Lambda GPU Cloud instances via REST API. [Lambda Cloud](https://lambdalabs.com/) - -> GPU cloud, uses 'ubuntu' user. Manual tool install (no cloud-init). - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/claude.sh) -``` - -#### OpenClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/openclaw.sh) -``` - -#### NanoClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/nanoclaw.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/aider.sh) -``` - -#### Goose - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/goose.sh) -``` - -#### Codex CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/codex.sh) -``` - -#### Open Interpreter - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/interpreter.sh) -``` - -#### Gemini CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/gemini.sh) -``` - -#### Amazon Q CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/amazonq.sh) -``` - -#### Cline - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/cline.sh) -``` - -#### gptme - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/gptme.sh) -``` - -#### OpenCode - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/opencode.sh) -``` - -#### Plandex - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/plandex.sh) -``` - -## Non-Interactive Mode - -```bash -LAMBDA_SERVER_NAME=dev-mk1 \ -LAMBDA_API_KEY=your-key \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/lambda/claude.sh) -``` diff --git a/lambda/aider.sh b/lambda/aider.sh deleted file mode 100644 index 257fe747..00000000 --- a/lambda/aider.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Aider on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Aider -log_warn "Installing Aider..." -run_server "${LAMBDA_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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 9. Start Aider interactively -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/lambda/amazonq.sh b/lambda/amazonq.sh deleted file mode 100644 index 91b95907..00000000 --- a/lambda/amazonq.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Amazon Q on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Amazon Q CLI -log_warn "Installing Amazon Q CLI..." -run_server "${LAMBDA_SERVER_IP}" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" -log_info "Amazon Q 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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Amazon Q interactively -log_warn "Starting Amazon Q..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && q chat" diff --git a/lambda/claude.sh b/lambda/claude.sh deleted file mode 100644 index 20e5c193..00000000 --- a/lambda/claude.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Claude Code on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Verify Claude Code is installed (fallback to manual install) -log_warn "Verifying Claude Code installation..." -if ! run_server "${LAMBDA_SERVER_IP}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${LAMBDA_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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 8. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${LAMBDA_SERVER_IP}" \ - "run_server ${LAMBDA_SERVER_IP}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 9. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && claude" diff --git a/lambda/cline.sh b/lambda/cline.sh deleted file mode 100644 index 33c4d747..00000000 --- a/lambda/cline.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Cline on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Cline -log_warn "Installing Cline..." -run_server "${LAMBDA_SERVER_IP}" "npm install -g cline" -log_info "Cline 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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Cline interactively -log_warn "Starting Cline..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && cline" diff --git a/lambda/codex.sh b/lambda/codex.sh deleted file mode 100644 index 182f03df..00000000 --- a/lambda/codex.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Codex CLI on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Codex CLI -log_warn "Installing Codex CLI..." -run_server "${LAMBDA_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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Codex interactively -log_warn "Starting Codex..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && codex" diff --git a/lambda/gemini.sh b/lambda/gemini.sh deleted file mode 100644 index 8dfc258a..00000000 --- a/lambda/gemini.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Gemini CLI on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Gemini CLI -log_warn "Installing Gemini CLI..." -run_server "${LAMBDA_SERVER_IP}" "npm install -g @google/gemini-cli" -log_info "Gemini 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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "GEMINI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Gemini interactively -log_warn "Starting Gemini..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && gemini" diff --git a/lambda/goose.sh b/lambda/goose.sh deleted file mode 100644 index d2b848f1..00000000 --- a/lambda/goose.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Goose on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Goose -log_warn "Installing Goose..." -run_server "${LAMBDA_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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Goose interactively -log_warn "Starting Goose..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && goose" diff --git a/lambda/gptme.sh b/lambda/gptme.sh deleted file mode 100644 index 18aee665..00000000 --- a/lambda/gptme.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/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 - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "gptme on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "$LAMBDA_SERVER_IP" -wait_for_cloud_init "$LAMBDA_SERVER_IP" - -# 5. Install gptme -log_warn "Installing gptme..." -run_server "$LAMBDA_SERVER_IP" "pip install gptme 2>/dev/null || pip3 install gptme" -log_info "gptme 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 gptme?" -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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" -rm "$ENV_TEMP" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: $SERVER_NAME (IP: $LAMBDA_SERVER_IP)" -echo "" - -# 9. Start gptme interactively -log_warn "Starting gptme..." -sleep 1 -clear -interactive_session "$LAMBDA_SERVER_IP" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}" diff --git a/lambda/interpreter.sh b/lambda/interpreter.sh deleted file mode 100644 index be2534ac..00000000 --- a/lambda/interpreter.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Open Interpreter on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Open Interpreter -log_warn "Installing Open Interpreter..." -run_server "${LAMBDA_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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Open Interpreter interactively -log_warn "Starting Open Interpreter..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && interpreter" diff --git a/lambda/kilocode.sh b/lambda/kilocode.sh deleted file mode 100644 index 79ec7793..00000000 --- a/lambda/kilocode.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Kilo Code on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Kilo Code -log_warn "Installing Kilo Code..." -run_server "${LAMBDA_SERVER_IP}" "npm install -g @kilocode/cli" -log_info "Kilo Code 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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "KILO_PROVIDER_TYPE=openrouter" \ - "KILO_OPEN_ROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Kilo Code interactively -log_warn "Starting Kilo Code..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && kilocode" diff --git a/lambda/lib/common.sh b/lambda/lib/common.sh deleted file mode 100644 index a15e48ef..00000000 --- a/lambda/lib/common.sh +++ /dev/null @@ -1,246 +0,0 @@ -#!/bin/bash -# Common bash functions for Lambda Cloud spawn scripts -# Uses Lambda Cloud REST API — https://docs.lambdalabs.com/cloud/api/ - -# Bash safety flags -set -eo pipefail - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "${SCRIPT_DIR}" && -f "${SCRIPT_DIR}/../../shared/common.sh" ]]; then - source "${SCRIPT_DIR}/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, nc_listen) are now in shared/common.sh - -# ============================================================ -# Lambda Cloud specific functions -# ============================================================ - -LAMBDA_API_BASE="https://cloud.lambdalabs.com/api/v1" -# SSH_OPTS is now defined in shared/common.sh - -# Configurable timeout/delay constants -INSTANCE_STATUS_POLL_DELAY=${INSTANCE_STATUS_POLL_DELAY:-10} # Delay between instance status checks -SSH_RETRY_DELAY=${SSH_RETRY_DELAY:-5} # Delay between SSH connection retry attempts - -lambda_api() { - local method="${1}" endpoint="${2}" body="${3}" - local args=(-s -X "${method}" -H "Authorization: Bearer ${LAMBDA_API_KEY}" -H "Content-Type: application/json") - if [[ -n "${body}" ]]; then args+=(-d "${body}"); fi - curl "${args[@]}" "${LAMBDA_API_BASE}${endpoint}" -} - -test_lambda_token() { - local test_response - test_response=$(lambda_api GET "/instances") - if echo "${test_response}" | grep -q '"error"'; then - log_error "Invalid API key" - return 1 - fi - return 0 -} - -ensure_lambda_token() { - ensure_api_token_with_provider \ - "Lambda Cloud" \ - "LAMBDA_API_KEY" \ - "${HOME}/.config/spawn/lambda.json" \ - "https://cloud.lambdalabs.com/api-keys" \ - "test_lambda_token" -} - -# Check if SSH key is registered with Lambda Cloud -lambda_check_ssh_key() { - local fingerprint="${1}" - local existing_keys - existing_keys=$(lambda_api GET "/ssh-keys") - echo "${existing_keys}" | grep -q "${fingerprint}" -} - -# Register SSH key with Lambda Cloud -lambda_register_ssh_key() { - local key_name="${1}" - local pub_path="${2}" - local pub_key - pub_key=$(cat "${pub_path}") - local json_pub_key - json_pub_key=$(json_escape "${pub_key}") - local register_body="{\"name\":\"${key_name}\",\"public_key\":${json_pub_key}}" - local register_response - register_response=$(lambda_api POST "/ssh-keys" "${register_body}") - - if echo "${register_response}" | grep -q '"id"'; then - return 0 - else - log_error "Failed to register SSH key: ${register_response}" - return 1 - fi -} - -ensure_ssh_key() { - ensure_ssh_key_with_provider lambda_check_ssh_key lambda_register_ssh_key "Lambda Cloud" -} - -get_server_name() { - if [[ -n "${LAMBDA_SERVER_NAME:-}" ]]; then - log_info "Using server name from environment: ${LAMBDA_SERVER_NAME}" - echo "${LAMBDA_SERVER_NAME}"; return 0 - fi - local server_name - server_name=$(safe_read "Enter instance name: ") - if [[ -z "${server_name}" ]]; then - log_error "Instance name is required" - log_warn "Set LAMBDA_SERVER_NAME environment variable for non-interactive usage"; return 1 - fi - echo "${server_name}" -} - -create_server() { - local name="${1}" - local instance_type="${LAMBDA_INSTANCE_TYPE:-gpu_1x_a10}" - local region="${LAMBDA_REGION:-us-east-1}" - - # Validate env var inputs to prevent injection into Python code - validate_resource_name "${instance_type}" || { log_error "Invalid LAMBDA_INSTANCE_TYPE"; return 1; } - validate_region_name "${region}" || { log_error "Invalid LAMBDA_REGION"; return 1; } - - log_warn "Creating Lambda instance '${name}' (type: ${instance_type}, region: ${region})..." - - # Get all SSH key IDs - local ssh_keys_response - ssh_keys_response=$(lambda_api GET "/ssh-keys") - local ssh_key_names - ssh_key_names=$(python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -names = [k['name'] for k in data.get('data', [])] -print(json.dumps(names)) -" <<< "${ssh_keys_response}") - - local body - body=$(python3 -c " -import json -body = { - 'name': '${name}', - 'instance_type_name': '${instance_type}', - 'region_name': '${region}', - 'ssh_key_names': ${ssh_key_names} -} -print(json.dumps(body)) -") - - local response - response=$(lambda_api POST "/instance-operations/launch" "${body}") - - if echo "${response}" | grep -q '"instance_ids"'; then - LAMBDA_SERVER_ID=$(echo "${response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['data']['instance_ids'][0])") - export LAMBDA_SERVER_ID - log_info "Instance launched: ID=${LAMBDA_SERVER_ID}" - else - local error_msg - error_msg=$(echo "${response}" | python3 -c " -import json,sys -d = json.loads(sys.stdin.read()) -print(d.get('error', {}).get('message', d.get('error', 'Unknown error'))) -" 2>/dev/null || echo "${response}") - log_error "Failed to create instance: ${error_msg}" - return 1 - fi - - # Wait for instance to become active and get IP - log_warn "Waiting for instance to become active..." - local max_attempts=60 attempt=1 - while [[ ${attempt} -le ${max_attempts} ]]; do - local status_response - status_response=$(lambda_api GET "/instances/${LAMBDA_SERVER_ID}") - local status - status=$(echo "${status_response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['data']['status'])" 2>/dev/null) - - if [[ "${status}" == "active" ]]; then - LAMBDA_SERVER_IP=$(echo "${status_response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['data']['ip'])") - export LAMBDA_SERVER_IP - log_info "Instance active: IP=${LAMBDA_SERVER_IP}" - return 0 - fi - log_warn "Instance status: ${status} (${attempt}/${max_attempts})" - sleep "${INSTANCE_STATUS_POLL_DELAY}"; attempt=$((attempt + 1)) - done - log_error "Instance did not become active in time"; return 1 -} - -verify_server_connectivity() { - local ip="${1}" max_attempts=${2:-30} attempt=1 - log_warn "Waiting for SSH connectivity to ${ip}..." - while [[ ${attempt} -le ${max_attempts} ]]; do - # SSH_OPTS is defined in shared/common.sh - # shellcheck disable=SC2154,SC2086 - if ssh ${SSH_OPTS} -o ConnectTimeout=5 "ubuntu@${ip}" "echo ok" >/dev/null 2>&1; then - log_info "SSH connection established"; return 0 - fi - log_warn "Waiting for SSH... (${attempt}/${max_attempts})"; sleep "${SSH_RETRY_DELAY}"; attempt=$((attempt + 1)) - done - log_error "Server failed to respond via SSH after ${max_attempts} attempts"; return 1 -} - -wait_for_cloud_init() { - local ip="${1}" - # Lambda instances come pre-provisioned, install tools manually - log_warn "Installing base tools..." - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "ubuntu@${ip}" "sudo apt-get update -y && sudo apt-get install -y curl unzip git zsh" >/dev/null 2>&1 - - # Install Bun - log_warn "Installing Bun..." - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "ubuntu@${ip}" "curl -fsSL https://bun.sh/install | bash" >/dev/null 2>&1 - - # Install Claude Code - log_warn "Installing Claude Code..." - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "ubuntu@${ip}" "curl -fsSL https://claude.ai/install.sh | bash" >/dev/null 2>&1 - - # Configure PATH - # shellcheck disable=SC2086 - ssh ${SSH_OPTS} "ubuntu@${ip}" "echo 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.bashrc && echo 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.zshrc" >/dev/null 2>&1 - - log_info "Base tools installed" -} - -# Lambda uses 'ubuntu' user -# shellcheck disable=SC2086 -run_server() { local ip="${1}" cmd="${2}"; ssh ${SSH_OPTS} "ubuntu@${ip}" "${cmd}"; } -# shellcheck disable=SC2086 -upload_file() { local ip="${1}" local_path="${2}" remote_path="${3}"; scp ${SSH_OPTS} "${local_path}" "ubuntu@${ip}:${remote_path}"; } -# shellcheck disable=SC2086 -interactive_session() { local ip="${1}" cmd="${2}"; ssh -t ${SSH_OPTS} "ubuntu@${ip}" "${cmd}"; } - -destroy_server() { - local server_id="${1}" - log_warn "Terminating instance ${server_id}..." - lambda_api POST "/instance-operations/terminate" "{\"instance_ids\":[\"${server_id}\"]}" - log_info "Instance ${server_id} terminated" -} - -list_servers() { - local response - response=$(lambda_api GET "/instances") - python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -instances = data.get('data', []) -if not instances: print('No instances found'); sys.exit(0) -print(f\"{'NAME':<25} {'ID':<40} {'STATUS':<12} {'IP':<16} {'TYPE':<20}\") -print('-' * 113) -for i in instances: - name = i.get('name','N/A'); iid = i['id']; status = i['status'] - ip = i.get('ip', 'N/A'); itype = i.get('instance_type',{}).get('name','N/A') - print(f'{name:<25} {iid:<40} {status:<12} {ip:<16} {itype:<20}') -" <<< "${response}" -} diff --git a/lambda/nanoclaw.sh b/lambda/nanoclaw.sh deleted file mode 100644 index 9784c93e..00000000 --- a/lambda/nanoclaw.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "NanoClaw on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Node.js deps and clone nanoclaw -log_warn "Installing tsx..." -run_server "${LAMBDA_SERVER_IP}" "source ~/.bashrc && bun install -g tsx" - -log_warn "Cloning and building nanoclaw..." -run_server "${LAMBDA_SERVER_IP}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build" -log_info "NanoClaw 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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 8. Create nanoclaw .env file -log_warn "Configuring nanoclaw..." - -DOTENV_TEMP=$(mktemp) -cat > "${DOTENV_TEMP}" << EOF -ANTHROPIC_API_KEY=${OPENROUTER_API_KEY} -EOF - -upload_file "${LAMBDA_SERVER_IP}" "${DOTENV_TEMP}" "/home/ubuntu/nanoclaw/.env" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 9. Start nanoclaw -log_warn "Starting nanoclaw..." -log_warn "You will need to scan a WhatsApp QR code to authenticate." -echo "" -interactive_session "${LAMBDA_SERVER_IP}" "cd ~/nanoclaw && source ~/.zshrc && npm run dev" diff --git a/lambda/openclaw.sh b/lambda/openclaw.sh deleted file mode 100755 index ada81aba..00000000 --- a/lambda/openclaw.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "OpenClaw on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install openclaw via bun -log_warn "Installing openclaw..." -run_server "${LAMBDA_SERVER_IP}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw 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 -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -# 8. Inject environment variables into ~/.zshrc -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${LAMBDA_SERVER_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 9. Configure openclaw -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${LAMBDA_SERVER_IP}" \ - "run_server ${LAMBDA_SERVER_IP}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 10. Start openclaw gateway in background and launch TUI -log_warn "Starting openclaw..." -run_server "${LAMBDA_SERVER_IP}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && openclaw tui" diff --git a/lambda/opencode.sh b/lambda/opencode.sh deleted file mode 100644 index 456debbf..00000000 --- a/lambda/opencode.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "OpenCode on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install OpenCode -log_warn "Installing OpenCode..." -run_server "${LAMBDA_SERVER_IP}" "$(opencode_install_cmd)" -log_info "OpenCode 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 -log_warn "Setting up environment variables..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start OpenCode interactively -log_warn "Starting OpenCode..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && opencode" diff --git a/lambda/plandex.sh b/lambda/plandex.sh deleted file mode 100644 index 65d37047..00000000 --- a/lambda/plandex.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=lambda/lib/common.sh - -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/lambda/lib/common.sh)" -fi - -log_info "Plandex on Lambda Cloud" -echo "" - -# 1. Ensure Lambda API key is configured -ensure_lambda_token - -# 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 "${LAMBDA_SERVER_IP}" -wait_for_cloud_init "${LAMBDA_SERVER_IP}" - -# 5. Install Plandex -log_warn "Installing Plandex..." -run_server "${LAMBDA_SERVER_IP}" "curl -sL https://plandex.ai/install.sh | bash" -log_info "Plandex 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..." - -inject_env_vars_ssh "${LAMBDA_INSTANCE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Lambda Cloud instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (IP: ${LAMBDA_SERVER_IP})" -echo "" - -# 8. Start Plandex interactively -log_warn "Starting Plandex..." -sleep 1 -clear -interactive_session "${LAMBDA_SERVER_IP}" "source ~/.zshrc && plandex" diff --git a/manifest.json b/manifest.json index 9d7e3cc6..ccc76107 100644 --- a/manifest.json +++ b/manifest.json @@ -288,21 +288,6 @@ "image": "linode/ubuntu24.04" } }, - "lambda": { - "name": "Lambda Cloud", - "description": "Lambda GPU Cloud instances via REST API", - "url": "https://lambdalabs.com/", - "type": "api", - "auth": "LAMBDA_API_KEY", - "provision_method": "POST /v1/instance-operations/launch", - "exec_method": "ssh ubuntu@IP", - "interactive_method": "ssh -t ubuntu@IP", - "defaults": { - "instance_type": "gpu_1x_a10", - "region": "us-east-1" - }, - "notes": "GPU cloud, uses 'ubuntu' user. Manual tool install (no cloud-init)." - }, "aws-lightsail": { "name": "AWS Lightsail", "description": "AWS Lightsail instances via AWS CLI", @@ -396,20 +381,6 @@ }, "notes": "Uses Machines API for provisioning and flyctl SSH for exec. Docker-based, pay-per-second pricing. Requires flyctl CLI." }, - "fluidstack": { - "name": "FluidStack", - "description": "FluidStack GPU cloud via REST API", - "url": "https://www.fluidstack.io/", - "type": "api", - "auth": "FLUIDSTACK_API_KEY", - "provision_method": "POST /instances with gpu_type and ssh_key", - "exec_method": "ssh root@IP", - "interactive_method": "ssh -t root@IP", - "defaults": { - "gpu_type": "RTX_4090" - }, - "notes": "GPU cloud provider with A100s and H100s starting at $1.35/hr. Up to 70% cheaper than hyperscalers. Zero egress fees. Simple REST API with Python SDK available." - }, "civo": { "name": "Civo", "description": "Civo cloud-native instances via REST API", @@ -458,23 +429,6 @@ }, "notes": "Sub-90ms sandbox creation. True SSH support via daytona ssh. Requires DAYTONA_API_KEY from https://app.daytona.io." }, - "runpod": { - "name": "RunPod", - "description": "RunPod GPU cloud pods via GraphQL API", - "url": "https://www.runpod.io/", - "type": "api", - "auth": "RUNPOD_API_KEY", - "provision_method": "GraphQL mutation podFindAndDeployOnDemand", - "exec_method": "ssh root@IP -p PORT or ssh PODID@ssh.runpod.io", - "interactive_method": "ssh -t root@IP -p PORT", - "defaults": { - "gpu_type": "NVIDIA RTX A4000", - "gpu_count": 1, - "image": "runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04", - "volume_gb": 50 - }, - "notes": "GPU cloud provider. Uses GraphQL API, SSH via TCP port mapping or proxy. Docker-based pods with CUDA pre-installed." - }, "upcloud": { "name": "UpCloud", "description": "UpCloud cloud servers via REST API with MaxIOPS storage", @@ -507,22 +461,6 @@ }, "notes": "Australian cloud provider. Hourly billing prorated from monthly rates. API documentation at api.binarylane.com.au/reference/" }, - "genesiscloud": { - "name": "Genesis Cloud", - "description": "Genesis Cloud GPU instances via REST API", - "url": "https://www.genesiscloud.com/", - "type": "api", - "auth": "GENESIS_API_KEY", - "provision_method": "POST /compute/v1/instances with ssh_keys", - "exec_method": "ssh root@IP", - "interactive_method": "ssh -t root@IP", - "defaults": { - "instance_type": "vcpu-4_memory-12g_nvidia-rtx-3080-1", - "region": "ARC-IS-HAF-1", - "image": "Ubuntu 24.04" - }, - "notes": "GPU cloud provider with NVIDIA RTX 3080/3090, A100, and H100 instances. European data centers (Iceland, Norway). Requires GENESIS_API_KEY from https://developers.genesiscloud.com/" - }, "latitude": { "name": "Latitude.sh", "description": "Latitude.sh bare metal and VM servers via REST API", @@ -589,22 +527,6 @@ }, "notes": "European cloud provider with bare metal and VPS. Hourly billing. Full root access. Requires CHERRY_AUTH_TOKEN from https://portal.cherryservers.com/" }, - "crusoe": { - "name": "Crusoe Cloud", - "description": "Crusoe Cloud GPU instances via CLI", - "url": "https://crusoecloud.com/", - "type": "cli", - "auth": "~/.crusoe/config (access_key_id + secret_key)", - "provision_method": "crusoe compute vms create with --keyfile and --startup-script", - "exec_method": "ssh root@IP", - "interactive_method": "ssh -t root@IP", - "defaults": { - "vm_type": "a40.1x", - "location": "us-east1-a", - "image": "ubuntu22.04:latest" - }, - "notes": "GPU cloud provider with NVIDIA H200/H100/L40S/A100 and AMD MI300X. Carbon-reducing infrastructure. Starting at $1.45/GPU-hr. Requires Crusoe CLI and ~/.crusoe/config with API credentials from https://console.crusoecloud.com/" - }, "oracle": { "name": "Oracle Cloud Infrastructure", "description": "Oracle Cloud compute instances via OCI CLI", @@ -620,37 +542,6 @@ }, "notes": "Has a generous Always Free tier (VM.Standard.E2.1.Micro, VM.Standard.A1.Flex). Uses 'ubuntu' user for SSH. Requires OCI CLI installed (pip install oci-cli) and configured. Set OCI_COMPARTMENT_ID for the target compartment." }, - "vastai": { - "name": "Vast.ai", - "description": "Vast.ai GPU marketplace via CLI", - "url": "https://vast.ai/", - "type": "cli", - "auth": "VASTAI_API_KEY", - "provision_method": "vastai create instance OFFER_ID --image IMAGE --ssh", - "exec_method": "ssh root@IP -p PORT", - "interactive_method": "ssh -t root@IP -p PORT", - "defaults": { - "gpu_type": "RTX_4090", - "disk_gb": 40, - "image": "nvidia/cuda:12.1.0-devel-ubuntu22.04" - }, - "notes": "GPU marketplace with per-hour pricing. Uses vastai CLI (pip install vastai). SSH via dynamic port mapping. Docker-based instances with CUDA pre-installed." - }, - "hyperstack": { - "name": "Hyperstack", - "description": "Hyperstack GPU cloud via REST API", - "url": "https://www.hyperstack.cloud/", - "type": "api", - "auth": "HYPERSTACK_API_KEY", - "provision_method": "POST /core/virtual-machines", - "exec_method": "ssh root@IP", - "interactive_method": "ssh -t root@IP", - "defaults": { - "flavor": "n1-cpu-small", - "image": "Ubuntu Server 24.04 LTS R5504 UEFI" - }, - "notes": "GPU cloud provider. Competitive pricing on RTX A6000 ($0.50/hr). Requires HYPERSTACK_API_KEY from https://infrahub.hyperstack.cloud" - }, "koyeb": { "name": "Koyeb", "description": "Koyeb serverless container platform via CLI", @@ -711,22 +602,6 @@ "runtime": "docker" }, "notes": "Developer-first platform with free Hobby plan (100GB bandwidth, 500 build minutes). Requires API key from https://dashboard.render.com/u/settings/api-keys. SSH not available on free tier." - }, - "paperspace": { - "name": "Paperspace", - "description": "Paperspace GPU cloud (DigitalOcean) via CLI and REST API", - "url": "https://www.paperspace.com/", - "type": "cli+api", - "auth": "PAPERSPACE_API_KEY", - "provision_method": "POST /v1/machines with machineType and templateId", - "exec_method": "ssh root@IP", - "interactive_method": "ssh -t root@IP", - "defaults": { - "machine_type": "C4", - "region": "NY2", - "disk_size": 50 - }, - "notes": "GPU cloud now part of DigitalOcean. Hourly billing. Uses pspace CLI (curl -fsSL https://www.paperspace.com/install.sh | sh) and REST API. Free unlimited bandwidth." } }, "matrix": { @@ -778,27 +653,17 @@ "vultr/gemini": "implemented", "linode/gemini": "implemented", "aws-lightsail/gemini": "implemented", - "lambda/claude": "implemented", - "lambda/openclaw": "implemented", - "lambda/nanoclaw": "implemented", - "lambda/aider": "implemented", - "lambda/goose": "implemented", - "lambda/codex": "implemented", - "lambda/interpreter": "implemented", - "lambda/gemini": "implemented", "sprite/amazonq": "implemented", "hetzner/amazonq": "implemented", "digitalocean/amazonq": "implemented", "vultr/amazonq": "implemented", "linode/amazonq": "implemented", - "lambda/amazonq": "implemented", "aws-lightsail/amazonq": "implemented", "sprite/cline": "implemented", "hetzner/cline": "implemented", "digitalocean/cline": "implemented", "vultr/cline": "implemented", "linode/cline": "implemented", - "lambda/cline": "implemented", "aws-lightsail/cline": "implemented", "gcp/claude": "implemented", "gcp/openclaw": "implemented", @@ -845,7 +710,6 @@ "digitalocean/gptme": "implemented", "vultr/gptme": "implemented", "linode/gptme": "implemented", - "lambda/gptme": "implemented", "aws-lightsail/gptme": "implemented", "gcp/gptme": "implemented", "github-codespaces/gptme": "implemented", @@ -862,20 +726,6 @@ "fly/amazonq": "implemented", "fly/cline": "implemented", "fly/gptme": "implemented", - "fluidstack/claude": "implemented", - "fluidstack/openclaw": "implemented", - "fluidstack/nanoclaw": "implemented", - "fluidstack/aider": "implemented", - "fluidstack/goose": "implemented", - "fluidstack/codex": "implemented", - "fluidstack/interpreter": "implemented", - "fluidstack/gemini": "implemented", - "fluidstack/amazonq": "implemented", - "fluidstack/cline": "implemented", - "fluidstack/gptme": "implemented", - "fluidstack/opencode": "implemented", - "fluidstack/plandex": "implemented", - "fluidstack/kilocode": "implemented", "civo/claude": "implemented", "civo/aider": "implemented", "civo/codex": "implemented", @@ -892,7 +742,6 @@ "digitalocean/opencode": "implemented", "vultr/opencode": "implemented", "linode/opencode": "implemented", - "lambda/opencode": "implemented", "aws-lightsail/opencode": "implemented", "gcp/opencode": "implemented", "github-codespaces/opencode": "implemented", @@ -929,7 +778,6 @@ "digitalocean/plandex": "implemented", "vultr/plandex": "implemented", "linode/plandex": "implemented", - "lambda/plandex": "implemented", "aws-lightsail/plandex": "implemented", "gcp/plandex": "implemented", "github-codespaces/plandex": "implemented", @@ -939,19 +787,6 @@ "civo/plandex": "implemented", "scaleway/plandex": "implemented", "daytona/plandex": "implemented", - "runpod/claude": "implemented", - "runpod/openclaw": "implemented", - "runpod/nanoclaw": "implemented", - "runpod/aider": "implemented", - "runpod/goose": "implemented", - "runpod/codex": "implemented", - "runpod/interpreter": "implemented", - "runpod/gemini": "implemented", - "runpod/amazonq": "implemented", - "runpod/cline": "implemented", - "runpod/gptme": "implemented", - "runpod/opencode": "implemented", - "runpod/plandex": "implemented", "upcloud/claude": "implemented", "upcloud/openclaw": "implemented", "upcloud/nanoclaw": "implemented", @@ -978,19 +813,6 @@ "binarylane/gptme": "implemented", "binarylane/opencode": "implemented", "binarylane/plandex": "implemented", - "genesiscloud/claude": "implemented", - "genesiscloud/openclaw": "implemented", - "genesiscloud/nanoclaw": "implemented", - "genesiscloud/aider": "implemented", - "genesiscloud/goose": "implemented", - "genesiscloud/codex": "implemented", - "genesiscloud/interpreter": "implemented", - "genesiscloud/gemini": "implemented", - "genesiscloud/amazonq": "implemented", - "genesiscloud/cline": "implemented", - "genesiscloud/gptme": "implemented", - "genesiscloud/opencode": "implemented", - "genesiscloud/plandex": "implemented", "latitude/claude": "implemented", "latitude/openclaw": "implemented", "latitude/nanoclaw": "implemented", @@ -1035,7 +857,6 @@ "digitalocean/kilocode": "implemented", "vultr/kilocode": "implemented", "linode/kilocode": "implemented", - "lambda/kilocode": "implemented", "aws-lightsail/kilocode": "implemented", "gcp/kilocode": "implemented", "github-codespaces/kilocode": "implemented", @@ -1045,10 +866,8 @@ "civo/kilocode": "implemented", "scaleway/kilocode": "implemented", "daytona/kilocode": "implemented", - "runpod/kilocode": "implemented", "upcloud/kilocode": "implemented", "binarylane/kilocode": "implemented", - "genesiscloud/kilocode": "implemented", "latitude/kilocode": "implemented", "ovh/kilocode": "implemented", "kamatera/kilocode": "implemented", @@ -1066,34 +885,6 @@ "oracle/opencode": "implemented", "oracle/plandex": "implemented", "oracle/kilocode": "implemented", - "vastai/claude": "implemented", - "vastai/aider": "implemented", - "vastai/codex": "implemented", - "vastai/openclaw": "implemented", - "vastai/nanoclaw": "implemented", - "vastai/goose": "implemented", - "vastai/interpreter": "implemented", - "vastai/gemini": "implemented", - "vastai/amazonq": "implemented", - "vastai/cline": "implemented", - "vastai/gptme": "implemented", - "vastai/opencode": "implemented", - "vastai/plandex": "implemented", - "vastai/kilocode": "implemented", - "hyperstack/claude": "implemented", - "hyperstack/openclaw": "implemented", - "hyperstack/nanoclaw": "implemented", - "hyperstack/aider": "implemented", - "hyperstack/goose": "implemented", - "hyperstack/codex": "implemented", - "hyperstack/interpreter": "implemented", - "hyperstack/gemini": "implemented", - "hyperstack/amazonq": "implemented", - "hyperstack/cline": "implemented", - "hyperstack/gptme": "implemented", - "hyperstack/opencode": "implemented", - "hyperstack/plandex": "implemented", - "hyperstack/kilocode": "implemented", "koyeb/claude": "implemented", "koyeb/openclaw": "implemented", "koyeb/nanoclaw": "implemented", @@ -1163,34 +954,6 @@ "cherry/gptme": "implemented", "cherry/opencode": "implemented", "cherry/plandex": "implemented", - "cherry/kilocode": "implemented", - "crusoe/claude": "implemented", - "crusoe/openclaw": "implemented", - "crusoe/nanoclaw": "missing", - "crusoe/aider": "implemented", - "crusoe/goose": "missing", - "crusoe/codex": "missing", - "crusoe/interpreter": "missing", - "crusoe/gemini": "missing", - "crusoe/amazonq": "missing", - "crusoe/cline": "missing", - "crusoe/gptme": "missing", - "crusoe/opencode": "missing", - "crusoe/plandex": "missing", - "crusoe/kilocode": "missing", - "paperspace/claude": "implemented", - "paperspace/openclaw": "implemented", - "paperspace/nanoclaw": "implemented", - "paperspace/aider": "implemented", - "paperspace/goose": "implemented", - "paperspace/codex": "implemented", - "paperspace/interpreter": "implemented", - "paperspace/gemini": "implemented", - "paperspace/amazonq": "implemented", - "paperspace/cline": "implemented", - "paperspace/gptme": "implemented", - "paperspace/opencode": "implemented", - "paperspace/plandex": "implemented", - "paperspace/kilocode": "implemented" + "cherry/kilocode": "implemented" } -} \ No newline at end of file +} diff --git a/paperspace/README.md b/paperspace/README.md deleted file mode 100644 index 6c44d3b2..00000000 --- a/paperspace/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Paperspace - -Paperspace GPU cloud machines (now part of DigitalOcean) via CLI and REST API. [Paperspace](https://www.paperspace.com/) - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/paperspace/claude.sh) -``` - -#### OpenClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/paperspace/openclaw.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/paperspace/aider.sh) -``` - -## Non-Interactive Mode - -```bash -PAPERSPACE_MACHINE_NAME=dev-mk1 \ -PAPERSPACE_API_KEY=your-api-key \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/paperspace/claude.sh) -``` - -## Environment Variables - -- `PAPERSPACE_API_KEY` - API key from https://console.paperspace.com/account/api -- `PAPERSPACE_MACHINE_NAME` - Name for the machine -- `PAPERSPACE_MACHINE_TYPE` - Machine type (default: C4) -- `PAPERSPACE_REGION` - Region (default: NY2, options: NY2, CA1, AMS1) -- `PAPERSPACE_DISK_SIZE` - Disk size in GB (default: 50) -- `OPENROUTER_API_KEY` - OpenRouter API key - -## Features - -- GPU machines starting at ~$0.46/hour (M4000) up to $1.90/hour (A6000) -- Hourly billing - only pay when machine is running (plus storage when stopped) -- Free unlimited bandwidth -- Three regions: NY2 (New York), CA1 (California), AMS1 (Amsterdam) -- Both CLI (pspace) and REST API support -- Full SSH access as root user - -## Getting Started - -1. Sign up at https://www.paperspace.com/ -2. Create an API key at https://console.paperspace.com/account/api -3. Run any agent script - the pspace CLI will auto-install if needed diff --git a/paperspace/aider.sh b/paperspace/aider.sh deleted file mode 100644 index bbf5ac1b..00000000 --- a/paperspace/aider.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=paperspace/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/paperspace/lib/common.sh)" -fi - -log_info "Aider on Paperspace" -echo "" - -# 1. Ensure pspace CLI is installed -ensure_pspace_installed - -# 2. Resolve Paperspace API key -ensure_paperspace_api_key - -# 3. Generate SSH key locally -ensure_ssh_key - -# 4. Get machine name and create machine -MACHINE_NAME=$(get_machine_name) -create_machine "${MACHINE_NAME}" - -# 5. Wait for SSH and system initialization -verify_server_connectivity "${PAPERSPACE_MACHINE_IP}" -wait_for_cloud_init "${PAPERSPACE_MACHINE_IP}" 120 - -# 6. Install Aider -log_warn "Installing Aider..." -run_server "${PAPERSPACE_MACHINE_IP}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -# Verify installation succeeded -if ! run_server "${PAPERSPACE_MACHINE_IP}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - log_error "The 'aider' command is not available or not working properly on machine ${PAPERSPACE_MACHINE_IP}" - exit 1 -fi -log_info "Aider installation verified successfully" - -# 7. 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${PAPERSPACE_MACHINE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Paperspace machine setup completed successfully!" -log_info "Machine: ${MACHINE_NAME} (ID: ${PAPERSPACE_MACHINE_ID}, IP: ${PAPERSPACE_MACHINE_IP})" -echo "" - -# 8. Start Aider interactively -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${PAPERSPACE_MACHINE_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/paperspace/claude.sh b/paperspace/claude.sh deleted file mode 100644 index 119c583a..00000000 --- a/paperspace/claude.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=paperspace/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/paperspace/lib/common.sh)" -fi - -log_info "Claude Code on Paperspace" -echo "" - -# 1. Ensure pspace CLI is installed -ensure_pspace_installed - -# 2. Resolve Paperspace API key -ensure_paperspace_api_key - -# 3. Generate SSH key locally -ensure_ssh_key - -# 4. Get machine name and create machine -MACHINE_NAME=$(get_machine_name) -create_machine "${MACHINE_NAME}" - -# 5. Wait for SSH and system initialization -verify_server_connectivity "${PAPERSPACE_MACHINE_IP}" -wait_for_cloud_init "${PAPERSPACE_MACHINE_IP}" 120 - -# 6. Verify Claude Code is installed (fallback to manual install) -log_warn "Verifying Claude Code installation..." -if ! run_server "${PAPERSPACE_MACHINE_IP}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${PAPERSPACE_MACHINE_IP}" "curl -fsSL https://claude.ai/install.sh | bash" -fi - -# Verify installation succeeded -if ! run_server "${PAPERSPACE_MACHINE_IP}" "command -v claude &> /dev/null && claude --version &> /dev/null"; then - log_error "Claude Code installation verification failed" - log_error "The 'claude' command is not available or not working properly on machine ${PAPERSPACE_MACHINE_IP}" - exit 1 -fi -log_info "Claude Code installation verified successfully" - -# 7. 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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${PAPERSPACE_MACHINE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 8. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${PAPERSPACE_MACHINE_IP}" \ - "run_server ${PAPERSPACE_MACHINE_IP}" - -echo "" -log_info "Paperspace machine setup completed successfully!" -log_info "Machine: ${MACHINE_NAME} (ID: ${PAPERSPACE_MACHINE_ID}, IP: ${PAPERSPACE_MACHINE_IP})" -echo "" - -# 9. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${PAPERSPACE_MACHINE_IP}" "source ~/.zshrc && claude" diff --git a/paperspace/lib/common.sh b/paperspace/lib/common.sh deleted file mode 100644 index 7c4b294a..00000000 --- a/paperspace/lib/common.sh +++ /dev/null @@ -1,307 +0,0 @@ -#!/bin/bash -set -eo pipefail -# Common bash functions for Paperspace spawn scripts - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../shared/common.sh" ]]; then - source "$SCRIPT_DIR/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, nc_listen) are now in shared/common.sh - -# ============================================================ -# Paperspace specific functions -# ============================================================ - -readonly PAPERSPACE_API_BASE="https://api.paperspace.com/v1" -readonly DEFAULT_MACHINE_TYPE="${PAPERSPACE_MACHINE_TYPE:-C4}" -readonly DEFAULT_REGION="${PAPERSPACE_REGION:-NY2}" -readonly DEFAULT_DISK_SIZE="${PAPERSPACE_DISK_SIZE:-50}" - -# Ensure pspace CLI is installed -ensure_pspace_installed() { - if ! command -v pspace &> /dev/null; then - log_warn "pspace CLI not found, installing..." - curl -fsSL https://www.paperspace.com/install.sh | sh - - # Verify installation - if ! command -v pspace &> /dev/null; then - log_error "Failed to install pspace CLI" - log_error "Please install manually: curl -fsSL https://www.paperspace.com/install.sh | sh" - return 1 - fi - log_info "pspace CLI installed successfully" - fi - return 0 -} - -# Test Paperspace API key -test_paperspace_api_key() { - local response - response=$(curl -fsSL -H "Authorization: Bearer ${PAPERSPACE_API_KEY}" \ - "${PAPERSPACE_API_BASE}/machines" 2>&1) - - if echo "$response" | grep -qi "unauthorized\|forbidden\|invalid"; then - log_error "API authentication failed" - log_error "" - log_error "How to fix:" - log_error " 1. Go to https://console.paperspace.com/account/api" - log_error " 2. Create a new API key if you don't have one" - log_error " 3. Copy the API key and set it as PAPERSPACE_API_KEY" - return 1 - fi - return 0 -} - -# Ensure PAPERSPACE_API_KEY is available (env var → config file → prompt+save) -ensure_paperspace_api_key() { - ensure_api_token_with_provider \ - "Paperspace" \ - "PAPERSPACE_API_KEY" \ - "$HOME/.config/spawn/paperspace.json" \ - "https://console.paperspace.com/account/api" \ - "test_paperspace_api_key" -} - -# Get machine name from env var or prompt -get_machine_name() { - local machine_name - machine_name=$(get_resource_name "PAPERSPACE_MACHINE_NAME" "Enter machine name: ") || return 1 - - if ! validate_server_name "$machine_name"; then - return 1 - fi - - echo "$machine_name" -} - -# Get or find a suitable template ID for Ubuntu -get_ubuntu_template() { - # Try to list templates and find Ubuntu 22.04 or 20.04 - local templates - templates=$(curl -fsSL -H "Authorization: Bearer ${PAPERSPACE_API_KEY}" \ - "${PAPERSPACE_API_BASE}/templates" 2>/dev/null || echo "") - - # Try to extract Ubuntu 22.04 template first, then 20.04 - local template_id - template_id=$(echo "$templates" | python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - templates = data if isinstance(data, list) else data.get('templates', []) - # Prefer Ubuntu 22.04 - for t in templates: - if 'ubuntu' in t.get('name', '').lower() and '22.04' in t.get('name', ''): - print(t.get('id', '')) - exit(0) - # Fallback to Ubuntu 20.04 - for t in templates: - if 'ubuntu' in t.get('name', '').lower() and '20.04' in t.get('name', ''): - print(t.get('id', '')) - exit(0) -except: - pass -" 2>/dev/null || echo "") - - # If we found a template, use it - if [[ -n "$template_id" ]]; then - echo "$template_id" - return 0 - fi - - # Fallback to a known Ubuntu template ID (this may need updating) - echo "tx98gvxz" # Common Ubuntu template -} - -# Ensure SSH key exists locally and get public key -ensure_ssh_key() { - ensure_ssh_key_with_provider "" "" "Paperspace" -} - -# Create a Paperspace machine -create_machine() { - local name="$1" - local machine_type="${DEFAULT_MACHINE_TYPE}" - local region="${DEFAULT_REGION}" - local disk_size="${DEFAULT_DISK_SIZE}" - - log_warn "Creating Paperspace machine '$name' (type: $machine_type, region: $region, disk: ${disk_size}GB)..." - - # Get SSH public key - local ssh_pub_key - ssh_pub_key=$(cat ~/.ssh/spawn-ed25519.pub) - - # Get template ID - local template_id - template_id=$(get_ubuntu_template) - log_info "Using template ID: $template_id" - - # Create startup script for cloud-init-like setup - local startup_script - startup_script=$(get_cloud_init_userdata) - - # Create a temporary file for the startup script - local script_file="/tmp/paperspace-startup-$$.sh" - echo "$startup_script" > "$script_file" - - # Create machine using pspace CLI - # Note: pspace doesn't support all the flags we need, so we'll use the API - local create_response - create_response=$(curl -fsSL -X POST \ - -H "Authorization: Bearer ${PAPERSPACE_API_KEY}" \ - -H "Content-Type: application/json" \ - "${PAPERSPACE_API_BASE}/machines" \ - -d "$(python3 -c " -import json, sys -data = { - 'name': '$name', - 'machineType': '$machine_type', - 'region': '$region', - 'size': $disk_size, - 'templateId': '$template_id', - 'billingType': 'hourly', - 'startOnCreate': True -} -print(json.dumps(data)) -")" 2>&1) - - # Clean up temp file - rm -f "$script_file" - - # Check for errors - if echo "$create_response" | grep -qi "error\|failed"; then - log_error "Failed to create machine:" - log_error "$create_response" - return 1 - fi - - # Extract machine ID and IP - export PAPERSPACE_MACHINE_ID=$(echo "$create_response" | python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('id', '')) -except: - pass -" 2>/dev/null || echo "") - - if [[ -z "$PAPERSPACE_MACHINE_ID" ]]; then - log_error "Failed to get machine ID from response" - return 1 - fi - - log_info "Machine created with ID: $PAPERSPACE_MACHINE_ID" - log_warn "Waiting for machine to start..." - - # Wait for machine to be ready and get IP - local retries=60 - while [[ $retries -gt 0 ]]; do - local machine_info - machine_info=$(curl -fsSL -H "Authorization: Bearer ${PAPERSPACE_API_KEY}" \ - "${PAPERSPACE_API_BASE}/machines/${PAPERSPACE_MACHINE_ID}" 2>/dev/null || echo "") - - local state - state=$(echo "$machine_info" | python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('state', '')) -except: - pass -" 2>/dev/null || echo "") - - if [[ "$state" == "ready" ]]; then - export PAPERSPACE_MACHINE_IP=$(echo "$machine_info" | python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('publicIpAddress', '')) -except: - pass -" 2>/dev/null || echo "") - - if [[ -n "$PAPERSPACE_MACHINE_IP" ]]; then - log_info "Machine is ready! IP: $PAPERSPACE_MACHINE_IP" - return 0 - fi - fi - - sleep 5 - retries=$((retries - 1)) - done - - log_error "Machine failed to become ready in time" - return 1 -} - -# Verify server connectivity via SSH -verify_server_connectivity() { - local ip="$1" - generic_ssh_wait "$ip" "root" 60 -} - -# Run command on Paperspace machine -run_server() { - local ip="$1" - shift - ssh ${SSH_OPTS} root@"${ip}" "$@" -} - -# Upload file to Paperspace machine -upload_file() { - local ip="$1" - local src="$2" - local dest="$3" - scp ${SSH_OPTS} "$src" root@"${ip}":"$dest" -} - -# Start interactive session -interactive_session() { - local ip="$1" - local cmd="${2:-bash}" - ssh -t ${SSH_OPTS} root@"${ip}" "$cmd" -} - -# Wait for cloud-init to complete -wait_for_cloud_init() { - local ip="$1" - local timeout="${2:-300}" - - log_warn "Waiting for system initialization (timeout: ${timeout}s)..." - local elapsed=0 - while [[ $elapsed -lt $timeout ]]; do - if run_server "$ip" "command -v curl" >/dev/null 2>&1; then - log_info "System initialization complete" - return 0 - fi - sleep 5 - elapsed=$((elapsed + 5)) - done - - log_error "System initialization timed out" - return 1 -} - -# Delete Paperspace machine -delete_machine() { - local machine_id="${1:-${PAPERSPACE_MACHINE_ID}}" - - if [[ -z "$machine_id" ]]; then - log_warn "No machine ID provided, skipping deletion" - return 0 - fi - - log_warn "Deleting machine $machine_id..." - curl -fsSL -X DELETE \ - -H "Authorization: Bearer ${PAPERSPACE_API_KEY}" \ - "${PAPERSPACE_API_BASE}/machines/${machine_id}" >/dev/null 2>&1 || true - - log_info "Machine deletion initiated" -} diff --git a/paperspace/openclaw.sh b/paperspace/openclaw.sh deleted file mode 100644 index b249a7bf..00000000 --- a/paperspace/openclaw.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=paperspace/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/paperspace/lib/common.sh)" -fi - -log_info "OpenClaw on Paperspace" -echo "" - -# 1. Ensure pspace CLI is installed -ensure_pspace_installed - -# 2. Resolve Paperspace API key -ensure_paperspace_api_key - -# 3. Generate SSH key locally -ensure_ssh_key - -# 4. Get machine name and create machine -MACHINE_NAME=$(get_machine_name) -create_machine "${MACHINE_NAME}" - -# 5. Wait for SSH and system initialization -verify_server_connectivity "${PAPERSPACE_MACHINE_IP}" -wait_for_cloud_init "${PAPERSPACE_MACHINE_IP}" 120 - -# 6. Install openclaw via bun -log_warn "Installing openclaw..." -run_server "${PAPERSPACE_MACHINE_IP}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw installed" - -# 7. 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${PAPERSPACE_MACHINE_IP}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 8. Configure openclaw -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${PAPERSPACE_MACHINE_IP}" \ - "run_server ${PAPERSPACE_MACHINE_IP}" - -echo "" -log_info "Paperspace machine setup completed successfully!" -log_info "Machine: ${MACHINE_NAME} (ID: ${PAPERSPACE_MACHINE_ID}, IP: ${PAPERSPACE_MACHINE_IP})" -echo "" - -# 9. Start openclaw gateway in background and launch TUI -log_warn "Starting openclaw..." -run_server "${PAPERSPACE_MACHINE_IP}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${PAPERSPACE_MACHINE_IP}" "source ~/.zshrc && openclaw tui" diff --git a/runpod/README.md b/runpod/README.md deleted file mode 100644 index a2bdb74e..00000000 --- a/runpod/README.md +++ /dev/null @@ -1,118 +0,0 @@ -# RunPod - -RunPod GPU cloud pods via GraphQL API. [RunPod](https://www.runpod.io/) - -## Prerequisites - -1. A RunPod account with API key from [Settings](https://www.runpod.io/console/user/settings) -2. SSH public key added to your RunPod account (same settings page) - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/claude.sh) -``` - -#### OpenClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/openclaw.sh) -``` - -#### NanoClaw - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/nanoclaw.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/aider.sh) -``` - -#### Goose - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/goose.sh) -``` - -#### Codex CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/codex.sh) -``` - -#### Open Interpreter - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/interpreter.sh) -``` - -#### Gemini CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/gemini.sh) -``` - -#### Amazon Q CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/amazonq.sh) -``` - -#### Cline - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/cline.sh) -``` - -#### gptme - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/gptme.sh) -``` - -#### OpenCode - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/opencode.sh) -``` - -#### Plandex - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/plandex.sh) -``` - -## Non-Interactive Mode - -```bash -RUNPOD_SERVER_NAME=dev-gpu \ -RUNPOD_API_KEY=your-api-key \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/runpod/claude.sh) -``` - -## Environment Variables - -| Variable | Description | Default | -|---|---|---| -| `RUNPOD_API_KEY` | RunPod API key | _(prompted)_ | -| `RUNPOD_SERVER_NAME` | Pod name | _(prompted)_ | -| `RUNPOD_GPU_TYPE` | GPU type ID | `NVIDIA RTX A4000` | -| `RUNPOD_GPU_COUNT` | Number of GPUs | `1` | -| `RUNPOD_IMAGE` | Docker image | `runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04` | -| `RUNPOD_VOLUME_GB` | Persistent volume size (GB) | `50` | -| `RUNPOD_CONTAINER_DISK_GB` | Container disk size (GB) | `20` | -| `RUNPOD_CLOUD_TYPE` | Cloud type (`ALL`, `COMMUNITY`, `SECURE`) | `ALL` | -| `OPENROUTER_API_KEY` | OpenRouter API key | _(prompted via OAuth)_ | - -## Notes - -- RunPod is a GPU cloud provider -- pods come with NVIDIA GPUs and CUDA pre-installed -- SSH keys must be added via the RunPod web console (not via API) -- Pods use Docker containers; base tools are installed automatically on first run -- SSH access is via direct TCP port mapping or RunPod's SSH proxy diff --git a/runpod/aider.sh b/runpod/aider.sh deleted file mode 100644 index 0e670f40..00000000 --- a/runpod/aider.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Aider on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Aider..." -run_server "${RUNPOD_POD_ID}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -if ! run_server "${RUNPOD_POD_ID}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - exit 1 -fi -log_info "Aider installation verified successfully" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/runpod/amazonq.sh b/runpod/amazonq.sh deleted file mode 100644 index 1d478c07..00000000 --- a/runpod/amazonq.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Amazon Q on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Amazon Q CLI..." -run_server "${RUNPOD_POD_ID}" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" -log_info "Amazon Q CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Amazon Q..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && q chat" diff --git a/runpod/claude.sh b/runpod/claude.sh deleted file mode 100644 index 5085ee96..00000000 --- a/runpod/claude.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Claude Code on RunPod" -echo "" - -# 1. Ensure RunPod API key is configured -ensure_runpod_token - -# 2. Ensure SSH key exists (user must add to RunPod console) -ensure_ssh_key - -# 3. Get pod name and create pod -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 4. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 5. Verify Claude Code is installed (fallback to manual install) -log_warn "Verifying Claude Code installation..." -if ! run_server "${RUNPOD_POD_ID}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${RUNPOD_POD_ID}" "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 -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 8. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${RUNPOD_POD_ID}" \ - "run_server ${RUNPOD_POD_ID}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -# 9. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && claude" diff --git a/runpod/cline.sh b/runpod/cline.sh deleted file mode 100644 index 2d97ffc4..00000000 --- a/runpod/cline.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Cline on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Cline..." -run_server "${RUNPOD_POD_ID}" "npm install -g cline" -log_info "Cline installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Cline..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && cline" diff --git a/runpod/codex.sh b/runpod/codex.sh deleted file mode 100644 index 64004f26..00000000 --- a/runpod/codex.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Codex CLI on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Codex CLI..." -run_server "${RUNPOD_POD_ID}" "npm install -g @openai/codex" -log_info "Codex CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Codex..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && codex" diff --git a/runpod/gemini.sh b/runpod/gemini.sh deleted file mode 100644 index f9dce39a..00000000 --- a/runpod/gemini.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Gemini CLI on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Gemini CLI..." -run_server "${RUNPOD_POD_ID}" "npm install -g @google/gemini-cli" -log_info "Gemini CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "GEMINI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Gemini..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && gemini" diff --git a/runpod/goose.sh b/runpod/goose.sh deleted file mode 100644 index 990ecf3e..00000000 --- a/runpod/goose.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Goose on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Goose..." -run_server "${RUNPOD_POD_ID}" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" - -if ! run_server "${RUNPOD_POD_ID}" "command -v goose &> /dev/null && goose --version &> /dev/null"; then - log_error "Goose installation verification failed" - exit 1 -fi -log_info "Goose installation verified successfully" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "GOOSE_PROVIDER=openrouter" \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Goose..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && goose" diff --git a/runpod/gptme.sh b/runpod/gptme.sh deleted file mode 100644 index 01a0f49a..00000000 --- a/runpod/gptme.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# 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 - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "gptme on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing gptme..." -run_server "${RUNPOD_POD_ID}" "pip install gptme 2>/dev/null || pip3 install gptme" - -if ! run_server "${RUNPOD_POD_ID}" "command -v gptme &> /dev/null && gptme --version &> /dev/null"; then - log_error "gptme installation verification failed" - exit 1 -fi -log_info "gptme installation verified successfully" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting gptme..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}" diff --git a/runpod/interpreter.sh b/runpod/interpreter.sh deleted file mode 100644 index aadd4703..00000000 --- a/runpod/interpreter.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Open Interpreter on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Open Interpreter..." -run_server "${RUNPOD_POD_ID}" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter" -log_info "Open Interpreter installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Open Interpreter..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && interpreter" diff --git a/runpod/kilocode.sh b/runpod/kilocode.sh deleted file mode 100644 index 33958d94..00000000 --- a/runpod/kilocode.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Kilo Code on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Kilo Code CLI..." -run_server "${RUNPOD_POD_ID}" "npm install -g @kilocode/cli" -log_info "Kilo Code CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "KILO_PROVIDER_TYPE=openrouter" \ - "KILO_OPEN_ROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Kilo Code..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && kilocode" diff --git a/runpod/lib/common.sh b/runpod/lib/common.sh deleted file mode 100644 index 5f0e8053..00000000 --- a/runpod/lib/common.sh +++ /dev/null @@ -1,321 +0,0 @@ -#!/bin/bash -# Common bash functions for RunPod spawn scripts -# Uses RunPod GraphQL API — https://docs.runpod.io/ - -# Bash safety flags -set -eo pipefail - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "${SCRIPT_DIR}" && -f "${SCRIPT_DIR}/../../shared/common.sh" ]]; then - source "${SCRIPT_DIR}/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# Note: Provider-agnostic functions (logging, OAuth, browser, nc_listen) are now in shared/common.sh - -# ============================================================ -# RunPod specific functions -# ============================================================ - -RUNPOD_GRAPHQL_URL="https://api.runpod.io/graphql" -# SSH_OPTS is defined in shared/common.sh - -# Configurable timeout/delay constants -INSTANCE_STATUS_POLL_DELAY=${INSTANCE_STATUS_POLL_DELAY:-10} # Delay between instance status checks -SSH_RETRY_DELAY=${SSH_RETRY_DELAY:-5} # Delay between SSH connection retry attempts - -# RunPod GraphQL API wrapper -# Usage: runpod_api QUERY -runpod_api() { - local query="${1}" - - # Pass query safely via stdin to avoid triple-quote injection - local body - body=$(python3 -c " -import json, sys -q = sys.stdin.read().strip() -print(json.dumps({'query': q})) -" <<< "${query}") - - curl -s -X POST \ - -H "Content-Type: application/json" \ - -H "api-key: ${RUNPOD_API_KEY}" \ - "${RUNPOD_GRAPHQL_URL}" \ - -d "${body}" -} - -test_runpod_token() { - local response - response=$(runpod_api "query { myself { id } }") - if echo "${response}" | grep -q '"errors"'; then - local error_msg - error_msg=$(echo "${response}" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('errors',[{}])[0].get('message','Unknown error'))" 2>/dev/null || echo "Unable to parse error") - log_error "API Error: ${error_msg}" - log_warn "Remediation steps:" - log_warn " 1. Verify API key at: https://www.runpod.io/console/user/settings" - log_warn " 2. Ensure the key has read/write permissions" - log_warn " 3. Check key hasn't been revoked" - return 1 - fi - return 0 -} - -# Ensure RUNPOD_API_KEY is available (env var -> config file -> prompt+save) -ensure_runpod_token() { - ensure_api_token_with_provider \ - "RunPod" \ - "RUNPOD_API_KEY" \ - "${HOME}/.config/spawn/runpod.json" \ - "https://www.runpod.io/console/user/settings" \ - "test_runpod_token" -} - -# RunPod manages SSH keys at the account level via the web console. -# Users must add their SSH public key at https://www.runpod.io/console/user/settings -# The key is automatically injected into all new pods. -ensure_ssh_key() { - local key_path="${HOME}/.ssh/id_ed25519" - generate_ssh_key_if_missing "${key_path}" - - log_warn "RunPod requires SSH keys to be added via the web console." - log_warn "Ensure your public key is added at: https://www.runpod.io/console/user/settings" - log_warn "" - log_warn "Your public key:" - cat "${key_path}.pub" >&2 - echo "" >&2 -} - -get_server_name() { - local server_name - server_name=$(get_resource_name "RUNPOD_SERVER_NAME" "Enter pod name: ") || return 1 - - if ! validate_server_name "${server_name}"; then - return 1 - fi - - echo "${server_name}" -} - -# Wait for a RunPod pod to become ready and set SSH connection vars -# Sets: RUNPOD_SSH_HOST, RUNPOD_SSH_PORT, RUNPOD_SSH_USER -# Usage: wait_for_pod_ready POD_ID [MAX_ATTEMPTS] -wait_for_pod_ready() { - local pod_id="${1}" - local max_attempts=${2:-60} - local attempt=1 - - log_warn "Waiting for pod to become ready..." - while [[ "${attempt}" -le "${max_attempts}" ]]; do - local status_query='query { pod(input: { podId: "'"${pod_id}"'" }) { id name desiredStatus runtime { uptimeInSeconds ports { ip isIpPublic privatePort publicPort type } } } }' - local status_response - status_response=$(runpod_api "${status_query}") - - local runtime - runtime=$(echo "${status_response}" | python3 -c "import json,sys; r=json.loads(sys.stdin.read())['data']['pod']['runtime']; print('running' if r else 'pending')" 2>/dev/null || echo "pending") - - if [[ "${runtime}" == "running" ]]; then - # Extract SSH connection info from ports - local ssh_info - ssh_info=$(echo "${status_response}" | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -ports = data['data']['pod']['runtime']['ports'] -for p in (ports or []): - if p['privatePort'] == 22 and p['type'] == 'tcp': - print(p['ip'] + ':' + str(p['publicPort'])) - sys.exit(0) -# No direct TCP port found, fall back to proxy SSH -print('proxy') -" 2>/dev/null || echo "proxy") - - if [[ "${ssh_info}" == "proxy" ]]; then - RUNPOD_SSH_HOST="ssh.runpod.io" - RUNPOD_SSH_PORT="22" - RUNPOD_SSH_USER="${pod_id}" - export RUNPOD_SSH_HOST RUNPOD_SSH_PORT RUNPOD_SSH_USER - log_info "Pod ready (using SSH proxy: ${RUNPOD_SSH_USER}@${RUNPOD_SSH_HOST})" - else - RUNPOD_SSH_HOST=$(echo "${ssh_info}" | cut -d: -f1) - RUNPOD_SSH_PORT=$(echo "${ssh_info}" | cut -d: -f2) - RUNPOD_SSH_USER="root" - export RUNPOD_SSH_HOST RUNPOD_SSH_PORT RUNPOD_SSH_USER - log_info "Pod ready: SSH at ${RUNPOD_SSH_HOST}:${RUNPOD_SSH_PORT}" - fi - return 0 - fi - - local desired_status - desired_status=$(echo "${status_response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['data']['pod']['desiredStatus'])" 2>/dev/null || echo "UNKNOWN") - log_warn "Pod status: ${desired_status}/${runtime} (${attempt}/${max_attempts})" - sleep "${INSTANCE_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - done - - log_error "Pod did not become ready in time" - return 1 -} - -create_server() { - local name="${1}" - local gpu_type="${RUNPOD_GPU_TYPE:-NVIDIA RTX A4000}" - local gpu_count="${RUNPOD_GPU_COUNT:-1}" - local image="${RUNPOD_IMAGE:-runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04}" - local volume_gb="${RUNPOD_VOLUME_GB:-50}" - local container_disk_gb="${RUNPOD_CONTAINER_DISK_GB:-20}" - local cloud_type="${RUNPOD_CLOUD_TYPE:-ALL}" - - # Validate numeric env vars to prevent injection into GraphQL query - if [[ ! "${gpu_count}" =~ ^[0-9]+$ ]]; then log_error "Invalid RUNPOD_GPU_COUNT: must be numeric"; return 1; fi - if [[ ! "${volume_gb}" =~ ^[0-9]+$ ]]; then log_error "Invalid RUNPOD_VOLUME_GB: must be numeric"; return 1; fi - if [[ ! "${container_disk_gb}" =~ ^[0-9]+$ ]]; then log_error "Invalid RUNPOD_CONTAINER_DISK_GB: must be numeric"; return 1; fi - if [[ ! "${cloud_type}" =~ ^[A-Z]+$ ]]; then log_error "Invalid RUNPOD_CLOUD_TYPE: must be uppercase letters only"; return 1; fi - # Block injection chars in string values (quotes, backslashes) - if [[ "${gpu_type}" =~ [\"\`\$\\] ]]; then log_error "Invalid RUNPOD_GPU_TYPE: contains unsafe characters"; return 1; fi - if [[ "${image}" =~ [\"\`\$\\] ]]; then log_error "Invalid RUNPOD_IMAGE: contains unsafe characters"; return 1; fi - - log_warn "Creating RunPod pod '${name}' (GPU: ${gpu_type}, image: ${image})..." - - local query='mutation { podFindAndDeployOnDemand(input: { name: "'"${name}"'", imageName: "'"${image}"'", gpuTypeId: "'"${gpu_type}"'", cloudType: '"${cloud_type}"', gpuCount: '"${gpu_count}"', volumeInGb: '"${volume_gb}"', containerDiskInGb: '"${container_disk_gb}"', ports: "22/tcp", volumeMountPath: "/workspace", dockerArgs: "" }) { id imageName machineId } }' - - local response - response=$(runpod_api "${query}") - - if echo "${response}" | grep -q '"errors"'; then - log_error "Failed to create RunPod pod" - local error_msg - error_msg=$(echo "${response}" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('errors',[{}])[0].get('message','Unknown error'))" 2>/dev/null || echo "${response}") - log_error "API Error: ${error_msg}" - log_warn "Common issues:" - log_warn " - Insufficient account balance" - log_warn " - GPU type unavailable (try different RUNPOD_GPU_TYPE)" - log_warn " - GPU count unavailable" - log_warn "Remediation: Check https://www.runpod.io/console/pods" - return 1 - fi - - RUNPOD_POD_ID=$(echo "${response}" | python3 -c "import json,sys; print(json.loads(sys.stdin.read())['data']['podFindAndDeployOnDemand']['id'])") - export RUNPOD_POD_ID - log_info "Pod created: ID=${RUNPOD_POD_ID}" - - wait_for_pod_ready "${RUNPOD_POD_ID}" -} - -# Build SSH options string for RunPod (may use non-standard port) -_runpod_ssh_opts() { - echo "${SSH_OPTS} -o ConnectTimeout=10 -p ${RUNPOD_SSH_PORT}" -} - -verify_server_connectivity() { - local max_attempts=${1:-30} - local attempt=1 - local ssh_target="${RUNPOD_SSH_USER}@${RUNPOD_SSH_HOST}" - - log_warn "Waiting for SSH connectivity to ${ssh_target}:${RUNPOD_SSH_PORT}..." - while [[ "${attempt}" -le "${max_attempts}" ]]; do - # shellcheck disable=SC2086 - if ssh $(_runpod_ssh_opts) "${ssh_target}" "echo ok" >/dev/null 2>&1; then - log_info "SSH connection established" - return 0 - fi - log_warn "Waiting for SSH... (${attempt}/${max_attempts})" - sleep "${SSH_RETRY_DELAY}" - attempt=$((attempt + 1)) - done - log_error "Pod failed to respond via SSH after ${max_attempts} attempts" - return 1 -} - -# Install base tools (RunPod pods are Docker containers, no cloud-init) -install_base_tools() { - local ssh_target="${RUNPOD_SSH_USER}@${RUNPOD_SSH_HOST}" - - log_warn "Installing base tools..." - # shellcheck disable=SC2086 - ssh $(_runpod_ssh_opts) "${ssh_target}" "apt-get update -y && apt-get install -y curl unzip git zsh npm" >/dev/null 2>&1 || true - - # Install Bun - log_warn "Installing Bun..." - # shellcheck disable=SC2086 - ssh $(_runpod_ssh_opts) "${ssh_target}" "curl -fsSL https://bun.sh/install | bash" >/dev/null 2>&1 || true - - # Install Claude Code - log_warn "Installing Claude Code..." - # shellcheck disable=SC2086 - ssh $(_runpod_ssh_opts) "${ssh_target}" "curl -fsSL https://claude.ai/install.sh | bash" >/dev/null 2>&1 || true - - # Configure PATH in .bashrc and .zshrc - # shellcheck disable=SC2086 - ssh $(_runpod_ssh_opts) "${ssh_target}" "grep -q '.bun/bin' ~/.bashrc 2>/dev/null || printf '%s\n' 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.bashrc; grep -q '.bun/bin' ~/.zshrc 2>/dev/null || printf '%s\n' 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.zshrc" >/dev/null 2>&1 || true - - log_info "Base tools installed" -} - -# RunPod uses root user (or pod ID for proxy SSH) -# These functions follow the IP-first arg pattern for compatibility with inject_env_vars_ssh -# The "ip" arg is ignored since RunPod uses RUNPOD_SSH_USER@RUNPOD_SSH_HOST -# shellcheck disable=SC2086 -run_server() { - local _ip="${1}" - local cmd="${2}" - ssh $(_runpod_ssh_opts) "${RUNPOD_SSH_USER}@${RUNPOD_SSH_HOST}" "${cmd}" -} - -# shellcheck disable=SC2086 -upload_file() { - local _ip="${1}" - local local_path="${2}" - local remote_path="${3}" - scp $(_runpod_ssh_opts) "${local_path}" "${RUNPOD_SSH_USER}@${RUNPOD_SSH_HOST}:${remote_path}" -} - -# shellcheck disable=SC2086 -interactive_session() { - local _ip="${1}" - local cmd="${2}" - ssh -t $(_runpod_ssh_opts) "${RUNPOD_SSH_USER}@${RUNPOD_SSH_HOST}" "${cmd}" -} - -destroy_server() { - local pod_id="${1}" - log_warn "Terminating pod ${pod_id}..." - local query='mutation { podTerminate(input: { podId: "'"${pod_id}"'" }) }' - runpod_api "${query}" >/dev/null - log_info "Pod ${pod_id} terminated" -} - -list_servers() { - local query='query { myself { pods { id name desiredStatus runtime { uptimeInSeconds ports { ip isIpPublic privatePort publicPort type } } } } }' - local response - response=$(runpod_api "${query}") - - python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -pods = data.get('data', {}).get('myself', {}).get('pods', []) -if not pods: - print('No pods found') - sys.exit(0) -print(f\"{'NAME':<25} {'ID':<25} {'STATUS':<12} {'SSH':<30}\") -print('-' * 92) -for p in pods: - name = p.get('name', 'N/A') - pid = p['id'] - status = p.get('desiredStatus', 'N/A') - ssh_info = 'N/A' - runtime = p.get('runtime') - if runtime and runtime.get('ports'): - for port in runtime['ports']: - if port.get('privatePort') == 22 and port.get('type') == 'tcp': - ssh_info = f\"{port['ip']}:{port['publicPort']}\" - break - if ssh_info == 'N/A': - ssh_info = f\"{pid}@ssh.runpod.io\" - print(f'{name:<25} {pid:<25} {status:<12} {ssh_info:<30}') -" <<< "${response}" -} diff --git a/runpod/nanoclaw.sh b/runpod/nanoclaw.sh deleted file mode 100644 index 035d9c5a..00000000 --- a/runpod/nanoclaw.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "NanoClaw on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing tsx..." -run_server "${RUNPOD_POD_ID}" "source ~/.bashrc && bun install -g tsx" - -log_warn "Cloning and building nanoclaw..." -run_server "${RUNPOD_POD_ID}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build" -log_info "NanoClaw installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -log_warn "Configuring nanoclaw..." -DOTENV_TEMP=$(mktemp) -trap 'rm -f "${DOTENV_TEMP}"' EXIT -chmod 600 "${DOTENV_TEMP}" -cat > "${DOTENV_TEMP}" << EOF -ANTHROPIC_API_KEY=${OPENROUTER_API_KEY} -EOF - -upload_file "${RUNPOD_POD_ID}" "${DOTENV_TEMP}" "/root/nanoclaw/.env" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting nanoclaw..." -log_warn "You will need to scan a WhatsApp QR code to authenticate." -echo "" -interactive_session "${RUNPOD_POD_ID}" "cd ~/nanoclaw && source ~/.zshrc && npm run dev" diff --git a/runpod/openclaw.sh b/runpod/openclaw.sh deleted file mode 100644 index b9d686ff..00000000 --- a/runpod/openclaw.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "OpenClaw on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing openclaw..." -run_server "${RUNPOD_POD_ID}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw installed" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${RUNPOD_POD_ID}" \ - "run_server ${RUNPOD_POD_ID}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting openclaw..." -run_server "${RUNPOD_POD_ID}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && openclaw tui" diff --git a/runpod/opencode.sh b/runpod/opencode.sh deleted file mode 100644 index 7102ce8e..00000000 --- a/runpod/opencode.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "OpenCode on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing OpenCode..." -run_server "${RUNPOD_POD_ID}" "$(opencode_install_cmd)" -log_info "OpenCode installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting OpenCode..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && opencode" diff --git a/runpod/plandex.sh b/runpod/plandex.sh deleted file mode 100644 index 9c02265c..00000000 --- a/runpod/plandex.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=runpod/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/runpod/lib/common.sh)" -fi - -log_info "Plandex on RunPod" -echo "" - -ensure_runpod_token -ensure_ssh_key - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Plandex..." -run_server "${RUNPOD_POD_ID}" "curl -sL https://plandex.ai/install.sh | bash" - -if ! run_server "${RUNPOD_POD_ID}" "command -v plandex &> /dev/null && plandex version &> /dev/null"; then - log_error "Plandex installation verification failed" - exit 1 -fi -log_info "Plandex installation verified successfully" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${RUNPOD_POD_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "RunPod pod setup completed successfully!" -log_info "Pod: ${SERVER_NAME} (ID: ${RUNPOD_POD_ID})" -echo "" - -log_warn "Starting Plandex..." -sleep 1 -clear -interactive_session "${RUNPOD_POD_ID}" "source ~/.zshrc && plandex" diff --git a/vastai/README.md b/vastai/README.md deleted file mode 100644 index e548e865..00000000 --- a/vastai/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Vast.ai - -Vast.ai GPU marketplace via CLI. [Vast.ai](https://vast.ai/) - -## Prerequisites - -1. A Vast.ai account with API key from [Account Settings](https://cloud.vast.ai/account/) -2. Python 3 with pip (for installing the `vastai` CLI) - -## Agents - -#### Claude Code - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/vastai/claude.sh) -``` - -#### Aider - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/vastai/aider.sh) -``` - -#### Codex CLI - -```bash -bash <(curl -fsSL https://openrouter.ai/lab/spawn/vastai/codex.sh) -``` - -## Non-Interactive Mode - -```bash -VASTAI_SERVER_NAME=dev-gpu \ -VASTAI_API_KEY=your-api-key \ -OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - bash <(curl -fsSL https://openrouter.ai/lab/spawn/vastai/claude.sh) -``` - -## Environment Variables - -| Variable | Description | Default | -|---|---|---| -| `VASTAI_API_KEY` | Vast.ai API key | _(prompted)_ | -| `VASTAI_SERVER_NAME` | Instance label | _(prompted)_ | -| `VASTAI_GPU_TYPE` | GPU type to search for | `RTX_4090` | -| `VASTAI_DISK_GB` | Disk size in GB | `40` | -| `VASTAI_IMAGE` | Docker image | `nvidia/cuda:12.1.0-devel-ubuntu22.04` | -| `OPENROUTER_API_KEY` | OpenRouter API key | _(prompted via OAuth)_ | - -## Notes - -- Vast.ai is a GPU marketplace -- instances come with NVIDIA GPUs and CUDA pre-installed -- The `vastai` CLI is installed automatically if not present (`pip install vastai`) -- Instances are Docker containers; base tools are installed automatically on first run -- SSH access is via dynamic port mapping (non-standard ports) -- Pricing is per-hour, varies by GPU type and availability diff --git a/vastai/aider.sh b/vastai/aider.sh deleted file mode 100644 index e14c3f04..00000000 --- a/vastai/aider.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Aider on Vast.ai" -echo "" - -ensure_vastai_cli -ensure_vastai_token - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Aider..." -run_server "${VASTAI_INSTANCE_ID}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" - -if ! run_server "${VASTAI_INSTANCE_ID}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then - log_error "Aider installation verification failed" - exit 1 -fi -log_info "Aider installation verified successfully" - -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 - -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -log_warn "Starting Aider..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/vastai/amazonq.sh b/vastai/amazonq.sh deleted file mode 100644 index f4cee812..00000000 --- a/vastai/amazonq.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Amazon Q on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Amazon Q CLI -log_warn "Installing Amazon Q CLI..." -run_server "${VASTAI_INSTANCE_ID}" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" -log_info "Amazon Q CLI installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Amazon Q interactively -log_warn "Starting Amazon Q..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && q chat" diff --git a/vastai/claude.sh b/vastai/claude.sh deleted file mode 100644 index 8ffd0670..00000000 --- a/vastai/claude.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Claude Code on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Verify Claude Code is installed (fallback to manual install) -log_warn "Verifying Claude Code installation..." -if ! run_server "${VASTAI_INSTANCE_ID}" "command -v claude" >/dev/null 2>&1; then - log_warn "Claude Code not found, installing manually..." - run_server "${VASTAI_INSTANCE_ID}" "curl -fsSL https://claude.ai/install.sh | bash" -fi -log_info "Claude Code is installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" \ - "ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=" \ - "CLAUDE_CODE_SKIP_ONBOARDING=1" \ - "CLAUDE_CODE_ENABLE_TELEMETRY=0" - -# 7. Configure Claude Code settings -setup_claude_code_config "${OPENROUTER_API_KEY}" \ - "upload_file ${VASTAI_INSTANCE_ID}" \ - "run_server ${VASTAI_INSTANCE_ID}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 8. Start Claude Code interactively -log_warn "Starting Claude Code..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && claude" diff --git a/vastai/cline.sh b/vastai/cline.sh deleted file mode 100644 index 9e78a088..00000000 --- a/vastai/cline.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Cline on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Cline -log_warn "Installing Cline..." -run_server "${VASTAI_INSTANCE_ID}" "npm install -g cline" -log_info "Cline installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Cline interactively -log_warn "Starting Cline..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && cline" diff --git a/vastai/codex.sh b/vastai/codex.sh deleted file mode 100644 index 212df189..00000000 --- a/vastai/codex.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Codex CLI on Vast.ai" -echo "" - -ensure_vastai_cli -ensure_vastai_token - -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" -verify_server_connectivity -install_base_tools - -log_warn "Installing Codex CLI..." -run_server "${VASTAI_INSTANCE_ID}" "npm install -g @openai/codex" -log_info "Codex CLI installed" - -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 - -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -log_warn "Starting Codex..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && codex" diff --git a/vastai/gemini.sh b/vastai/gemini.sh deleted file mode 100644 index aee45a3b..00000000 --- a/vastai/gemini.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Gemini CLI on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Gemini CLI -log_warn "Installing Gemini CLI..." -run_server "${VASTAI_INSTANCE_ID}" "npm install -g @google/gemini-cli" -log_info "Gemini CLI installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "GEMINI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Gemini CLI interactively -log_warn "Starting Gemini..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && gemini" diff --git a/vastai/goose.sh b/vastai/goose.sh deleted file mode 100644 index 25d22316..00000000 --- a/vastai/goose.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Goose on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Goose -log_warn "Installing Goose..." -run_server "${VASTAI_INSTANCE_ID}" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" -log_info "Goose installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "GOOSE_PROVIDER=openrouter" \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Goose interactively -log_warn "Starting Goose..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && goose" diff --git a/vastai/gptme.sh b/vastai/gptme.sh deleted file mode 100644 index c88c5db1..00000000 --- a/vastai/gptme.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "gptme on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install gptme -log_warn "Installing gptme..." -run_server "${VASTAI_INSTANCE_ID}" "pip install gptme 2>/dev/null || pip3 install gptme" - -# Verify installation succeeded -if ! run_server "${VASTAI_INSTANCE_ID}" "command -v gptme && gptme --version" >/dev/null 2>&1; then - log_error "gptme installation verification failed" - exit 1 -fi -log_info "gptme installation verified successfully" - -# 5. 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start gptme interactively -log_warn "Starting gptme..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}" diff --git a/vastai/interpreter.sh b/vastai/interpreter.sh deleted file mode 100644 index 78cdd6e2..00000000 --- a/vastai/interpreter.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Open Interpreter on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Open Interpreter -log_warn "Installing Open Interpreter..." -run_server "${VASTAI_INSTANCE_ID}" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter" -log_info "Open Interpreter installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_API_KEY=${OPENROUTER_API_KEY}" \ - "OPENAI_BASE_URL=https://openrouter.ai/api/v1" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Open Interpreter interactively -log_warn "Starting Open Interpreter..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && interpreter" diff --git a/vastai/kilocode.sh b/vastai/kilocode.sh deleted file mode 100644 index 372c96b5..00000000 --- a/vastai/kilocode.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Kilo Code on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Kilo Code -log_warn "Installing Kilo Code..." -run_server "${VASTAI_INSTANCE_ID}" "npm install -g @kilocode/cli" -log_info "Kilo Code installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "KILO_PROVIDER_TYPE=openrouter" \ - "KILO_OPEN_ROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Kilo Code interactively -log_warn "Starting Kilo Code..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && kilocode" diff --git a/vastai/lib/common.sh b/vastai/lib/common.sh deleted file mode 100644 index 016393a9..00000000 --- a/vastai/lib/common.sh +++ /dev/null @@ -1,362 +0,0 @@ -#!/bin/bash -# Common bash functions for Vast.ai spawn scripts -# Uses Vast.ai CLI (vastai) — https://vast.ai/docs/ - -# Bash safety flags -set -eo pipefail - -# ============================================================ -# Provider-agnostic functions -# ============================================================ - -# Source shared provider-agnostic functions (local or remote fallback) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -if [[ -n "${SCRIPT_DIR}" && -f "${SCRIPT_DIR}/../../shared/common.sh" ]]; then - source "${SCRIPT_DIR}/../../shared/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/common.sh)" -fi - -# ============================================================ -# Vast.ai specific functions -# ============================================================ - -# SSH_OPTS is defined in shared/common.sh - -# Configurable timeout/delay constants -INSTANCE_STATUS_POLL_DELAY=${INSTANCE_STATUS_POLL_DELAY:-10} -SSH_RETRY_DELAY=${SSH_RETRY_DELAY:-5} - -# Ensure vastai CLI is installed -ensure_vastai_cli() { - if command -v vastai &>/dev/null; then - return 0 - fi - - log_warn "Installing Vast.ai CLI..." - pip install vastai 2>/dev/null || pip3 install vastai 2>/dev/null || { - log_error "Failed to install vastai CLI" - log_error "Please install manually: pip install vastai" - return 1 - } - log_info "Vast.ai CLI installed" -} - -# Test Vast.ai API key validity -test_vastai_token() { - local result - result=$(vastai show instances 2>&1) || true - - if printf '%s' "${result}" | grep -qi "invalid\|unauthorized\|forbidden\|error.*key\|error.*auth"; then - log_error "Invalid Vast.ai API key" - log_warn "Get your API key from: https://cloud.vast.ai/account/" - return 1 - fi - return 0 -} - -# Ensure VASTAI_API_KEY is available (env var -> config file -> prompt+save) -ensure_vastai_token() { - # Vast.ai CLI reads from ~/.vast_api_key, so check that too - if [[ -z "${VASTAI_API_KEY:-}" ]] && [[ -f "${HOME}/.vast_api_key" ]]; then - VASTAI_API_KEY=$(cat "${HOME}/.vast_api_key" 2>/dev/null) - if [[ -n "${VASTAI_API_KEY}" ]]; then - log_info "Using Vast.ai API key from ~/.vast_api_key" - export VASTAI_API_KEY - fi - fi - - ensure_api_token_with_provider \ - "Vast.ai" \ - "VASTAI_API_KEY" \ - "${HOME}/.config/spawn/vastai.json" \ - "https://cloud.vast.ai/account/" \ - "test_vastai_token" - - # Also set the key for the vastai CLI - vastai set api-key "${VASTAI_API_KEY}" >/dev/null 2>&1 || true -} - -get_server_name() { - local server_name - server_name=$(get_resource_name "VASTAI_SERVER_NAME" "Enter instance name: ") || return 1 - - if ! validate_server_name "${server_name}"; then - return 1 - fi - - echo "${server_name}" -} - -# Validate Vast.ai create_server parameters -# Usage: _validate_vastai_params DISK_GB IMAGE GPU_TYPE -_validate_vastai_params() { - local disk_gb="${1}" image="${2}" gpu_type="${3}" - - if [[ ! "${disk_gb}" =~ ^[0-9]+$ ]]; then - log_error "Invalid VASTAI_DISK_GB: must be numeric" - return 1 - fi - if [[ "${image}" =~ [\"\`\$\\] ]]; then - log_error "Invalid VASTAI_IMAGE: contains unsafe characters" - return 1 - fi - if [[ "${gpu_type}" =~ [\"\`\$\\] ]]; then - log_error "Invalid VASTAI_GPU_TYPE: contains unsafe characters" - return 1 - fi -} - -# Search for the cheapest available GPU offer on Vast.ai -# Prints the offer ID on success -# Usage: _find_cheapest_offer GPU_TYPE -_find_cheapest_offer() { - local gpu_type="${1}" - - log_warn "Searching for available ${gpu_type} offers..." - - local offer_id - offer_id=$(vastai search offers "gpu_name=${gpu_type} num_gpus=1 rentable=true inet_down>100 reliability>0.95" -o "dph_total" --raw 2>/dev/null | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -if not data: - sys.exit(1) -print(data[0]['id']) -" 2>/dev/null) || { - log_error "No available offers found for GPU type: ${gpu_type}" - log_warn "Try a different GPU type with VASTAI_GPU_TYPE (e.g., RTX_3090, RTX_4080)" - log_warn "Browse available GPUs at: https://cloud.vast.ai/create/" - return 1 - } - - log_info "Found offer: ${offer_id}" - printf '%s' "${offer_id}" -} - -# Create a Vast.ai instance from an offer and extract its ID -# Sets: VASTAI_INSTANCE_ID -# Usage: _create_vastai_instance OFFER_ID NAME IMAGE DISK_GB -_create_vastai_instance() { - local offer_id="${1}" name="${2}" image="${3}" disk_gb="${4}" - - local create_output - create_output=$(vastai create instance "${offer_id}" \ - --image "${image}" \ - --disk "${disk_gb}" \ - --ssh \ - --direct \ - --label "${name}" \ - --onstart-cmd "apt-get update -y && apt-get install -y curl unzip git zsh" \ - 2>&1) || { - log_error "Failed to create Vast.ai instance" - log_error "${create_output}" - log_warn "Common issues:" - log_warn " - Insufficient account balance (add funds at https://cloud.vast.ai/billing/)" - log_warn " - GPU type unavailable" - return 1 - } - - # Extract instance ID from create output - VASTAI_INSTANCE_ID=$(printf '%s' "${create_output}" | grep -oP "new instance is \K[0-9]+" 2>/dev/null || \ - printf '%s' "${create_output}" | python3 -c " -import sys, re -text = sys.stdin.read() -m = re.search(r'(\d{5,})', text) -if m: - print(m.group(1)) -else: - sys.exit(1) -" 2>/dev/null) || { - log_error "Could not extract instance ID from create output" - log_error "Output: ${create_output}" - return 1 - } - - export VASTAI_INSTANCE_ID - log_info "Instance created: ID=${VASTAI_INSTANCE_ID}" -} - -# Search for an available offer and create an instance -# Sets: VASTAI_INSTANCE_ID -create_server() { - local name="${1}" - local gpu_type="${VASTAI_GPU_TYPE:-RTX_4090}" - local disk_gb="${VASTAI_DISK_GB:-40}" - local image="${VASTAI_IMAGE:-nvidia/cuda:12.1.0-devel-ubuntu22.04}" - - _validate_vastai_params "${disk_gb}" "${image}" "${gpu_type}" || return 1 - - local offer_id - offer_id=$(_find_cheapest_offer "${gpu_type}") || return 1 - - log_warn "Creating instance '${name}' (GPU: ${gpu_type}, image: ${image})..." - _create_vastai_instance "${offer_id}" "${name}" "${image}" "${disk_gb}" || return 1 - - wait_for_instance_ready "${VASTAI_INSTANCE_ID}" -} - -# Wait for a Vast.ai instance to become ready and set SSH connection vars -# Sets: VASTAI_SSH_HOST, VASTAI_SSH_PORT -wait_for_instance_ready() { - local instance_id="${1}" - local max_attempts=${2:-60} - local attempt=1 - - log_warn "Waiting for instance to become ready..." - while [[ "${attempt}" -le "${max_attempts}" ]]; do - local status - status=$(vastai show instances --raw 2>/dev/null | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -for inst in data: - if str(inst.get('id')) == '${instance_id}': - print(inst.get('actual_status', 'unknown')) - sys.exit(0) -print('not_found') -" 2>/dev/null || printf '%s' "unknown") - - if [[ "${status}" == "running" ]]; then - # Get SSH connection info - local ssh_url - ssh_url=$(vastai ssh-url "${instance_id}" 2>/dev/null) || { - log_warn "Instance running but SSH URL not yet available, retrying..." - sleep "${INSTANCE_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - continue - } - - # Parse SSH URL: ssh -p PORT root@HOST or ssh://root@HOST:PORT - VASTAI_SSH_HOST=$(printf '%s' "${ssh_url}" | grep -oP '@\K[^ :]+' 2>/dev/null || \ - printf '%s' "${ssh_url}" | sed -n 's/.*@\([^: ]*\).*/\1/p') - VASTAI_SSH_PORT=$(printf '%s' "${ssh_url}" | grep -oP '\-p\s*\K[0-9]+' 2>/dev/null || \ - printf '%s' "${ssh_url}" | grep -oP ':(\K[0-9]+)' 2>/dev/null || printf '%s' "22") - - if [[ -z "${VASTAI_SSH_HOST}" ]]; then - log_warn "Could not parse SSH URL: ${ssh_url}, retrying..." - sleep "${INSTANCE_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - continue - fi - - export VASTAI_SSH_HOST VASTAI_SSH_PORT - log_info "Instance ready: SSH at ${VASTAI_SSH_HOST}:${VASTAI_SSH_PORT}" - return 0 - fi - - log_warn "Instance status: ${status} (${attempt}/${max_attempts})" - sleep "${INSTANCE_STATUS_POLL_DELAY}" - attempt=$((attempt + 1)) - done - - log_error "Instance did not become ready after ${max_attempts} attempts" - return 1 -} - -# Build SSH options string for Vast.ai (uses non-standard port) -_vastai_ssh_opts() { - printf '%s' "${SSH_OPTS} -o ConnectTimeout=10 -p ${VASTAI_SSH_PORT}" -} - -verify_server_connectivity() { - local max_attempts=${1:-30} - local attempt=1 - local ssh_target="root@${VASTAI_SSH_HOST}" - - log_warn "Waiting for SSH connectivity to ${ssh_target}:${VASTAI_SSH_PORT}..." - while [[ "${attempt}" -le "${max_attempts}" ]]; do - # shellcheck disable=SC2086 - if ssh $(_vastai_ssh_opts) "${ssh_target}" "echo ok" >/dev/null 2>&1; then - log_info "SSH connection established" - return 0 - fi - log_warn "Waiting for SSH... (${attempt}/${max_attempts})" - sleep "${SSH_RETRY_DELAY}" - attempt=$((attempt + 1)) - done - log_error "Instance failed to respond via SSH after ${max_attempts} attempts" - return 1 -} - -# Install base tools (Vast.ai instances are Docker containers) -install_base_tools() { - local ssh_target="root@${VASTAI_SSH_HOST}" - - log_warn "Installing base tools..." - # shellcheck disable=SC2086 - ssh $(_vastai_ssh_opts) "${ssh_target}" "apt-get update -y && apt-get install -y curl unzip git zsh npm" >/dev/null 2>&1 || true - - # Install Bun - log_warn "Installing Bun..." - # shellcheck disable=SC2086 - ssh $(_vastai_ssh_opts) "${ssh_target}" "curl -fsSL https://bun.sh/install | bash" >/dev/null 2>&1 || true - - # Install Claude Code - log_warn "Installing Claude Code..." - # shellcheck disable=SC2086 - ssh $(_vastai_ssh_opts) "${ssh_target}" "curl -fsSL https://claude.ai/install.sh | bash" >/dev/null 2>&1 || true - - # Configure PATH in .bashrc and .zshrc - # shellcheck disable=SC2086 - ssh $(_vastai_ssh_opts) "${ssh_target}" "grep -q '.bun/bin' ~/.bashrc 2>/dev/null || printf '%s\n' 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.bashrc; grep -q '.bun/bin' ~/.zshrc 2>/dev/null || printf '%s\n' 'export PATH=\"\${HOME}/.claude/local/bin:\${HOME}/.bun/bin:\${PATH}\"' >> ~/.zshrc" >/dev/null 2>&1 || true - - log_info "Base tools installed" -} - -# Vast.ai uses root user -# These functions follow the IP-first arg pattern for compatibility with inject_env_vars_ssh -# The "ip" arg is the instance ID (used for consistency, not for SSH target) -# shellcheck disable=SC2086 -run_server() { - local _ip="${1}" - local cmd="${2}" - ssh $(_vastai_ssh_opts) "root@${VASTAI_SSH_HOST}" "${cmd}" -} - -# shellcheck disable=SC2086 -upload_file() { - local _ip="${1}" - local local_path="${2}" - local remote_path="${3}" - scp $(_vastai_ssh_opts) "${local_path}" "root@${VASTAI_SSH_HOST}:${remote_path}" -} - -# shellcheck disable=SC2086 -interactive_session() { - local _ip="${1}" - local cmd="${2}" - ssh -t $(_vastai_ssh_opts) "root@${VASTAI_SSH_HOST}" "${cmd}" -} - -destroy_server() { - local instance_id="${1}" - log_warn "Destroying instance ${instance_id}..." - vastai destroy instance "${instance_id}" >/dev/null 2>&1 - log_info "Instance ${instance_id} destroyed" -} - -list_servers() { - vastai show instances --raw 2>/dev/null | python3 -c " -import json, sys -data = json.loads(sys.stdin.read()) -if not data: - print('No instances found') - sys.exit(0) -fmt = '{:<25} {:<12} {:<15} {:<12} {:<30}' -print(fmt.format('LABEL', 'ID', 'STATUS', 'GPU', 'SSH')) -print('-' * 94) -for inst in data: - label = inst.get('label', 'N/A') or 'N/A' - iid = str(inst.get('id', 'N/A')) - status = inst.get('actual_status', 'N/A') - gpu = inst.get('gpu_name', 'N/A') - ssh_host = inst.get('ssh_host', '') - ssh_port = inst.get('ssh_port', '') - ssh_info = 'N/A' - if ssh_host and ssh_port: - ssh_info = '{}:{}'.format(ssh_host, ssh_port) - print(fmt.format(label[:25], iid[:12], status[:15], gpu[:12], ssh_info[:30])) -" || { - log_error "Failed to list instances" - return 1 - } -} diff --git a/vastai/nanoclaw.sh b/vastai/nanoclaw.sh deleted file mode 100644 index d3a4bbcb..00000000 --- a/vastai/nanoclaw.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "NanoClaw on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Node.js deps and clone nanoclaw -log_warn "Installing tsx..." -run_server "${VASTAI_INSTANCE_ID}" "source ~/.bashrc && bun install -g tsx" - -log_warn "Cloning and building nanoclaw..." -run_server "${VASTAI_INSTANCE_ID}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build" -log_info "NanoClaw installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 7. Create nanoclaw .env file -log_warn "Configuring nanoclaw..." - -DOTENV_TEMP=$(mktemp) -trap 'rm -f "${DOTENV_TEMP}"' EXIT -chmod 600 "${DOTENV_TEMP}" -cat > "${DOTENV_TEMP}" << EOF -ANTHROPIC_API_KEY=${OPENROUTER_API_KEY} -EOF - -upload_file "${VASTAI_INSTANCE_ID}" "${DOTENV_TEMP}" "/root/nanoclaw/.env" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 8. Start nanoclaw -log_warn "Starting nanoclaw..." -log_warn "You will need to scan a WhatsApp QR code to authenticate." -echo "" -interactive_session "${VASTAI_INSTANCE_ID}" "cd ~/nanoclaw && source ~/.zshrc && npm run dev" diff --git a/vastai/openclaw.sh b/vastai/openclaw.sh deleted file mode 100644 index 05e1255f..00000000 --- a/vastai/openclaw.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "OpenClaw on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install openclaw via bun -log_warn "Installing openclaw..." -run_server "${VASTAI_INSTANCE_ID}" "source ~/.bashrc && bun install -g openclaw" -log_info "OpenClaw installed" - -# 5. 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 - -# Get model preference -MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \ - "ANTHROPIC_BASE_URL=https://openrouter.ai/api" - -# 7. Configure openclaw -setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" \ - "upload_file ${VASTAI_INSTANCE_ID}" \ - "run_server ${VASTAI_INSTANCE_ID}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 8. Start openclaw gateway in background and launch TUI -log_warn "Starting openclaw..." -run_server "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &" -sleep 2 -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && openclaw tui" diff --git a/vastai/opencode.sh b/vastai/opencode.sh deleted file mode 100644 index f20ed444..00000000 --- a/vastai/opencode.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "OpenCode on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install OpenCode -log_warn "Installing OpenCode..." -run_server "${VASTAI_INSTANCE_ID}" "$(opencode_install_cmd)" -log_info "OpenCode installed" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start OpenCode interactively -log_warn "Starting OpenCode..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && opencode" diff --git a/vastai/plandex.sh b/vastai/plandex.sh deleted file mode 100644 index c912cd8e..00000000 --- a/vastai/plandex.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC2154 -set -eo pipefail - -# Source common functions - try local file first, fall back to remote -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" -# shellcheck source=vastai/lib/common.sh -if [[ -f "${SCRIPT_DIR}/lib/common.sh" ]]; then - source "${SCRIPT_DIR}/lib/common.sh" -else - eval "$(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/vastai/lib/common.sh)" -fi - -log_info "Plandex on Vast.ai" -echo "" - -# 1. Ensure vastai CLI and API key are configured -ensure_vastai_cli -ensure_vastai_token - -# 2. Get instance name and create instance -SERVER_NAME=$(get_server_name) -create_server "${SERVER_NAME}" - -# 3. Wait for SSH connectivity and install base tools -verify_server_connectivity -install_base_tools - -# 4. Install Plandex -log_warn "Installing Plandex..." -run_server "${VASTAI_INSTANCE_ID}" "curl -sL https://plandex.ai/install.sh | bash" - -# Verify installation succeeded -if ! run_server "${VASTAI_INSTANCE_ID}" "command -v plandex &> /dev/null && plandex version &> /dev/null"; then - log_error "Plandex installation verification failed" - exit 1 -fi -log_info "Plandex installation verified successfully" - -# 5. 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 - -# 6. Inject environment variables -log_warn "Setting up environment variables..." -inject_env_vars_ssh "${VASTAI_INSTANCE_ID}" upload_file run_server \ - "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" - -echo "" -log_info "Vast.ai instance setup completed successfully!" -log_info "Instance: ${SERVER_NAME} (ID: ${VASTAI_INSTANCE_ID})" -echo "" - -# 7. Start Plandex interactively -log_warn "Starting Plandex..." -sleep 1 -clear -interactive_session "${VASTAI_INSTANCE_ID}" "source ~/.zshrc && plandex"