Entries in `spawn ls` and `spawn delete` now display as two lines:
- Line 1: spawn name (bold)
- Line 2: Agent · Cloud · relative time
Removes SSH connection info and prompt previews from the list display
to keep it clean and scannable.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Long labels (e.g. "Claude Code on GCP Compute Engine -- spawn-trial-000-ahmed")
wrap to multiple rows, but the redraw logic uses a fixed line count to cursor-up.
This causes old content to pile up on every arrow-key press.
Query terminal width via `stty size` and truncate all lines to fit within
a single row, with a 1-char margin to prevent auto-wrap edge cases.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pressing `d` in the server picker now shows a sub-menu:
- Destroy server: hard delete (destroys cloud VM + marks deleted)
- Remove from history: soft delete (removes entry, no cloud API call)
- Cancel: go back to picker
Also adds `kill` as an alias for `spawn delete`.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
KNOWN_FLAGS in unknown-flags.test.ts was copy-pasted from index.ts and
was missing the --name flag, causing silent test gaps. Extract
KNOWN_FLAGS, findUnknownFlag, and expandEqualsFlags into a new flags.ts
module so tests import the real source of truth.
- Create cli/src/flags.ts with KNOWN_FLAGS, findUnknownFlag, expandEqualsFlags
- Update index.ts to import from flags.ts (checkUnknownFlags now uses findUnknownFlag)
- Update unknown-flags.test.ts to import from flags.ts instead of copy-pasting
- Add tests for --name flag, KNOWN_FLAGS completeness, and expandEqualsFlags
- Bump CLI version to 0.6.15
Fixes#1744
Agent: test-engineer
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
When the CLI collects a display name (SPAWN_NAME), each cloud now shows
the kebab-case derivative as the default in the resource name prompt
instead of silently accepting it. Users can hit Enter to accept or type
an override. Non-interactive mode still skips the prompt.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SSH interactive sessions ran the agent command in a non-login,
non-interactive shell — .bashrc/.profile weren't sourced and TERM
wasn't always set, making the shell feel broken (no colors, bad
line editing, missing env).
Fix for all 6 SSH-based clouds (DO, Hetzner, AWS, GCP, Fly, Daytona):
- Forward local TERM (default xterm-256color) to the remote
- Use `exec bash -l -c` for a proper login shell
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add ~/.bun/bin to shell rc files so spawn finds bun after install
The install script was only adding ~/.local/bin to shell profile files
(bashrc/zshrc/bash_profile), but not ~/.bun/bin. Since the spawn binary
uses #!/usr/bin/env bun as its shebang, bun must be in PATH for spawn
to work. After exec $SHELL, only dirs in rc files are available.
Now ensure_in_path() patches shell rc files for both ~/.local/bin (for
spawn) and ~/.bun/bin (for bun), and correctly checks both when deciding
whether to show "Run spawn" vs "exec $SHELL" instructions.
Fixes#1747
Agent: code-health
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: quote dir in fish_add_path to prevent command injection
Address security review feedback on PR #1748 — unquoted ${dir} in
fish command string could allow injection if HOME/BUN_INSTALL env
vars contain metacharacters.
Agent: code-health
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
apt-get install nodejs npm pulls in hundreds of node-* packages
(libhwasan, node-jsonify, node-eslint-utils, etc.) adding 60-90s
to cloud-init. We immediately replace it with Node 22 via n anyway.
Fix: bootstrap n directly from curl and install Node 22 in one step.
No apt nodejs/npm needed.
Before: apt install nodejs npm → npm install -g n → n 22 (slow)
After: curl n | bash -s install 22 (fast, no apt bloat)
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add build-essential to node cloud-init tier
The "node" tier (used by claude, codex, kilocode) was missing
build-essential. Native npm packages that compile C/C++ addons
fail without it. The "full" tier had it but no agent uses "full".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: upgrade openclaw to full cloud-init tier
Openclaw needs the most dependencies (build-essential, nodejs, npm,
bun) but was on the "bun" tier which only installed curl/unzip/git/zsh.
Switch to "full" which includes everything.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DigitalOcean's cloud-init environment doesn't set HOME. Combined
with set -e, any $HOME or ~ reference (bun install, .bashrc writes)
fails with "HOME: unbound variable" and cloud-init silently aborts.
Fixed in both DigitalOcean and Hetzner (same pattern). AWS doesn't
use set -e so is unaffected.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
.join("; ") produced invalid bash: &; after background command,
do; after for, then; after if. Use newline-joined string instead.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 60×5s blind poll loop ("Cloud-init in progress N/60") with
real-time streaming of /var/log/cloud-init-output.log via tail -f
over SSH. Users now see every apt-get, curl, and error as it happens.
Background checker exits as soon as .cloud-init-complete marker
appears. 5min timeout. Brief 30s fallback poll if streaming fails.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Agents declare their dependency tier (minimal/node/bun/full), and
cloud-init only installs what's needed. Lightweight agents like
OpenCode and ZeroClaw skip Node.js upgrade, Bun install, and
build-essential — saving 60-90s on boot and eliminating the
DigitalOcean cloud-init timeout.
- Add CloudInitTier type + cloudInitTier field to AgentConfig
- Add shared/cloud-init.ts: tier-to-packages mapping
- Update all 6 clouds (DO, Hetzner, AWS, GCP, Fly, Daytona)
- Bump CLI version to 0.6.8
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When both OAuth flows open browser tabs back-to-back, the user may
reactively close the second tab thinking it's a duplicate. Add a 5-second
pause with a message after DO OAuth completes, only when browser auth
was actually used (skipped for env var / saved token paths).
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OAuth token validation calls GET /v2/account which requires the
account:read scope. Without it, the token exchange succeeds but
validation fails with 403, falling through to manual token entry.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add DigitalOcean OAuth2 flow for automatic token provisioning
Implements the OAuth2 authorization code flow for DigitalOcean as an
alternative to manual API token entry. The flow mirrors the existing
OpenRouter OAuth pattern using Bun.serve() for the local callback.
Changes:
- Add tryDoOAuth() with local Bun.serve callback, CSRF state, and
code-for-token exchange via DO's /v1/oauth/token endpoint
- Add tryRefreshDoToken() for refreshing expired tokens without
re-authorization
- Extend config persistence with refresh_token, expires_at, auth_method
- Modify ensureDoToken() flow: env var -> saved config (with refresh) ->
OAuth browser flow -> manual paste fallback
- OAuth is gated on DO_OAUTH_CLIENT_ID and DO_OAUTH_CLIENT_SECRET env vars
- Add 37 tests covering config persistence, CSRF generation, code
validation, token expiry, URL construction, and feature toggle
- Bump CLI version to 0.6.5
Closes#1715
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: hardcode DO OAuth credentials, remove env var gate
Embed client_id and client_secret as constants (same pattern as gh CLI,
doctl, gcloud). OAuth is now always available — no env vars needed.
Public CLI clients cannot keep secrets confidential; security comes from
the authorization code flow itself (user consent, localhost redirect,
CSRF state, single-use codes).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add droplet:delete scope for spawn delete support
The spawn CLI's destroyServer() calls DELETE /droplets/{id} which
requires the droplet:delete scope. All its required sub-scopes
(droplet:read, regions:read, sizes:read, actions:read, image:read)
were already present.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All clouds now use TypeScript. Convert the last holdout (AWS) from bash
lib fallback to the JS bundle download pattern, then delete all remaining
cloud bash libs and clean up stale test code.
- Convert 6 AWS agent scripts to JS bundle fallback (matching hetzner)
- Delete aws/lib/common.sh and hetzner/lib/common.sh
- Delete orphaned test/fixtures/ovh/
- Stub out dead functions in test/e2e.sh that sourced deleted libs
- Delete 3 test files that only tested cloud bash libs
- Remove dead describe blocks from 3 remaining test files
- Bump CLI version 0.6.3 → 0.6.4
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert gcp, daytona, digitalocean, hetzner, sprite, and local clouds
to use shared/agent-setup.ts and shared/orchestrate.ts, matching the
pattern established by AWS and Fly. Each cloud's agents.ts is now a
~26-line thin wrapper; each main.ts uses runOrchestration().
- Delete gcp/lib/common.sh (406 lines of dead bash code)
- Delete cli/src/fly/oauth.ts and cli/src/fly/ui.ts re-export wrappers
- Fix all fly/oauth and fly/ui imports to use shared/ directly
- Update test thresholds for reduced bash cloud count
- Bump CLI version to 0.6.3
Net reduction: ~2,850 lines removed.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract ~800 lines of duplicated agent helpers and orchestration logic
from aws/agents.ts and fly/agents.ts into shared modules:
- shared/agent-setup.ts: CloudRunner interface, installAgent,
uploadConfigFile, installClaudeCode, setupClaudeCodeConfig,
GitHub auth, config helpers, createAgents(), resolveAgent()
- shared/orchestrate.ts: CloudOrchestrator interface + 12-step
runOrchestration() pipeline
- shared/agents.ts: AgentConfig type + generateEnvConfig (single source)
Each cloud becomes a thin wrapper (~25-60 lines) that constructs a
CloudRunner/CloudOrchestrator from its provider-specific functions.
Also fixes pre-existing test breakage (aws.test.ts imported renamed
exports LIGHTSAIL_BUNDLES/BundleTier → BUNDLES/Bundle) and removes
dead aws/lib/common.sh reference from test/e2e.sh.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Creates cli/src/local/{main,local,agents}.ts following the Fly.io
pattern. All 6 agent .sh files replaced with thin bun shims.
Extracts shared oauth.ts and ui.ts to cli/src/shared/ for reuse
across cloud providers. Updates fly/ to re-export from shared.
Fixes#1681
Agent: code-health
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Eliminates the slow waitForCloudInit() + bun install phase by booting
a pre-built image with Node.js, bun, and openclaw already installed.
The image is rebuilt daily via GitHub Actions to pick up new releases.
Other agents are unaffected — they still use ubuntu:24.04 + cloud-init.
Co-authored-by: spawn-bot <spawn-bot@openrouter.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
cmdRun (spawn <agent> <cloud>) was not collecting or passing the spawn
name, so SPAWN_NAME was never set in the script environment and the
history record lacked a name. cmdRunHeadless had the same gap.
- Add promptSpawnName() call to cmdRun and pass result to execScript
- Wire spawnName through HeadlessOptions to runBashHeadless
- Add --name CLI flag to set SPAWN_NAME from the command line
- Skip interactive name prompt when SPAWN_NAME is already set
- Bump CLI to 0.5.33
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Default VM memory: 1024MB → 4096MB (all agents except ZeroClaw
which stays at 1024MB). Prevents OOM kills during native installs.
- Attach a 10GB persistent volume at /data with a /root/work symlink
so agents have enough storage to clone repos and work.
Configurable via FLY_VOLUME_SIZE env var.
- Keepalive: changed dots to spaces so they're invisible in terminal.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Users can now choose VM size (1x/2x/4x shared CPU tiers) and opt into
persistent volumes during provisioning instead of getting hardcoded defaults.
FLY_VM_MEMORY env var still works for CI/headless mode.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The old flow opened up to 60+ separate fly ssh console sessions to
poll port 18789 after starting the gateway daemon. Each session opens
a new WireGuard tunnel which is slow and flaky.
Now: one SSH session starts the daemon, then polls the port in-band
with a simple for loop. Output from the loop also serves as a
keepalive for flyctl.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
bun install -g openclaw spawns child processes that keep stdout/stderr
FDs open, preventing fly ssh console from detecting EOF. Replace with
the official curl installer (--no-onboard) which handles Node detection
and cleanup without leaving orphan processes on the pipe.
See: https://docs.openclaw.ai/install
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
flyctl tears down the WireGuard transport when stdin closes ("session
forcibly closed; the remote process may still be running"). This
killed long-running commands like `bun install -g openclaw`.
Instead of calling stdin.end() immediately, keep the pipe open for
the duration of the command and close it after the process exits.
The pipe still prevents interactive prompts from hanging (no data
flows through it), but flyctl no longer interprets the closed fd
as a signal to kill the session.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fly ssh console with stdin as /dev/null ("ignore") can cause the
connection to hang — flyctl doesn't get a clean EOF signal to know
when to close the transport. Switch to "pipe" and immediately call
stdin.end() so flyctl receives a proper EOF.
Applied to runServer, runServerCapture, and uploadFile.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
git on Ubuntu 24.04 pulls in python3 via recommended packages. Use
--no-install-recommends to install only direct dependencies. Also
added ca-certificates explicitly since it's needed for HTTPS but
won't be auto-pulled without recommends.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes:
1. runServer() was inheriting stdin, so commands like `claude install`
that try to read input would hang the terminal indefinitely. Changed
stdin to "ignore" (/dev/null) for non-interactive remote commands.
2. preLaunch failures (e.g. OpenClaw gateway) were silently swallowed,
dropping users into a broken TUI with no gateway. Now preLaunch
errors propagate — users get a clear error instead of a mystery hang.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tzdata (pulled in as a Node.js dependency) tries to run
dpkg-reconfigure interactively, which fails on headless Fly
machines. Set DEBIAN_FRONTEND=noninteractive so apt silently
accepts defaults.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Fly Machines API enforces a [1s, 1m0s] range on
WaitMachineRequest.Timeout. We were passing 90s, which caused an
invalid_argument error and prevented machines from starting.
Lower the default to 60s (the API maximum) and retry up to 3 times
so slow-starting machines still have a full 3-minute window.
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
testFlyToken() fallback to /v1/user accepted 404 plain text responses
because hasError() only checks for JSON "error"/"errors" keys. Adding
resp.ok check ensures non-2xx responses are correctly rejected.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
promptSpawnName() used `placeholder` (visual hint only) without `defaultValue`,
so pressing Enter returned an empty string instead of applying the placeholder.
Now generates a unique default like `spawn-a3f2` with a random suffix to avoid
Fly.io global name collisions.
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
validateConnectionIP rejected "localhost" (written by local cloud) and
hostnames like "ssh.app.daytona.io" (written by Daytona), causing
mergeLastConnection to silently discard connection data. This broke
spawn list and spawn delete for these providers.
- Add "localhost" to CONNECTION_SENTINELS
- Add HOSTNAME_PATTERN for valid multi-label DNS hostnames
- Update tests: localhost now valid, add hostname acceptance/rejection tests
Agent: code-health
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Two bugs in reExecWithArgs():
1. args.length === 0 early exit:
Running bare `spawn` (interactive picker) after an auto-update would
print "Run your spawn command again" and exit, requiring the user to
manually re-invoke. Now always re-exec so the new flow triggers
immediately.
2. process.argv[1] stale binary path:
If the installer places the updated binary in a different directory than
the currently running binary (e.g. old: ~/.local/bin, new: /usr/local/bin),
re-exec would run the old stale binary. Fix: add findUpdatedBinary() which
resolves via `which spawn` (PATH lookup) first, falling back to
process.argv[1] only if which fails.
Bump CLI version 0.5.17 → 0.5.18.
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix: replace hardcoded ~/.spawn/history.json path in security.ts error messages
Error messages in security validation functions (validateConnectionIP,
validateUsername, validateServerIdentifier, validateMetadataValue) hardcoded
~/.spawn/history.json as the fix path. This is wrong when SPAWN_HOME is set,
directing users to a nonexistent file. Replace all 9 occurrences with
'spawn list --clear' which works regardless of SPAWN_HOME and is simpler
than manually editing JSON.
Agent: ux-engineer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: bump cli version to 0.5.17
Required by CLAUDE.md: any change to cli/ needs a version bump.
PR #1520 changes security.ts error messages (cli/ change).
Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
The test's runCli() helper used \${process.env.HOME}/.bun/bin/bun as
the subprocess command. The test preload sandboxes HOME to a temp dir,
so this path resolves to a nonexistent file, causing ENOENT and 49/56
test failures.
Fix: use bare "bun" (resolved via PATH), matching the pattern in
cli-version-and-dispatch.test.ts and cmdrun-resolution.test.ts.
All 56 tests in cli-entry-edge-cases.test.ts now pass.
Agent: team-lead
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Two error messages told users to run 'spawn clear-history' when
encountering corrupted history files, but that command does not exist.
The actual command is 'spawn list --clear'. Users got a confusing
"Unknown agent or cloud: clear-history" error when following the advice.
Agent: ux-engineer
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Enrich each agent entry with curated metadata fields: creator, repo,
license, created/added dates, GitHub stars, language, runtime, category,
tagline, and tags. This helps users compare and choose agents.
- Extend AgentDef interface with 12 optional metadata fields
- Add metadata to all 6 agents in manifest.json
- Add type validation tests for new fields
- Bump CLI version 0.5.12 → 0.5.13
Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Why: `set -eo pipefail` + `output=$(shellcheck ...)` on line 659 of
test/run.sh causes immediate exit when shellcheck finds any warning,
preventing the entire shell test suite from running. 53 CLI tests also
fail due to stale assertions after agents/clouds were removed in recent
PRs.
Fixes:
- test/run.sh:659 — add `|| true` to shellcheck command substitution so
shell test suite runs to completion even when scripts have warnings
- manifest-real-data.test.ts — lower agent count min from 10→5,
matrix count min from 80→40 (now 6 agents, 48 matrix entries)
- agent-env-injection-contract.test.ts — lower script count min
from 70→40 (now 47 implemented scripts)
- script-conventions.test.ts — same script count fix (70→40)
- cloud-lib-source-chain.test.ts — lower cloud lib min from 9→8
(OVH removed, now 8 clouds)
- commands-credential-display-internals.test.ts — add missing
@clack/prompts mock (tests call p.log.error but never mocked it)
- commands-exported-helpers-edges.test.ts — fix environment-dependent
assertion: only check credential-based hintOverrides, not
CLI-installed ones (sprite CLI is installed in CI/dev)
- agent-config-setup.test.ts — fix stale model ID assertion
("openrouter/anthropic/..." → "anthropic/...") and stale mkdir
command ("rm -rf && mkdir" → "mkdir -p")
- agent-info-quickstart.test.ts — remove sprite from singleAuthManifest
fixture (sprite CLI installed causes sprite to be prioritized over
hetzner, breaking 4 tests); update count assertions for single cloud
Agent: team-lead
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Delete 32 agent scripts ({cloud}/{cline,gptme,plandex,continue}.sh across
8 clouds), remove the 4 agents from manifest.json with all their matrix
entries, update README matrix rows, remove stale mock agent binaries and
plandex.ai URL patterns from test harness, update CLI help examples to use
remaining agents, and bump version 0.5.7 → 0.5.8.
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>