diff --git a/hetzner/opencode.sh b/hetzner/opencode.sh new file mode 100755 index 00000000..3216bb7d --- /dev/null +++ b/hetzner/opencode.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -eo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" +# shellcheck source=hetzner/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/hetzner/lib/common.sh)" +fi + +log_info "OpenCode on Hetzner Cloud" +echo "" + +ensure_hcloud_token +ensure_ssh_key + +SERVER_NAME=$(get_server_name) +create_server "${SERVER_NAME}" +verify_server_connectivity "${HETZNER_SERVER_IP}" +wait_for_cloud_init "${HETZNER_SERVER_IP}" 60 + +log_warn "Installing OpenCode..." +run_server "${HETZNER_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 "${HETZNER_SERVER_IP}" upload_file run_server \ + "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" + +echo "" +log_info "Hetzner server setup completed successfully!" +log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})" +echo "" + +log_warn "Starting OpenCode..." +sleep 1 +clear +interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && opencode" diff --git a/manifest.json b/manifest.json index b177b04a..eafecd71 100644 --- a/manifest.json +++ b/manifest.json @@ -178,6 +178,17 @@ } }, "notes": "Natively supports OpenRouter via OPENROUTER_API_KEY and -m openrouter/... flag" + }, + "opencode": { + "name": "OpenCode", + "description": "AI coding agent built for the terminal with TUI", + "url": "https://github.com/opencode-ai/opencode", + "install": "curl -fsSL https://raw.githubusercontent.com/opencode-ai/opencode/refs/heads/main/install | bash", + "launch": "opencode", + "env": { + "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}" + }, + "notes": "Natively supports OpenRouter via OPENROUTER_API_KEY env var. Go-based TUI using Bubble Tea." } }, "clouds": { @@ -342,6 +353,38 @@ "image": "ubuntu:24.04" }, "notes": "Uses Machines API for provisioning and flyctl SSH for exec. Docker-based, pay-per-second pricing. Requires flyctl CLI." + }, + "civo": { + "name": "Civo", + "description": "Civo cloud-native instances via REST API", + "url": "https://www.civo.com/", + "type": "api", + "auth": "CIVO_API_TOKEN", + "provision_method": "POST /v2/instances with script", + "exec_method": "ssh root@IP", + "interactive_method": "ssh -t root@IP", + "defaults": { + "size": "g3.medium", + "region": "NYC1", + "image": "ubuntu-jammy" + }, + "notes": "Fast provisioning (~45s), free data transfer, hourly billing. NVMe storage." + }, + "scaleway": { + "name": "Scaleway", + "description": "Scaleway Cloud instances via REST API", + "url": "https://www.scaleway.com/", + "type": "api", + "auth": "SCW_SECRET_KEY", + "provision_method": "POST /instance/v1/zones/{zone}/servers", + "exec_method": "ssh root@IP", + "interactive_method": "ssh -t root@IP", + "defaults": { + "commercial_type": "DEV1-S", + "zone": "fr-par-1", + "image": "Ubuntu 24.04" + }, + "notes": "European cloud provider. Requires SCW_SECRET_KEY and optionally SCW_DEFAULT_PROJECT_ID." } }, "matrix": { @@ -465,6 +508,41 @@ "fly/gemini": "implemented", "fly/amazonq": "implemented", "fly/cline": "implemented", - "fly/gptme": "implemented" + "fly/gptme": "implemented", + "civo/claude": "implemented", + "civo/aider": "implemented", + "civo/codex": "implemented", + "civo/openclaw": "missing", + "civo/nanoclaw": "missing", + "civo/goose": "missing", + "civo/interpreter": "missing", + "civo/gemini": "missing", + "civo/amazonq": "missing", + "civo/cline": "missing", + "civo/gptme": "missing", + "sprite/opencode": "implemented", + "hetzner/opencode": "implemented", + "digitalocean/opencode": "missing", + "vultr/opencode": "missing", + "linode/opencode": "missing", + "lambda/opencode": "missing", + "aws-lightsail/opencode": "missing", + "gcp/opencode": "missing", + "e2b/opencode": "missing", + "modal/opencode": "missing", + "fly/opencode": "missing", + "civo/opencode": "missing", + "scaleway/claude": "implemented", + "scaleway/openclaw": "implemented", + "scaleway/nanoclaw": "implemented", + "scaleway/aider": "implemented", + "scaleway/goose": "implemented", + "scaleway/codex": "implemented", + "scaleway/interpreter": "implemented", + "scaleway/gemini": "implemented", + "scaleway/amazonq": "implemented", + "scaleway/cline": "implemented", + "scaleway/gptme": "implemented", + "scaleway/opencode": "implemented" } } diff --git a/sprite/opencode.sh b/sprite/opencode.sh new file mode 100755 index 00000000..cffdf289 --- /dev/null +++ b/sprite/opencode.sh @@ -0,0 +1,58 @@ +#!/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/sprite/lib/common.sh)" +fi + +log_info "OpenCode on Sprite" +echo "" + +# Setup sprite environment +ensure_sprite_installed +ensure_sprite_authenticated + +SPRITE_NAME=$(get_sprite_name) +ensure_sprite_exists "${SPRITE_NAME}" 5 +verify_sprite_connectivity "${SPRITE_NAME}" + +log_warn "Setting up sprite environment..." +setup_shell_environment "${SPRITE_NAME}" + +# Install OpenCode +log_warn "Installing OpenCode..." +run_sprite "${SPRITE_NAME}" "curl -fsSL https://raw.githubusercontent.com/opencode-ai/opencode/refs/heads/main/install | bash" + +# Verify installation succeeded +if ! run_sprite "${SPRITE_NAME}" "command -v opencode &> /dev/null"; then + log_error "OpenCode installation verification failed" + log_error "The 'opencode' command is not available" + exit 1 +fi +log_info "OpenCode 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_sprite "${SPRITE_NAME}" \ + "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" + +echo "" +log_info "Sprite setup completed successfully!" +echo "" + +# Start OpenCode interactively +log_warn "Starting OpenCode..." +sleep 1 +clear +sprite exec -s "${SPRITE_NAME}" -tty -- zsh -c "source ~/.zshrc && opencode"