printf %q escapes spaces and shell metacharacters, turning "claude install"
into "claude\ install" — which bash -c interprets as a single command named
"claude install" (with literal space). This broke all multi-word commands
passed to run_sprite, including pipes, redirects, and && chains.
Since all callers pass trusted, hardcoded command strings (not user input),
the command string should be passed directly to bash -c for normal shell
parsing.
Fixes#88
Agent: team-lead
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When sprite version output doesn't match the expected format, the message
now omits the version rather than displaying "unknown". Also broadened the
version regex to match versions without 'v' prefix.
Fixes#79
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhance UX across CLI and cloud providers with actionable error messages:
1. Modal sandbox creation failures now provide:
- Detailed error output from Python SDK
- Common causes (auth expired, quota issues, network)
- Step-by-step troubleshooting (re-auth, check quota, status page)
2. Modal CLI installation failures now explain:
- Missing pip/pip3 (with installation commands)
- Permission issues (suggest --user flag)
- Manual installation steps
3. Sprite connectivity failures now include:
- Commands to check sprite status and logs
- Steps to recreate sprite
- Support contact information
4. Sprite CLI installation now:
- Catches installation failures with helpful error messages
- Verifies installation succeeded before proceeding
- Provides manual installation instructions
5. CLI script download failures improved:
- Distinguish between 404 (doesn't exist) and other errors
- Provide specific next steps for each scenario
- Suggest checking matrix for implementation status
All error messages follow the pattern:
- What went wrong
- Why it might have happened (common causes)
- What to do next (actionable steps)
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Modified ensure_sprite_installed() to check if sprite is already installed
- When sprite is found, log version and skip installation
- Prevents unnecessary reinstalls when sprite CLI is already present
Fixes#63
Agent: community-coordinator
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Removed manual rm calls for temp files in sprite/lib/common.sh since
traps now handle cleanup automatically. Combined traps for both temp
files in configure_shell_sprite() function.
Impact: Prevents temp file leaks on crashes/interrupts
Risk: Low - only removing redundant cleanup calls
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Quote INSTANCE_STATUS_POLL_DELAY, SSH_RETRY_DELAY, and
SPRITE_CONNECTIVITY_POLL_DELAY to prevent potential word splitting
issues with unusual values.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Separated local variable declaration from command substitution assignment
in upload_file_sprite function to avoid masking return values.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Protects against 'unbound variable' errors even if set -u is
re-enabled or inherited. Every [[ -n "$UPPER_VAR" ]] pattern now
uses [[ -n "${UPPER_VAR:-}" ]] to safely default to empty.
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
When scripts run via `bash <(curl ...)`, BASH_SOURCE resolves to
/dev/fd/N, making the relative path `../../shared/common.sh` fail.
Fix: add remote fallback — try local file first, fall back to
fetching shared/common.sh from GitHub via eval+curl.
Applied to all 5 refactored lib/common.sh files (sprite, hetzner,
digitalocean, vultr, linode).
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three issues broke the OAuth callback server on macOS:
1. echo -e doesn't work in bash 3.x — \r\n appears as literal text
in the HTTP response, browser gets malformed headers.
Fix: pre-write response with printf to a file before the subshell.
2. local variables inside ( ... ) & subshell — undefined behavior in
bash 3.x since subshells aren't function scope.
Fix: use plain variables in subshells.
3. ((elapsed++)) when elapsed=0 evaluates to falsy — set -e kills
the script on the first iteration of the timeout loop.
Fix: use elapsed=$((elapsed + 1)) instead.
Also simplified nc_listen detection to only check for BusyBox
(the -p flag check could misfire on macOS nc).
Applied to all 10 lib/common.sh files.
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add styled success page with CSS-animated checkmark, fade-in messaging,
and auto-close after 3 seconds with fallback text if browser blocks it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add nc_listen helper that detects busybox nc and uses -p flag accordingly
- Add termux-open-url support to open_browser
- Deduplicate inline browser opener in try_oauth_flow to use open_browser
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Retry connectivity up to 6 attempts (30s) instead of trying once and
silently continuing, which caused the next sprite exec to fail under set -e.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- safe_read(): Test /dev/tty is functional before using it (exists
but fails in containers/VMs)
- Log functions: Write to stderr so they don't pollute stdout in
command substitutions like $(get_sprite_name)
- ensure_sprite_exists(): Fix grep regex (use -E for ERE)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The scripts were failing when run via curl | bash because they tried
to read from /dev/tty which doesn't exist in piped contexts.
## Changes
- Added safe_read() helper function that gracefully handles TTY absence
- Updated get_sprite_name() to support SPRITE_NAME env variable
- Updated all read commands to use safe_read()
- Added clear error messages for non-interactive usage
- Updated README with non-interactive mode documentation
## Usage
Interactive:
curl URL | bash
Non-interactive:
SPRITE_NAME=dev-mk1 curl URL | bash
SPRITE_NAME=dev-mk1 OPENROUTER_API_KEY=sk-xxx curl URL | bash
## Fixes
- /dev/tty: No such device or address error
- Scripts now work in CI/CD and automated contexts
- OAuth fallback still works via OPENROUTER_API_KEY env var
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>