Previously, `spawn list hetzner` always treated the bare positional
argument as an agent filter, returning 0 results since "hetzner" is a
cloud, not an agent. Now resolveListFilters auto-detects: when the
filter doesn't resolve as an agent but does resolve as a cloud, it
reclassifies to a cloud filter. This matches the help text which
promises "Filter history by agent or cloud name".
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>
Adds label lifecycle transitions (Pending Review → Under Review → In Progress)
directly into both issue mode and refactor mode prompts per maintainer request
on #546. The community-coordinator now manages labels at each stage of issue
engagement, and the shutdown checklist verifies all open issues are labeled.
Fixes#546
Agent: team-lead
Co-authored-by: Sprite <noreply@sprite.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover groupByType, buildAgentLines, buildCloudLines, credentialHint,
mapToSelectOptions, buildRecordLabel, buildRecordHint, and
resolveDisplayName edge cases. Uses the established replica pattern
since these functions are not exported.
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>
Implements Plandex on Netcup VPS using netcup/lib/common.sh primitives.
Updates manifest.json to mark netcup/plandex as implemented.
Updates netcup/README.md with Plandex usage instructions.
Agent: gap-filler-netcup
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements Open Interpreter on local machine using local lib/common.sh primitives.
Agent: gap-filler-local
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Exit codes 126 (permission denied) and 137 (killed/OOM) previously
showed terse one-line messages with no suggestions for what to do.
Now they include specific causes and remediation steps, consistent
with all other exit codes in getScriptFailureGuidance.
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>
The `echo ""` on line 351 of get_model_id_interactive() was going to
stdout, causing it to be captured by command substitution into MODEL_ID.
This injected a newline into the openclaw.json config, breaking JSON
parsing with "invalid character '\n' at 15:0".
Fixes#553
Agent: issue-fixer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
13 cloud providers had identical 5-line check_ssh_key functions that
fetch SSH keys from the provider API and grep for the fingerprint.
Extract this pattern into a shared check_ssh_key_by_fingerprint helper
in shared/common.sh, reducing each cloud's function to a single line.
Affected clouds: BinaryLane, Cherry, Civo, Contabo, DigitalOcean,
Genesis Cloud, Hetzner, Hostinger, Latitude, Linode, OVH, Scaleway,
Vultr.
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>
The generic_wait_for_instance timeout message previously just said
"did not become active in time" with no guidance. Now it follows the
same pattern as generic_ssh_wait by telling users what to do next.
Similarly, _validate_token_with_provider now shows the env var name
so users can set it directly instead of re-running interactively.
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>
- Support `spawn list claude` as shorthand for `spawn list -a claude`
- Add --agent and --cloud as long-flag aliases for -a and -c
- Fix flaky cmdlist-integration tests by priming manifest cache in
beforeEach and isolating XDG_CACHE_HOME to prevent cross-test leakage
- Export _resetCacheForTesting from manifest.ts for deterministic tests
- Update help text with new filter syntax and examples
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>
The get_model_id_interactive function returned MODEL_ID from env vars
without calling validate_model_id, bypassing the allowlist check. Also
migrated 13 legacy scripts from raw safe_read to get_model_id_interactive
which includes validation.
Agent: security-auditor
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The json_escape function already adds quotes around strings, so using
"%s" in printf was adding a second set of quotes, resulting in invalid
JSON like `"OPENROUTER_API_KEY": ""value""`.
Fixed railway/openclaw.sh and koyeb/openclaw.sh to use %s (unquoted)
for API key and token fields, matching the correct pattern used in
fly/openclaw.sh and shared/common.sh.
Fixes#542
Agent: issue-responder
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Cover the untested filter resolution path added in PR #537 where
cmdList resolves display names (e.g., "Claude Code" -> "claude") before
querying history. Also cover buildRecordLabel/buildRecordHint helpers
from PR #531 and the double-quote escaping in rerun prompt 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 saveSpawnRecord MAX_HISTORY_ENTRIES=100 trimming was completely untested.
These tests cover: trimming at boundary (99->100, 100->101), trimming well
over limit (150+1), prompt preservation through trimming, sequential saves
crossing the limit, filterHistory reverse-chronological ordering, boundary
conditions (empty/missing dir), and file format after trimming.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
The word "list" is ambiguous in a CLI that also has "spawn agents" and
"spawn clouds" -- users naturally expect "spawn list" to list resources,
not show history. Adding "spawn history" as a first-class alias makes
the history command more discoverable. Also documents both aliases (ls,
history) in the help text.
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>
1. _cloud_api_retry_loop: consolidate two duplicate retry branches
(network error + HTTP 429/503) into a single retry path using a
retry_reason variable. Reduces from 47 to 43 lines, eliminates
duplicated _api_should_retry_on_error / _update_retry_interval calls.
2. interactive_pick: extract list display + selection into reusable
_display_and_select helper. The main function is now a thin wrapper
that checks env var, fetches items, then delegates to the helper.
3. generic_ssh_wait: replace inline backoff calculation (3 lines) with
existing _update_retry_interval helper, reducing duplication.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Replace 25-line custom _binarylane_wait_for_active with 4-line
generic_wait_for_instance call, matching the pattern used by 7 other
clouds (DigitalOcean, Vultr, Linode, etc).
Change log_warn to log_step for status/progress messages in polling
loops across 7 cloud providers (aws-lightsail, exoscale, fly, kamatera,
latitude, ovh, scaleway). These are normal status updates, not warnings.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
- Resolve display names in `spawn list -a/-c` filters (e.g., "Claude Code" -> "claude")
- Fix dry-run preview to show GitHub raw URL instead of non-existent openrouter.ai/lab URL
- Cap history at 100 entries to prevent unbounded growth
- Rename compact matrix "Missing" column to "Not yet available" for clarity
- Escape double quotes in rerun prompt suggestions to produce valid shell commands
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
18 cloud lib/common.sh files had identical 7-line get_server_name()
functions (get_resource_name + validate_server_name + echo). Added a
shared get_validated_server_name helper to shared/common.sh and replaced
all duplicates with one-line delegations. Net -110 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>
~1500 progress messages across 481 files were using log_warn (yellow)
for normal status updates like "Installing...", "Setting up...",
"Creating server...", etc. This made users think something was wrong
when everything was proceeding normally.
Changes:
- Replace log_warn with log_step for all progress/status messages
- Keep log_warn only for actual warnings (errors, remediation hints)
- Remove emoji from 3 sprite completion messages
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Remove 2 unnecessary indirection layers (_handle_api_transient_error and
_api_handle_transient_http_error) from the cloud API retry infrastructure.
The old _handle_api_transient_error had a bug where "network" was passed
as the attempt parameter to _api_should_retry_on_error, which expects a
numeric value. The retry logic is now inlined directly in
_cloud_api_retry_loop, calling _api_should_retry_on_error with the
correct arguments.
Also extract duplicated help-flag checking in dispatchCommand into a
hasTrailingHelpFlag helper, reducing nesting and removing repeated code.
Net: -72 lines, 2 fewer functions, 1 bug fix.
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 26 tests covering the cmdList pipeline through the actual
exported function with mock.module for @clack/prompts. Tests the
full path from history file through rendering: empty history,
table rendering with display names, agent/cloud filtering,
prompt display, manifest fallback, footer formatting.
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>
When run in a TTY, `spawn list` (or `spawn ls`) now shows an interactive
picker using @clack/prompts select. Users can navigate the list with
arrow keys and press Enter to immediately rerun a previous spawn.
Non-TTY environments (piped output, CI) continue to show the static
table as before.
Fixes#492
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>
Add Cline agent support for RamNode Cloud via OpenStack API.
Uses npm install -g cline, injects OpenRouter credentials via
OPENAI_API_KEY and OPENAI_BASE_URL env vars.
Agent: ramnode-gap-filler
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Add local machine support for Continue (31K+ GitHub stars).
Installs @continuedev/cli via npm and configures OpenRouter.
Agent: local-gap-filler
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Tests the complete cmdRun success flow: primary/fallback download,
history recording during execScript, SPAWN_PROMPT/SPAWN_MODE env var
passing to bash, dry-run skip, and script content validation.
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 credential-hint logic from case 1/default into
credentialHint() helper, and flatten nested if-blocks in
generic_wait_for_instance using early-continue.
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>
Replace log_warn (yellow) with log_step (cyan) for progress messages
like "Installing...", "Setting up environment variables...", and
"Starting..." in recently-added scripts. Yellow warnings should be
reserved for actual warnings, not normal progress output.
Also fix bare `clear` calls to use `clear 2>/dev/null || true` for
robustness on minimal terminals, and improve the misleading
"Appending environment variables to ~/.zshrc..." message in local
scripts to the standard "Setting up environment variables..." phrasing.
Files: local/gptme.sh, local/aider.sh, ramnode/openclaw.sh,
ramnode/gptme.sh, netcup/gptme.sh
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>
Implements local/gptme.sh for running gptme on the local machine without cloud provisioning.
Agent: gap-filler-local-2
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements OpenClaw deployment on RamNode Cloud using OpenStack API primitives.
Agent: gap-filler-ramnode-1
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements local/aider for running Aider AI pair programming tool on local machine.
Agent: gap-filler-local-1
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements gptme agent on Netcup VPS using netcup lib primitives.
Agent: gap-filler-netcup
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements gptme agent on RamNode Cloud using OpenStack primitives.
Agent: gap-filler-ramnode-2
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
When a spawn script fails with exit code 1 (the most common failure),
the error message now shows which specific environment variables are
needed (e.g., "need HCLOUD_TOKEN + OPENROUTER_API_KEY") instead of
the generic "run spawn <cloud> for setup" which required a second
command to discover the needed credentials.
Also adds a "Retry:" hint with the exact rerun command at the end of
all script failure error messages.
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 renderMatrixFooter, renderListTable, and suggestTypoCorrection
to reduce function complexity and improve readability.
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>
Users coming from Docker, kubectl, or other CLIs naturally try
"spawn run claude sprite" or "spawn launch aider hetzner". Previously
these would show a confusing "Unknown command: run" error. Now the CLI
transparently strips these verb prefixes and forwards to the correct
agent/cloud handler. Bare verbs like "spawn run" show a helpful message
explaining the correct syntax.
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>
Cover the integration of cmdList with manifest-resolved display names,
table header/separator rendering, prompt preview truncation in rows
vs footer, filtered result counts, timestamp formatting, and the
resolveDisplayName exported utility.
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
- Add "Availability Matrix (N agents, M clouds)" title to spawn matrix output
- Shorten compact view column header from "Not available on" to "Missing"
- Show display names (e.g. "Claude Code") instead of raw keys in 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>
Fix agent-config-setup test that expected "does not run correctly" but
shared/common.sh now says "returned an error". Add 25 new tests verifying
checkEntity's user-facing messages for wrong-type detection, same-kind
fuzzy match, cross-kind fuzzy match (PR #510), and no-match fallback.
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>