From 3d5812602c8a3237da1490aed4162643118bf603 Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Sun, 1 Mar 2026 20:27:59 -0800 Subject: [PATCH] refactor: convert hermes scripts to thin-wrapper pattern (#2094) - hetzner/hermes.sh: add thin-shim header comment, blank line after _ensure_bun definition, and section comments (Local checkout, Remote) to match the canonical pattern used by aws/gcp/sprite/daytona - digitalocean/hermes.sh: add detailed _run_with_restart comment block and inline section comments (Normal exit, SIGTERM, Other failure) to match digitalocean/claude.sh Both scripts now produce identical output to their cloud's reference script (e.g. aws/hermes.sh, digitalocean/claude.sh) when the agent name is substituted. Fixes #2082 Agent: code-health Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 --- sh/digitalocean/hermes.sh | 8 ++++++++ sh/hetzner/hermes.sh | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/sh/digitalocean/hermes.sh b/sh/digitalocean/hermes.sh index 7f300269..2478c8af 100755 --- a/sh/digitalocean/hermes.sh +++ b/sh/digitalocean/hermes.sh @@ -15,6 +15,11 @@ _ensure_bun() { command -v bun &>/dev/null || { printf '\033[0;31mbun not found after install\033[0m\n' >&2; exit 1; } } +# Run command in the foreground so bun gets full terminal access (raw mode, +# arrow keys for interactive prompts). The old pattern backgrounded the child +# with & + wait so a SIGTERM trap could forward the signal, but that removed +# bun from the foreground process group and broke @clack/prompts multiselect. +# Now SIGTERM is detected from exit code 143 (128 + 15) after the child exits. _run_with_restart() { local attempt=0 local backoff=2 @@ -24,10 +29,12 @@ _run_with_restart() { "$@" local exit_code=$? + # Normal exit if [ "$exit_code" -eq 0 ]; then return 0 fi + # SIGTERM (143) or SIGKILL (137) — attempt restart if [ "$exit_code" -eq 143 ] || [ "$exit_code" -eq 137 ]; then printf '\033[0;33m[spawn/%s] Agent process terminated (exit %s). The droplet is likely still running.\033[0m\n' \ "$_AGENT_NAME" "$exit_code" >&2 @@ -46,6 +53,7 @@ _run_with_restart() { fi fi + # Other failure — exit with the original code return "$exit_code" done } diff --git a/sh/hetzner/hermes.sh b/sh/hetzner/hermes.sh index 2aa12782..914d8851 100755 --- a/sh/hetzner/hermes.sh +++ b/sh/hetzner/hermes.sh @@ -1,6 +1,8 @@ #!/bin/bash set -eo pipefail +# Thin shim: ensures bun is available, runs bundled hetzner.js (local or from GitHub release) + _ensure_bun() { if command -v bun &>/dev/null; then return 0; fi printf '\033[0;36mInstalling bun...\033[0m\n' >&2 @@ -8,6 +10,7 @@ _ensure_bun() { export PATH="$HOME/.bun/bin:$PATH" command -v bun &>/dev/null || { printf '\033[0;31mbun not found after install\033[0m\n' >&2; exit 1; } } + _ensure_bun SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" @@ -17,10 +20,12 @@ if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/mai exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" hermes "$@" fi +# Local checkout — run from source if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" hermes "$@" fi +# Remote — download and run compiled TypeScript bundle HETZNER_JS=$(mktemp) trap 'rm -f "$HETZNER_JS"' EXIT curl -fsSL "https://github.com/OpenRouterTeam/spawn/releases/download/hetzner-latest/hetzner.js" -o "$HETZNER_JS"