mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-20 01:11:18 +00:00
feat: wire shared/github-auth.sh into all agent flows (#1216)
* feat: wire shared/github-auth.sh into all agent flows Add offer_github_auth() to shared/common.sh and call it from the inject_env_vars_* functions so all agent flows automatically offer GitHub CLI setup after env var injection — no per-script changes needed. Changes: - shared/common.sh: add offer_github_auth() function, call it from inject_env_vars_ssh() and inject_env_vars_local() - sprite/lib/common.sh: call offer_github_auth() from inject_env_vars_sprite() - OVH is covered automatically (inject_env_vars_ovh delegates to inject_env_vars_ssh) Behavior: - Prompts "Set up GitHub CLI (gh) on this machine? (y/N):" - Defaults to No (non-blocking for users who don't need it) - Skippable via SPAWN_SKIP_GITHUB_AUTH=1 env var for CI/automation - Uses safe_read for curl|bash compatibility - Downloads and runs shared/github-auth.sh on the remote VM Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: add shared agent setup helpers, deduplicate hetzner scripts (#1236) Add 5 composable helper functions to shared/common.sh (install_agent, verify_agent, get_or_prompt_api_key, inject_env_vars_cb, launch_session) that use the same callback pattern as offer_github_auth and setup_claude_code_config. Refactor all 15 hetzner agent scripts to use them, reducing total line count from 868 to 579 (-33%). Phase 1 of multi-phase rollout — remaining clouds to follow. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
86d77bc059
commit
fffb3591c4
18 changed files with 285 additions and 454 deletions
|
|
@ -203,10 +203,12 @@ describe("Agent Environment Variable Injection Contract", () => {
|
|||
// 2. OAuth flow: get_openrouter_api_key_oauth
|
||||
// 3. Manual prompt: get_openrouter_api_key_manual
|
||||
// 4. try_oauth_flow
|
||||
// 5. Shared helper: get_or_prompt_api_key (wraps env check + OAuth)
|
||||
const hasEnvCheck = code.includes("OPENROUTER_API_KEY:-") || code.includes("OPENROUTER_API_KEY:=");
|
||||
const hasOAuth = code.includes("get_openrouter_api_key_oauth") || code.includes("try_oauth_flow");
|
||||
const hasManual = code.includes("get_openrouter_api_key_manual");
|
||||
const hasAnyAcquisition = hasEnvCheck || hasOAuth || hasManual;
|
||||
const hasSharedHelper = code.includes("get_or_prompt_api_key");
|
||||
const hasAnyAcquisition = hasEnvCheck || hasOAuth || hasManual || hasSharedHelper;
|
||||
|
||||
if (!hasAnyAcquisition) {
|
||||
failures.push(key + ".sh");
|
||||
|
|
|
|||
|
|
@ -13,53 +13,24 @@ fi
|
|||
log_info "Aider on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "${SERVER_NAME}"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "${HETZNER_SERVER_IP}"
|
||||
wait_for_cloud_init "${HETZNER_SERVER_IP}" 60
|
||||
|
||||
# 5. Install Aider
|
||||
log_step "Installing Aider..."
|
||||
run_server "${HETZNER_SERVER_IP}" "pip install aider-chat 2>/dev/null || pip3 install aider-chat"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
# Verify installation succeeded
|
||||
if ! run_server "${HETZNER_SERVER_IP}" "command -v aider &> /dev/null && aider --version &> /dev/null"; then
|
||||
log_install_failed "Aider" "pip install aider-chat" "${HETZNER_SERVER_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
|
||||
# Install, configure, launch
|
||||
install_agent "Aider" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" "$RUN"
|
||||
verify_agent "Aider" "command -v aider && aider --version" "pip install aider-chat" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1
|
||||
|
||||
log_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"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 ""
|
||||
|
||||
# 9. Start Aider interactively
|
||||
log_step "Starting Aider..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
|
@ -14,37 +13,24 @@ fi
|
|||
log_info "Amazon Q on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Amazon Q CLI..."
|
||||
run_server "${HETZNER_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"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Amazon Q CLI" "curl -fsSL https://desktop-release.q.us-east-1.amazonaws.com/latest/amazon-q-cli-install.sh | bash" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_BASE_URL=https://openrouter.ai/api/v1"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
log_step "Starting Amazon Q..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && q chat"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && q chat"
|
||||
|
|
|
|||
|
|
@ -13,47 +13,32 @@ fi
|
|||
log_info "Claude Code on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "${SERVER_NAME}"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "${HETZNER_SERVER_IP}"
|
||||
wait_for_cloud_init "${HETZNER_SERVER_IP}" 60
|
||||
|
||||
# 5. Verify Claude Code is installed (try curl first, then bun fallback)
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
# Claude-specific install: try curl first, fall back to bun
|
||||
log_step "Verifying Claude Code installation..."
|
||||
if ! run_server "${HETZNER_SERVER_IP}" "export PATH=\$HOME/.claude/local/bin:\$HOME/.local/bin:\$PATH && command -v claude" >/dev/null 2>&1; then
|
||||
if ! ${RUN} "export PATH=\$HOME/.claude/local/bin:\$HOME/.local/bin:\$PATH && command -v claude" >/dev/null 2>&1; then
|
||||
log_step "Claude Code not found, installing..."
|
||||
if ! run_server "${HETZNER_SERVER_IP}" "curl -fsSL https://claude.ai/install.sh | bash"; then
|
||||
if ! ${RUN} "curl -fsSL https://claude.ai/install.sh | bash"; then
|
||||
log_warn "curl install failed, falling back to bun..."
|
||||
run_server "${HETZNER_SERVER_IP}" "export PATH=\$HOME/.bun/bin:\$HOME/.local/bin:\$PATH && bun add -g @anthropic-ai/claude-code && claude install"
|
||||
${RUN} "export PATH=\$HOME/.bun/bin:\$HOME/.local/bin:\$PATH && bun add -g @anthropic-ai/claude-code && claude install"
|
||||
fi
|
||||
fi
|
||||
verify_agent "Claude Code" "export PATH=\$HOME/.claude/local/bin:\$HOME/.local/bin:\$PATH && command -v claude && claude --version" "curl -fsSL https://claude.ai/install.sh | bash" "$RUN"
|
||||
|
||||
# Verify installation succeeded
|
||||
if ! run_server "${HETZNER_SERVER_IP}" "export PATH=\$HOME/.claude/local/bin:\$HOME/.local/bin:\$PATH && command -v claude &> /dev/null && claude --version &> /dev/null"; then
|
||||
log_install_failed "Claude Code" "curl -fsSL https://claude.ai/install.sh | bash" "${HETZNER_SERVER_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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"ANTHROPIC_BASE_URL=https://openrouter.ai/api" \
|
||||
"ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \
|
||||
|
|
@ -61,18 +46,7 @@ inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
|||
"CLAUDE_CODE_SKIP_ONBOARDING=1" \
|
||||
"CLAUDE_CODE_ENABLE_TELEMETRY=0"
|
||||
|
||||
# 8. Configure Claude Code settings
|
||||
setup_claude_code_config "${OPENROUTER_API_KEY}" \
|
||||
"upload_file ${HETZNER_SERVER_IP}" \
|
||||
"run_server ${HETZNER_SERVER_IP}"
|
||||
# Claude-specific config
|
||||
setup_claude_code_config "${OPENROUTER_API_KEY}" "$UPLOAD" "$RUN"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
# 9. Start Claude Code interactively
|
||||
log_step "Starting Claude Code..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "export PATH=\$HOME/.local/bin:\$HOME/.bun/bin:\$PATH && source ~/.zshrc && claude"
|
||||
launch_session "Hetzner server" "$SESSION" "export PATH=\$HOME/.local/bin:\$HOME/.bun/bin:\$PATH && source ~/.zshrc && claude"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
|
@ -14,38 +13,24 @@ fi
|
|||
log_info "Cline on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Cline..."
|
||||
run_server "${HETZNER_SERVER_IP}" "npm install -g cline"
|
||||
log_info "Cline installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Cline" "npm install -g cline" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_BASE_URL=https://openrouter.ai/api/v1"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
log_step "Starting Cline..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && cline"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && cline"
|
||||
|
|
|
|||
|
|
@ -12,37 +12,24 @@ fi
|
|||
log_info "Codex CLI on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Codex CLI..."
|
||||
run_server "${HETZNER_SERVER_IP}" "npm install -g @openai/codex"
|
||||
log_info "Codex CLI installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Codex CLI" "npm install -g @openai/codex" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_BASE_URL=https://openrouter.ai/api/v1"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
log_step "Starting Codex..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && codex"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && codex"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
|
@ -14,40 +13,23 @@ fi
|
|||
log_info "Continue on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Continue CLI..."
|
||||
run_server "${HETZNER_SERVER_IP}" "npm install -g @continuedev/cli"
|
||||
log_info "Continue installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Continue CLI" "npm install -g @continuedev/cli" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}"
|
||||
|
||||
setup_continue_config "${OPENROUTER_API_KEY}" \
|
||||
"upload_file ${HETZNER_SERVER_IP}" \
|
||||
"run_server ${HETZNER_SERVER_IP}"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
log_step "Starting Continue CLI in TUI mode..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && cn"
|
||||
setup_continue_config "${OPENROUTER_API_KEY}" "$UPLOAD" "$RUN"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && cn"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
|
@ -14,39 +13,25 @@ fi
|
|||
log_info "Gemini CLI on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Gemini CLI..."
|
||||
run_server "${HETZNER_SERVER_IP}" "npm install -g @google/gemini-cli"
|
||||
log_info "Gemini CLI installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Gemini CLI" "npm install -g @google/gemini-cli" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"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 "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
log_step "Starting Gemini..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && gemini"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && gemini"
|
||||
|
|
|
|||
|
|
@ -13,51 +13,24 @@ fi
|
|||
log_info "Goose on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "${SERVER_NAME}"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "${HETZNER_SERVER_IP}"
|
||||
wait_for_cloud_init "${HETZNER_SERVER_IP}" 60
|
||||
|
||||
# 5. Install Goose
|
||||
log_step "Installing Goose..."
|
||||
run_server "${HETZNER_SERVER_IP}" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
# Verify installation succeeded
|
||||
if ! run_server "${HETZNER_SERVER_IP}" "command -v goose &> /dev/null && goose --version &> /dev/null"; then
|
||||
log_install_failed "Goose" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" "${HETZNER_SERVER_IP}"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Goose 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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Goose" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" "$RUN"
|
||||
verify_agent "Goose" "command -v goose && goose --version" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"GOOSE_PROVIDER=openrouter" \
|
||||
"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 ""
|
||||
|
||||
# 8. Start Goose interactively
|
||||
log_step "Starting Goose..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && goose"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && goose"
|
||||
|
|
|
|||
|
|
@ -12,53 +12,24 @@ fi
|
|||
log_info "gptme on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "$SERVER_NAME"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "$HETZNER_SERVER_IP"
|
||||
wait_for_cloud_init "$HETZNER_SERVER_IP"
|
||||
|
||||
# 5. Install gptme
|
||||
log_step "Installing gptme..."
|
||||
run_server "$HETZNER_SERVER_IP" "pip install gptme 2>/dev/null || pip3 install gptme"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
# Verify installation succeeded
|
||||
if ! run_server "$HETZNER_SERVER_IP" "command -v gptme &> /dev/null && gptme --version &> /dev/null"; then
|
||||
log_install_failed "gptme" "pip install gptme" "${HETZNER_SERVER_IP}"
|
||||
exit 1
|
||||
fi
|
||||
log_info "gptme 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
|
||||
# Install, configure, launch
|
||||
install_agent "gptme" "pip install gptme 2>/dev/null || pip3 install gptme" "$RUN"
|
||||
verify_agent "gptme" "command -v gptme && gptme --version" "pip install gptme" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1
|
||||
|
||||
log_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "$HETZNER_SERVER_IP" upload_file run_server \
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"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 ""
|
||||
|
||||
# 9. Start gptme interactively
|
||||
log_step "Starting gptme..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "$HETZNER_SERVER_IP" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && gptme -m openrouter/${MODEL_ID}"
|
||||
|
|
|
|||
|
|
@ -12,37 +12,24 @@ fi
|
|||
log_info "Open Interpreter on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Open Interpreter..."
|
||||
run_server "${HETZNER_SERVER_IP}" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter"
|
||||
log_info "Open Interpreter installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Open Interpreter" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"OPENAI_BASE_URL=https://openrouter.ai/api/v1"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
log_step "Starting Open Interpreter..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && interpreter"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && interpreter"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
|
@ -14,38 +13,24 @@ fi
|
|||
log_info "Kilo Code on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing Kilo Code..."
|
||||
run_server "${HETZNER_SERVER_IP}" "npm install -g @kilocode/cli"
|
||||
log_info "Kilo Code installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Kilo Code" "npm install -g @kilocode/cli" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"KILO_PROVIDER_TYPE=openrouter" \
|
||||
"KILO_OPEN_ROUTER_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_step "Starting Kilo Code..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && kilocode"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && kilocode"
|
||||
|
|
|
|||
|
|
@ -13,58 +13,43 @@ fi
|
|||
log_info "NanoClaw on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "${SERVER_NAME}"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "${HETZNER_SERVER_IP}"
|
||||
wait_for_cloud_init "${HETZNER_SERVER_IP}" 60
|
||||
|
||||
# 5. Install Node.js deps and clone nanoclaw
|
||||
log_step "Installing tsx..."
|
||||
run_server "${HETZNER_SERVER_IP}" "source ~/.bashrc && bun install -g tsx"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
|
||||
# NanoClaw multi-step install
|
||||
log_step "Installing tsx..."
|
||||
${RUN} "source ~/.bashrc && bun install -g tsx"
|
||||
log_step "Cloning and building nanoclaw..."
|
||||
run_server "${HETZNER_SERVER_IP}" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build"
|
||||
${RUN} "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
|
||||
|
||||
log_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"ANTHROPIC_BASE_URL=https://openrouter.ai/api"
|
||||
|
||||
# 8. Create nanoclaw .env file
|
||||
# NanoClaw-specific .env file
|
||||
log_step "Configuring nanoclaw..."
|
||||
|
||||
DOTENV_TEMP=$(mktemp)
|
||||
trap 'rm -f "${DOTENV_TEMP}"' EXIT
|
||||
chmod 600 "${DOTENV_TEMP}"
|
||||
printf 'ANTHROPIC_API_KEY=%s\n' "${OPENROUTER_API_KEY}" > "${DOTENV_TEMP}"
|
||||
|
||||
upload_file "${HETZNER_SERVER_IP}" "${DOTENV_TEMP}" "/root/nanoclaw/.env"
|
||||
${UPLOAD} "${DOTENV_TEMP}" "/root/nanoclaw/.env"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
# 9. Start nanoclaw
|
||||
log_step "Starting nanoclaw..."
|
||||
log_info "You will need to scan a WhatsApp QR code to authenticate."
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -13,54 +13,34 @@ fi
|
|||
log_info "OpenClaw on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "${SERVER_NAME}"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "${HETZNER_SERVER_IP}"
|
||||
wait_for_cloud_init "${HETZNER_SERVER_IP}" 60
|
||||
|
||||
# 5. Install openclaw via bun
|
||||
log_step "Installing openclaw..."
|
||||
run_server "${HETZNER_SERVER_IP}" "source ~/.bashrc && bun install -g openclaw"
|
||||
log_info "OpenClaw installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
|
||||
# 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
|
||||
# Install, configure
|
||||
install_agent "openclaw" "source ~/.bashrc && bun install -g openclaw" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Openclaw") || exit 1
|
||||
|
||||
log_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"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 ${HETZNER_SERVER_IP}" \
|
||||
"run_server ${HETZNER_SERVER_IP}"
|
||||
setup_openclaw_config "${OPENROUTER_API_KEY}" "${MODEL_ID}" "$UPLOAD" "$RUN"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: ${SERVER_NAME} (ID: ${HETZNER_SERVER_ID}, IP: ${HETZNER_SERVER_IP})"
|
||||
echo ""
|
||||
|
||||
# 10. Start openclaw gateway in background and launch TUI
|
||||
# Start openclaw gateway in background, then launch TUI
|
||||
log_step "Starting openclaw..."
|
||||
run_server "${HETZNER_SERVER_IP}" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &"
|
||||
${RUN} "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &"
|
||||
sleep 2
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && openclaw tui"
|
||||
|
|
|
|||
|
|
@ -12,35 +12,22 @@ fi
|
|||
log_info "OpenCode on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# Provision server
|
||||
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_step "Installing OpenCode..."
|
||||
run_server "${HETZNER_SERVER_IP}" "$(opencode_install_cmd)"
|
||||
log_info "OpenCode installed"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "OpenCode" "$(opencode_install_cmd)" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"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_step "Starting OpenCode..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && opencode"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && opencode"
|
||||
|
|
|
|||
|
|
@ -13,50 +13,23 @@ fi
|
|||
log_info "Plandex on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
# Provision server
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "${SERVER_NAME}"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "${HETZNER_SERVER_IP}"
|
||||
wait_for_cloud_init "${HETZNER_SERVER_IP}" 60
|
||||
|
||||
# 5. Install Plandex
|
||||
log_step "Installing Plandex..."
|
||||
run_server "${HETZNER_SERVER_IP}" "curl -sL https://plandex.ai/install.sh | bash"
|
||||
# Set up callbacks
|
||||
RUN="run_server ${HETZNER_SERVER_IP}"
|
||||
UPLOAD="upload_file ${HETZNER_SERVER_IP}"
|
||||
SESSION="interactive_session ${HETZNER_SERVER_IP}"
|
||||
|
||||
# Verify installation succeeded
|
||||
if ! run_server "${HETZNER_SERVER_IP}" "command -v plandex &> /dev/null && plandex version &> /dev/null"; then
|
||||
log_install_failed "Plandex" "curl -sL https://plandex.ai/install.sh | bash" "${HETZNER_SERVER_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_step "Setting up environment variables..."
|
||||
inject_env_vars_ssh "${HETZNER_SERVER_IP}" upload_file run_server \
|
||||
# Install, configure, launch
|
||||
install_agent "Plandex" "curl -sL https://plandex.ai/install.sh | bash" "$RUN"
|
||||
verify_agent "Plandex" "command -v plandex && plandex version" "curl -sL https://plandex.ai/install.sh | bash" "$RUN"
|
||||
get_or_prompt_api_key
|
||||
inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
"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 ""
|
||||
|
||||
# 7. Start Plandex interactively
|
||||
log_step "Starting Plandex..."
|
||||
sleep 1
|
||||
clear
|
||||
interactive_session "${HETZNER_SERVER_IP}" "source ~/.zshrc && plandex"
|
||||
launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && plandex"
|
||||
|
|
|
|||
115
shared/common.sh
115
shared/common.sh
|
|
@ -1095,6 +1095,9 @@ inject_env_vars_ssh() {
|
|||
"${run_func}" "${server_ip}" "cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Note: temp file will be cleaned up by trap handler
|
||||
|
||||
# Offer optional GitHub CLI setup
|
||||
offer_github_auth "${run_func} ${server_ip}"
|
||||
}
|
||||
|
||||
# Inject environment variables for providers without SSH (modal, e2b, sprite)
|
||||
|
|
@ -1120,6 +1123,32 @@ inject_env_vars_local() {
|
|||
"${run_func}" "cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Note: temp file will be cleaned up by trap handler
|
||||
|
||||
# Offer optional GitHub CLI setup
|
||||
offer_github_auth "${run_func}"
|
||||
}
|
||||
|
||||
# Offer optional GitHub CLI setup on remote VM
|
||||
# Usage (SSH clouds): offer_github_auth "run_server SERVER_IP"
|
||||
# Usage (local): offer_github_auth "run_server"
|
||||
# Skipped if SPAWN_SKIP_GITHUB_AUTH=1 or non-interactive
|
||||
offer_github_auth() {
|
||||
local run_callback="${1}"
|
||||
|
||||
# Skip in non-interactive or if user opted out
|
||||
if [[ -n "${SPAWN_SKIP_GITHUB_AUTH:-}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '\n'
|
||||
local choice
|
||||
choice=$(safe_read "Set up GitHub CLI (gh) on this machine? (y/N): ") || return 0
|
||||
if [[ ! "${choice}" =~ ^[Yy]$ ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_step "Installing and authenticating GitHub CLI..."
|
||||
${run_callback} "curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/shared/github-auth.sh | bash"
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
|
|
@ -1157,6 +1186,92 @@ register_cleanup_trap() {
|
|||
trap cleanup_temp_files EXIT INT TERM
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Agent setup helpers (composable, callback-based)
|
||||
# ============================================================
|
||||
# These helpers accept pre-applied RUN/UPLOAD/SESSION callbacks,
|
||||
# following the same callback pattern used by offer_github_auth
|
||||
# and setup_claude_code_config.
|
||||
#
|
||||
# Usage pattern in agent scripts:
|
||||
# RUN="run_server ${SERVER_IP}"
|
||||
# UPLOAD="upload_file ${SERVER_IP}"
|
||||
# SESSION="interactive_session ${SERVER_IP}"
|
||||
#
|
||||
# install_agent "Aider" "pip install aider-chat" "$RUN"
|
||||
# verify_agent "Aider" "command -v aider && aider --version" "pip install aider-chat" "$RUN"
|
||||
# get_or_prompt_api_key
|
||||
# inject_env_vars_cb "$RUN" "$UPLOAD" "OPENROUTER_API_KEY=${OPENROUTER_API_KEY}"
|
||||
# launch_session "Hetzner server" "$SESSION" "source ~/.zshrc && aider"
|
||||
|
||||
# Run an agent's install command on the target machine
|
||||
# Usage: install_agent AGENT_NAME INSTALL_CMD RUN_CB
|
||||
install_agent() {
|
||||
local agent_name="$1" install_cmd="$2" run_cb="$3"
|
||||
log_step "Installing ${agent_name}..."
|
||||
${run_cb} "${install_cmd}"
|
||||
}
|
||||
|
||||
# Verify an agent installed correctly; exit 1 on failure
|
||||
# Usage: verify_agent AGENT_NAME VERIFY_CMD INSTALL_CMD RUN_CB
|
||||
verify_agent() {
|
||||
local agent_name="$1" verify_cmd="$2" install_cmd="$3" run_cb="$4"
|
||||
if ! ${run_cb} "${verify_cmd}" >/dev/null 2>&1; then
|
||||
log_install_failed "${agent_name}" "${install_cmd}"
|
||||
exit 1
|
||||
fi
|
||||
log_info "${agent_name} installation verified successfully"
|
||||
}
|
||||
|
||||
# Get OpenRouter API key from environment or prompt via OAuth
|
||||
# Sets the global OPENROUTER_API_KEY variable
|
||||
get_or_prompt_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
|
||||
}
|
||||
|
||||
# Inject environment variables using pre-applied callbacks
|
||||
# Usage: inject_env_vars_cb RUN_CB UPLOAD_CB KEY1=val1 KEY2=val2 ...
|
||||
# Example: inject_env_vars_cb "$RUN" "$UPLOAD" \
|
||||
# "OPENROUTER_API_KEY=$OPENROUTER_API_KEY" \
|
||||
# "ANTHROPIC_BASE_URL=https://openrouter.ai/api"
|
||||
inject_env_vars_cb() {
|
||||
local run_cb="$1" upload_cb="$2"
|
||||
shift 2
|
||||
|
||||
log_step "Setting up environment variables..."
|
||||
|
||||
local env_temp
|
||||
env_temp=$(mktemp)
|
||||
chmod 600 "${env_temp}"
|
||||
track_temp_file "${env_temp}"
|
||||
|
||||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
${upload_cb} "${env_temp}" "/tmp/env_config"
|
||||
${run_cb} "cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
|
||||
# Offer optional GitHub CLI setup
|
||||
offer_github_auth "${run_cb}"
|
||||
}
|
||||
|
||||
# Print success message and launch an interactive agent session
|
||||
# Usage: launch_session CLOUD_MSG SESSION_CB LAUNCH_CMD
|
||||
launch_session() {
|
||||
local cloud_msg="$1" session_cb="$2" launch_cmd="$3"
|
||||
echo ""
|
||||
log_info "${cloud_msg} setup completed successfully!"
|
||||
echo ""
|
||||
log_step "Starting agent..."
|
||||
sleep 1
|
||||
clear 2>/dev/null || true
|
||||
${session_cb} "${launch_cmd}"
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# SSH configuration
|
||||
# ============================================================
|
||||
|
|
|
|||
|
|
@ -212,6 +212,9 @@ inject_env_vars_sprite() {
|
|||
# Upload and append to both .bashrc and .zshrc using sprite exec with -file flag
|
||||
sprite exec -s "${sprite_name}" -file "${env_temp}:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.bashrc && cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
trap - EXIT
|
||||
|
||||
# Offer optional GitHub CLI setup
|
||||
offer_github_auth "run_sprite ${sprite_name}"
|
||||
}
|
||||
|
||||
# Upload file to sprite (for use with setup_claude_code_config callback)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue