Commit graph

21 commits

Author SHA1 Message Date
Sprite
3a0ecd80e9 refactor: Extract ENV_TEMP pattern to inject_env_vars_local (Modal)
Created inject_env_vars_local() function in shared/common.sh to eliminate
duplicate temporary file creation pattern. Converted 10 Modal scripts:
- aider, claude, amazonq, cline, codex
- gemini, goose, interpreter, nanoclaw, openclaw

Reduces ~10-15 lines per script to 3-4 lines.

Pattern before:
  ENV_TEMP=$(mktemp)
  trap 'rm -f "${ENV_TEMP}"' EXIT
  cat > "${ENV_TEMP}" << EOF
  # [spawn:env]
  export KEY=value
  EOF
  upload_file "${ENV_TEMP}" "/tmp/env_config"
  run_server "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"

Pattern after:
  inject_env_vars_local upload_file run_server \
      "KEY=value"

Special case: nanoclaw.sh has additional DOTENV_TEMP for agent-specific
.env file, which remains unchanged.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 04:04:01 +00:00
Sprite
e0c6344049 refactor: Add trap-based cleanup for temp files in library code
Added EXIT traps to ensure temporary files are cleaned up even if scripts crash or are interrupted:

**cli/spawn.sh** (2 mktemp calls):
- Line 219: Added trap after mktemp in fetch_manifest(), clear trap after mv
- Line 537: Added trap after mktemp in cmd_update(), clear trap after mv
- Removed manual rm -f calls in error paths (trap handles cleanup)

**sprite/lib/common.sh** (3 mktemp calls):
- setup_shell_environment(): Consolidated trap for both path_temp and bash_temp
- inject_env_vars_sprite(): Added trap for env_temp, clear after successful upload

**shared/common.sh** (cleanup system):
- Auto-register cleanup trap at end of file when sourced
- This activates the existing track_temp_file() + cleanup_temp_files() system
- Previously register_cleanup_trap() had to be manually called (only 1 script did this)

Impact: Prevents /tmp file leaks when scripts are killed, crashed, or interrupted mid-execution.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 03:31:47 +00:00
Sprite
36b3d82d2e refactor: add OAuth timeout and remove unused color variables
- Add --max-time 30 to OAuth key exchange curl to prevent indefinite hangs
- Remove unused DIM variable from cli/install.sh
- Remove unused BLUE variable from cli/spawn.sh

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 03:01:55 +00:00
Sprite
3e7f723667 refactor: fix read flags, unused variable, and return quoting
- Add -r flag to safe_read() to prevent backslash mangling (SC2162)
- Add shellcheck disable for intentional SSH_OPTS word splitting
- Remove unused 'gaps' variable in improve.sh (SC2034)
- Quote exit_code in return statement for consistency (SC2248)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 02:55:23 +00:00
Sprite
d3d2e23e0b refactor: add port range fallback to OAuth flow
Modified OAuth server to try ports sequentially (PORT to PORT+10) if initial
port is busy. Server now writes actual port used to a port file, which
try_oauth_flow reads to construct the correct callback URL.

Changes:
- start_oauth_server: Added port range retry logic with EADDRINUSE handling
- start_oauth_server: Now accepts port_file parameter to communicate actual port
- try_oauth_flow: Waits for port allocation and reads actual port used
- try_oauth_flow: Logs allocated port for user visibility
- Backward compatible: PORT env var still respected as starting point

Pattern:
Before: Fixed port 5180 → fails if busy
After: Try 5180, 5181, 5182... → resilient to port conflicts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 02:42:24 +00:00
Sprite
f9da80ecae refactor: extract OAuth polling sleep to configurable constant
Extract hardcoded `sleep 1` values in OAuth code polling and server
startup wait to environment-configurable POLL_INTERVAL constant.

Changes:
- Added POLL_INTERVAL="${SPAWN_POLL_INTERVAL:-1}" at top of shared/common.sh
- Updated wait_for_oauth_code() to use POLL_INTERVAL (line 388)
- Updated OAuth server startup wait to use POLL_INTERVAL (line 489)

Benefits:
- Faster testing with SPAWN_POLL_INTERVAL=0.1
- Configurable for slow networks with SPAWN_POLL_INTERVAL=2
- Consistent with other timeout/delay constants added in previous commit

File modified:
- shared/common.sh

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 02:38:46 +00:00
Sprite
cabdbc37ba refactor: add pipefail to error handling flags
Changed 65 agent scripts from `set -e` to `set -eo pipefail` to ensure
errors in piped commands are properly caught. This prevents silent
failures when commands like `curl | bash` fail in the middle.

Files updated across all cloud providers:
- aws-lightsail: 10 scripts
- digitalocean: 3 scripts
- e2b: 10 scripts
- gcp: 10 scripts
- hetzner: 3 scripts
- lambda: 10 scripts
- linode: 3 scripts
- modal: 10 scripts
- sprite: 3 scripts
- vultr: 3 scripts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 02:34:45 +00:00
Sprite
0cab5827de refactor: consolidate OpenClaw config setup to shared helper
- Add setup_openclaw_config() to shared/common.sh
- Replace ~350 lines of duplicate config code across 10 files
- Uses callback pattern for provider-specific upload/run operations

Score: 14 (Impact: 7, Confidence: 8, Risk: 4)
2026-02-08 02:25:17 +00:00
Sprite
f9dd9a7bf5 refactor: consolidate Claude Code config setup to shared helper
- Add setup_claude_code_config() to shared/common.sh
- Replace ~400 lines of duplicate config code across 10 files
- Uses callback pattern for provider-specific upload/run operations
- Net reduction: 325 lines (81.2% reduction)

Score: 16 (Impact: 8, Confidence: 8, Risk: 4)
2026-02-08 02:22:06 +00:00
Sprite
8aeef42471 refactor: fix SC2088 tilde expansion in GCP scripts
- Replace "~/" with "$HOME/" for proper expansion
- Fix 4 SC2088 warnings in nanoclaw.sh, claude.sh, openclaw.sh
- Ensures paths resolve correctly in upload_file calls

Score: 15 (Impact: 5, Confidence: 9, Risk: 3)
2026-02-08 02:09:45 +00:00
Sprite
3b6c761904 refactor: add username parameter to generic_ssh_wait
- Add required username parameter to generic_ssh_wait()
- Update SSH command to use dynamic username instead of hardcoded "root"
- Update all existing callers to pass username explicitly
- Enables GCP and AWS Lightsail to adopt generic_ssh_wait in future

Score: 40 (Impact: 8, Confidence: 10, Risk: 2)
2026-02-08 01:58:48 +00:00
Sprite
2b91efc1db refactor: add braces to variable references in shared/common.sh
Fixed all SC2250 shellcheck warnings by adding braces to variable
references throughout the file. This improves code consistency and
follows shellcheck best practices.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 01:43:37 +00:00
Sprite
f2afdea792 refactor: extract ensure_ssh_key duplication to shared library (~220 lines)
Eliminates duplicate SSH key registration logic across 5 cloud providers
(Hetzner, DigitalOcean, Vultr, Linode, Lambda) by introducing a generic
callback-based pattern in shared/common.sh.

Before: Each provider had ~45 lines of nearly identical code for:
- Generating SSH keys if missing
- Getting fingerprints
- Checking if key exists with provider
- Registering key if not exists
- Error handling

After: Providers implement 2 simple callbacks:
- check_callback: provider-specific API call to check if key exists
- register_callback: provider-specific API call to register key

The shared function handles:
- Key generation (via generate_ssh_key_if_missing)
- Fingerprint extraction (via get_ssh_fingerprint)
- Flow control and logging
- Callback orchestration

Changes:
- shared/common.sh: Added ensure_ssh_key_with_provider() function
- hetzner/lib/common.sh: Refactored to use callbacks
- digitalocean/lib/common.sh: Refactored to use callbacks
- vultr/lib/common.sh: Refactored to use callbacks
- linode/lib/common.sh: Refactored to use callbacks
- lambda/lib/common.sh: Refactored to use callbacks

Benefits:
- DRY: Eliminates ~220 lines of duplicate code
- Maintainability: Bug fixes in registration flow benefit all providers
- Consistency: All providers use identical registration logic
- Extensibility: New providers can reuse this pattern

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 01:33:06 +00:00
Sprite
8febdaf7f5 Fix: remove stale write_oauth_response_file call from try_oauth_flow
The Node.js OAuth server handles its own HTTP response — the old
write_oauth_response_file and 3-arg start_oauth_server are gone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-08 01:24:40 +00:00
Sprite
0ad6680f1f refactor: extract duplicate get_server_name logic to shared function
- Add get_resource_name() to shared/common.sh
  - Generic function for env-var-or-prompt pattern
  - Uses indirect expansion ${!var} for dynamic env vars
  - Preserves exact behavior: env check → prompt → error

- Update 9 cloud providers to use shared function:
  - aws-lightsail: LIGHTSAIL_SERVER_NAME
  - digitalocean: DO_DROPLET_NAME (with validation)
  - gcp: GCP_INSTANCE_NAME
  - hetzner: HETZNER_SERVER_NAME (with validation)
  - linode: LINODE_SERVER_NAME (with validation)
  - sprite: SPRITE_NAME (with validation)
  - vultr: VULTR_SERVER_NAME (with validation)
  - e2b: E2B_SANDBOX_NAME
  - modal: MODAL_SANDBOX_NAME

- Reduces code duplication: ~120 lines → ~25 lines
- Maintains backward compatibility (env vars, prompts, errors unchanged)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 01:16:20 +00:00
Sprite
1320b3c7d2 refactor: fix SC2155 shellcheck warnings in shared/common.sh
Split all 16 instances of combined local declaration+assignment to
avoid masking return values. This is a mechanical refactor with no
logic changes.

Fixed lines: 219, 279, 283, 357, 363, 381, 385, 396, 408, 450, 618,
622, 623, 639, 664, 759

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 01:16:20 +00:00
L
99c89eadd9
Replace nc-based OAuth server with Node.js HTTP server (#31)
The nc (netcat) approach was fundamentally broken:
- macOS BSD nc has different flags than GNU nc
- nc handles exactly one connection — browsers send favicon, prefetch, etc.
- Pipe-based I/O has race conditions and blocks $() capture
- echo -e doesn't work on macOS bash 3.x for HTTP headers

Replace with Node.js http.createServer (via bun or node):
- Proper HTTP server handles multiple connections
- Parses URL query params correctly (no sed/grep on raw HTTP)
- Sends proper HTTP response with correct headers
- Gracefully ignores favicon/prefetch/extra requests
- Shuts itself down after receiving the callback code
- Works identically on macOS, Linux, and Termux

bun is already a dependency (installed by cloud-init), node is
available on most systems. Falls back to manual API key entry
if neither is available.

Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-07 17:09:52 -08:00
L
d053865c29
Fix OAuth server blocking: redirect subshell stdout (#30)
start_oauth_server was called inside $() to capture the PID, but the
backgrounded nc subshell inherited the $() stdout pipe. Since $()
waits for ALL writers to close, it blocked forever until nc exited
(which never happens — it's listening).

Fix: redirect the subshell's stdout/stderr to /dev/null so it doesn't
hold the pipe open. The PID echo still works because it runs in the
parent (after the & backgrounds the child).

Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-07 17:00:50 -08:00
L
26b70cc792
Fix OAuth server in shared/common.sh for macOS bash 3.x (#29)
The autonomous refactoring reverted all our macOS fixes in shared/common.sh:

1. nc_listen: removed spurious -p flag check that misfires on macOS BSD nc
   (BSD nc's -p means source port, not listen port — wrong syntax)

2. start_oauth_server: replaced echo -e (broken on macOS bash 3.x) with
   printf-based write_oauth_response_file called before the subshell.
   Removed local vars from subshell (not function scope).

3. ((elapsed++)) / ((attempt++)) → $((var + 1)) to avoid set -e killing
   the script when the value is 0 (evaluates falsy).

Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-07 16:40:21 -08:00
L
4087deb14e
Drop nounset (set -u) flag — incompatible with env var checks (#27)
The autonomous refactoring added `set -euo pipefail` but the scripts
check optional env vars with `[[ -n "$VAR" ]]` which is a fatal error
under nounset when the var isn't set (e.g. SPRITE_NAME, OPENROUTER_API_KEY).

Fix: downgrade to `set -eo pipefail` across all 42 affected files.

Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-07 16:22:04 -08:00
L
3fb2e77b03
Autonomous refactoring: 5 rounds, ~1,400 lines eliminated, production-ready
Five rounds of autonomous AI agent team refactoring with security fixes, code consolidation, and expanded test coverage.
2026-02-08 00:06:46 +00:00