The showInfoOrError function loaded the manifest without a spinner,
causing no visual feedback on cold cache. Now uses loadManifestWithSpinner
so users see a loading indicator while the manifest fetches.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Show actionable auth setup commands in `spawn <cloud>` and `spawn <agent>`
output so users can get started immediately without reading README docs.
For clouds with env var auth (e.g. Hetzner), shows exact export commands:
Quick start:
export HCLOUD_TOKEN=your-hcloud-token-here
spawn claude hetzner
For agents, shows OpenRouter API key and example launch command:
Quick start:
export OPENROUTER_API_KEY=sk-or-v1-...
spawn claude sprite
Also adds parseAuthEnvVars() utility with 6 tests and 8 quick-start
integration tests.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Export and test 7 previously-unexported utility functions from commands.ts:
getTerminalWidth, getMissingClouds, getImplementedAgents, getImplementedClouds,
getErrorMessage, calculateColumnWidth, getStatusDescription.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover previously untested code paths:
- cmdCloudInfo "Not yet available" missing agents text (<=5 threshold)
- cmdCloudInfo setup URL and auth field display
- cmdCloudInfo agent count (N of M) format
- cmdAgentInfo URL and notes display
- cmdAgentInfo cloud count and type grouping
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
- Manifest load failure now shows specific troubleshooting steps including
cache directory path for manual cleanup
- Non-TTY mode explains why interactive picker is unavailable and suggests
the direct launch syntax instead of silently falling through to help
- `spawn update` network failure now includes recovery steps and manual
update command
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Agent info (spawn <agent>) now shows "X of Y" cloud count and groups
clouds by type (api, cli, sandbox) for easier scanning
- Cloud info (spawn <cloud>) now shows "X of Y" agent count, auth method,
and lists missing agents when there are 5 or fewer
- Cloud listing (spawn clouds) groups providers by type with X/Y ratio
counts instead of singular/plural text
- Remove unused TYPE_COLUMN_WIDTH constant
- Bump CLI version to 0.2.26
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Validates ALL implemented scripts against CLAUDE.md shell script rules,
covering shebang, set -eo pipefail, lib/common.sh sourcing, macOS bash
3.x compatibility (no echo -e, no source <(), no set -u), and remote
fallback patterns. Unlike manifest-integrity.test.ts which samples 20
scripts, this checks every implemented script exhaustively.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Cover the previously untested branch in validateAgent (lines 150-158) and
validateCloud (lines 186-194) where findClosestMatch against display names
is used when key-based suggestion fails. Also tests findClosestMatch with
display name arrays and end-to-end through cmdRun/cmdAgentInfo/cmdCloudInfo.
22 new tests, all pass.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Show agent/cloud URLs in info pages (spawn <agent>, spawn <cloud>)
- Add setup instructions link to cloud info pages
- Suggest available clouds when --prompt is used without a cloud arg
- Fix help text alignment for spawn list
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Spinner completion messages now show "done" state instead of repeating
the in-progress message (e.g., "Loading manifest" instead of "Loading manifest...")
- Script failures show actionable troubleshooting (missing credentials,
rate limits, dependencies) instead of generic "Script exited with code N"
- Ctrl+C (exit code 130) exits silently instead of showing an error
- Fuzzy matching for unknown agents/clouds now also searches display names,
so "Hetzner" suggests "hetzner" even when the key doesn't fuzzy-match
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename "Missing" column to "Not available on" to avoid confusion
- Change "all clouds" to "-- all clouds supported" for full coverage agents
- Only show +/- grid legend in grid view (not compact view)
- Fix help text alignment for "spawn list" command
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Users typing "spawn Claude" or "spawn Claude Code" now get resolved
to the correct key automatically instead of an "invalid characters"
error. Works for both agents and clouds in single-arg info and
two-arg run paths.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auto-correct swapped arguments (e.g., `spawn sprite claude` now runs
as `spawn claude sprite`) instead of just warning and exiting
- Document `ls` alias for `list` in help text
- Add SPAWN_NO_UPDATE_CHECK env var to troubleshooting section
- Bump version to 0.2.21
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests the compact list view triggered when the matrix grid is wider
than the terminal. Covers view switching logic, count formatting,
missing clouds column, "all clouds" display, and edge cases.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cli/cli.js is a bun build output that should never have been committed.
Remove it from tracking and add it to .gitignore.
Fixes#296
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>
Adds 25 tests for the previously untested showInfoOrError function which
handles single-argument CLI routing (agent info, cloud info, unknown
command with fuzzy suggestions). Tests cover valid agents, valid clouds,
unknown names, fuzzy match suggestions, help flag routing, and edge cases.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The `spawn list` grid was 888 characters wide with 30 clouds, making it
completely unreadable in standard terminals (80-120 columns). Now detects
terminal width and automatically switches to a compact view showing each
agent with its cloud count and any missing clouds.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cmdAgentInfo now displays the cloud type (api, cli, sandbox, etc.) next
to each cloud provider, helping users understand what kind of
infrastructure they're choosing. Also shows agent notes when present.
cmdCloudInfo now shows the cloud type beneath the description for
quick reference.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Runs `bash -n` on every shell script in the repo:
- shared/common.sh (core library)
- All 21 cloud lib/common.sh files
- All 264+ implemented agent scripts
This is the automated equivalent of the CLAUDE.md rule:
"Run bash -n on every changed .sh file before committing."
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract duplicated agent/cloud lookup logic into showInfoOrError() and
replace repetitive switch cases with dispatch tables, reducing main()
from 85 to 65 lines and handleDefaultCommand() from 52 to 16 lines.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, unknown flags like --json or --verbose were silently ignored
or misinterpreted as positional arguments (agent/cloud names), leading to
confusing error messages. Now the CLI detects unrecognized flags and shows
a clear error listing the supported flags.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests the actual CLI entry point through subprocess execution:
- help/version command routing (help, --help, -h, version, --version, -v, -V)
- Subcommand --help routing (list --help, agents --help, clouds --help, etc.)
- ls alias routing
- Non-TTY mode behavior (shows help when no args)
- handleError formatting for invalid identifiers
- extractFlagValue in actual CLI (--prompt/--prompt-file missing values)
- --prompt and --prompt-file mutual exclusion
- --prompt-file with nonexistent file
- Prompt-only-without-cloud error messaging
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, `spawn hetzne` (typo of cloud name "hetzner") would show
"Unknown agent: hetzne" with no useful suggestion, because it only
searched agent names for typo matches. Now when a single argument
matches neither an agent nor a cloud, the error searches both pools
and shows "Did you mean hetzner (cloud)?" — guiding the user to the
right command.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cmdCloudInfo was the only major command function with zero test coverage.
Tests cover happy paths, cloud notes display, empty agents state, error
paths (invalid identifiers, unknown clouds), and typo suggestions.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bun build command was failing on proot-distro ubuntu because it couldn't
resolve node_modules dependencies. Added --packages bundle flag to explicitly
bundle all dependencies into the output file.
Fixes#209
Agent: issue-responder
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Validates that manifest.json is internally consistent and that every
"implemented" matrix entry has a corresponding script file. Catches
configuration drift between manifest.json and the actual file tree.
Tests cover:
- Manifest structure (agents, clouds, matrix top-level keys)
- Agent/cloud definition required fields and naming conventions
- Matrix consistency (valid statuses, complete coverage, no duplicates)
- Script file existence for all implemented entries
- Cloud lib/common.sh existence for clouds with implementations
- Script content basics (shebang, set -eo pipefail, sourcing lib)
- Orphaned script detection (files exist but marked "missing")
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Users who know their preferred cloud but not which agents are available
had no way to find out. Now `spawn hetzner` shows all agents available
on Hetzner, mirroring how `spawn claude` shows all clouds for Claude.
- Add cmdCloudInfo() showing cloud details + available agents
- handleDefaultCommand detects cloud names and routes to cloud info
- Update help text and clouds list footer to document the new command
- Bump CLI version to 0.2.15
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Rename the GitHub workflow, scripts, and service from "improve" to
"discovery" to better reflect what the automation does. Remove the
`spawn improve` CLI command entirely — the discovery/refactor loops
are internal automation, not user-facing CLI features.
File renames:
- .github/workflows/improve.yml → discovery.yml
- .claude/skills/.../improve.sh → discovery.sh
- .claude/skills/.../start-improve.sh → start-discovery.sh
- Service: improve-trigger → discovery-trigger
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When users type "spawn sprite claude" instead of "spawn claude sprite",
the CLI now detects the swap and suggests the correct order instead of
showing a confusing "Unknown agent" error. Also fixes grammar in
"spawn agents" and "spawn clouds" output (1 cloud vs 1 clouds).
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add "Did you mean?" suggestions when agent/cloud names have typos
(using Levenshtein distance, max 3 edits)
- Handle "spawn <agent> --help" to show agent info instead of failing
with "invalid characters" error on the --help flag
- Handle "--help" after subcommands (spawn list --help, spawn agents --help)
to show general help instead of silently ignoring the flag
- Bump CLI version to 0.2.13
- Add 15 tests for levenshtein and findClosestMatch functions
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
The compareVersions function decides whether auto-update runs, but had
no direct test coverage. Tests cover: basic comparisons, precedence
ordering (major > minor > patch), missing/extra segments, zero and
boundary versions, non-numeric input handling, parseSemver helper,
realistic spawn version scenarios, and full checkForUpdates integration
with edge-case version strings.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
The spawn scripts themselves use curl|bash to install agents (e.g.
Claude Code). The validateScriptContent check was blocking our own
legitimate scripts. Removed curl|bash and wget|bash from the
dangerous patterns list since the scripts are already fetched from
our trusted GitHub repo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The unicode-detect module only modifies TERM, never LANG. Two tests
incorrectly expected LANG to be set to en_US.UTF-8 - fixed to match
actual module behavior.
Agent: team-lead
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: Bun has a known bug (oven-sh/bun#25767) where --target=node
causes UTF-8 string literals to be double-encoded as Latin-1, producing
mojibake (â instead of ◆/│/✔). Switching to --target=bun avoids this
encoding path entirely.
Also removes the ineffective stdout.write monkey-patch that was
attempting to work around this issue.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- `spawn update` now performs auto-update instead of printing curl command
- `--prompt` without both agent and cloud now errors instead of being silently dropped
- Update banner box uses dynamic padding to align correctly with any version length
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract resolvePrompt() from main() in cli/src/index.ts (98 -> 62 lines)
Separates prompt flag parsing/file-reading from command dispatch
- Extract _validate_oauth_server_args() and _generate_oauth_html() from
start_oauth_server() in shared/common.sh (81 -> 52 lines)
Separates validation/HTML generation from server startup
- Bump CLI version to 0.2.11
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 16 tests for unicode-detect.ts which had zero coverage.
Tests verify ASCII/Unicode detection based on TERM, SSH,
and SPAWN_UNICODE/SPAWN_ASCII/SPAWN_NO_UNICODE env vars.
Also tests LANG setting and debug output behavior.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Explicitly convert string chunks to Buffer.from(chunk, 'utf8') before
writing to process.stdout. This fixes UTF-8 mojibake (â instead of ◆/│)
seen in some Bun + terminal combinations (e.g. Ghostty on macOS) where
process.stdout.write(string) doesn't encode as UTF-8 by default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added explicit LANG=en_US.UTF-8 and stdout.setEncoding('utf8')
when Unicode mode is enabled. This should prevent UTF-8 mojibake
(â appearing instead of ◆) in terminals like Ghostty.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds debug logging to unicode-detect.ts to help troubleshoot why
Unicode rendering isn't working in Ghostty terminal. When SPAWN_DEBUG=1
is set, the CLI will show:
- Current TERM value (e.g., xterm-ghostty)
- SSH environment variables (SSH_CONNECTION, SSH_CLIENT, SSH_TTY)
- Whether ASCII mode is being forced
This will help identify if SSH detection is incorrectly triggering
ASCII fallback for local Ghostty sessions.
Usage: SPAWN_DEBUG=1 spawn list
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Reverses the overly conservative ASCII-only approach. Now defaults to
Unicode (beautiful spinners, checkmarks, symbols) on local macOS
Terminal, iTerm2, and modern Linux terminals, while still forcing
ASCII fallback for problematic environments:
- SSH sessions (encoding mismatches)
- Dumb terminals (TERM=dumb)
- Users can override with SPAWN_UNICODE=1 or SPAWN_NO_UNICODE=1
This fixes rendering issues while maintaining compatibility across
all environments.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Set both TERM=linux and CI=true in unicode-detect.ts
- CI env var provides additional Unicode disabling for @clack/prompts
- Fix test imports to use package.json instead of deleted version.ts
- Bump to 0.2.6
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Bumped CLI version from 0.2.4 to 0.2.5
- Added rule to CLAUDE.md: ANY change to cli/ requires a version bump
- Uses semantic versioning (patch for fixes, minor for features, major for breaking)
- Auto-update ensures users get latest version immediately
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>