- Remove redundant "Warning:" prefix from API key format message (log_warn
already conveys warning status)
- Fix incorrect `export VAR=token spawn ...` syntax in auth failure hint
(export makes it persistent, inline env var syntax is correct)
- Replace attempt/retry jargon with elapsed time in SSH wait and instance
polling messages (users care about time, not internal retry counts)
- Show instance IP in friendlier "ready (IP: x.x.x.x)" format
- Move HTTP status codes from error title to body in download failures
(cleaner error headline, details still available)
- Simplify dry-run credential warning (remove confusing double-negative
"without --dry-run")
- Remove redundant "Warning:" prefix from extra arguments message
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Three scripts were missed in the previous inject_env_vars migration
(commit d785571): atlanticnet/amazonq.sh, codesandbox/cline.sh, and
civo/continue.sh. These still used raw heredoc/echo patterns that
embed OPENROUTER_API_KEY directly into shell command strings without
escaping, allowing potential command injection if the API key contained
shell metacharacters (quotes, backticks, dollar signs).
Replace with inject_env_vars_ssh (Atlantic.Net, Civo) and
inject_env_vars_local (CodeSandbox) which use generate_env_config
to safely single-quote all values.
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>
Both the security team's pr-reviewer and the refactor team's pr-maintainer
now read PR comments before passing verdict. If comments indicate a PR is
superseded, duplicate, or abandoned, they close it instead of reviewing.
Security reviewer: new step 2 (comment-based triage) before staleness check,
steps renumbered 3→4 through 11→12, verdict options include closed-duplicate.
Refactor pr-maintainer: reads comments first, closes when clearly indicated,
rule updated from "NEVER close" to "only close when comments justify it".
Also updates CLAUDE.md dual-mode table: Agents → Teammates.
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These two critical shared/common.sh functions had zero test coverage despite
being used across 4+ and 9 cloud providers respectively (10+ call sites each).
extract_api_error_message tests cover:
- All JSON error field patterns (message, error, error.message, error_message, reason)
- Field priority ordering
- Fallback behavior for invalid JSON, empty input, unrecognized fields
- Real-world API response formats (Hetzner, DigitalOcean, Vultr, Contabo)
- Edge cases (special characters, unicode, arrays, null)
generic_wait_for_instance tests cover:
- Successful polling (first attempt and multi-attempt)
- IP extraction from flat and deeply nested JSON
- Timeout behavior when status never reaches target
- Continued polling when API returns errors or invalid JSON
- Polling when status matches but IP is empty
- Logging output (progress, success, timeout)
Agent: test-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
* test: add 97 tests for list command output helpers
Cover buildRetryCommand (prompt truncation at 80 chars, quote escaping,
prompt-file fallback), resolveDisplayName (null manifest fallback),
buildRecordLabel/buildRecordHint (30-char hint truncation, picker
formatting), parseAuthEnvVars (multi-var parsing, validation),
hasCloudCredentials (multi-var auth, empty/unset vars),
getImplementedClouds/getImplementedAgents (manifest filtering),
isRetryableExitCode (SSH 255 detection), formatTimestamp (edge cases),
and getStatusDescription (404 special case).
Agent: test-engineer
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* fix: import actual functions instead of duplicating them in tests
- Export formatTimestamp, buildRecordLabel, buildRecordHint from commands.ts
- Replace 11 duplicated function implementations with imports from commands.ts
- Add @clack/prompts mock (required when importing commands.ts)
- All 97 tests still pass against the real production code
Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: resolve rebase conflicts and update tests for formatRelativeTime
Merged formatRelativeTime from main, exported formatTimestamp and
buildRecordHint, updated tests to use relative time assertions.
Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
* feat: Add codesandbox/gptme
Agent: gap-filler
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: use safe quoting pattern for API key injection in gptme
Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: Add interpreter on Atlantic.Net
Agent: gap-filler
* fix: use inject_env_vars_ssh, fix README markdown, use zshrc
Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Team leaders were outputting "Continue waiting for agent results" because
the prompts used "agent" language throughout. Updated all 4 team scripts
to use "teammate" and "spawn team" terminology per the Anthropic agent
teams documentation (https://code.claude.com/docs/en/agent-teams).
Changes across refactor.sh, security.sh, discovery.sh, qa-cycle.sh:
- "agents" → "teammates" when referring to team members
- "agent teams" → "spawn teams" when referring to the coordination concept
- Preserved: Agent: commit trailers, AGENT-NAME sign-offs, subagent_type,
agent-teams URL, and "agent" as software product (AI agents)
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements Amazon Q CLI on local machine with OpenRouter integration.
Agent: gap-filler-5
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix macOS compatibility bug in Atlantic.Net API signature: `base64 -w 0`
fails on macOS (no `-w` flag); add fallback like other providers
- Replace misleading "Use 'csb' CLI dashboard" in CodeSandbox interactive
session with link to the actual web terminal at codesandbox.io/dashboard
- Soften preflight credential check prompt from "will likely fail" to
"will prompt you to authenticate" (scripts have built-in auth flows)
- Bump CLI version to 0.2.72
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Show warning when manifest is loaded from stale cache (offline fallback)
so users know the data may be outdated
- Fix list footer rerun command: reuse buildRetryCommand instead of
truncating prompts with "..." which produced broken copy-paste commands
- Show manifest cache age in "spawn version" output for troubleshooting
- Bump CLI version to 0.2.67
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 _extract_json_field and extract_api_error_message functions that
were recently extracted (PRs #673, #767) but had zero test coverage.
These are critical infrastructure used by Hetzner, DigitalOcean, Vultr,
and Contabo for API error parsing and by generic_wait_for_instance for
status polling.
Tests cover:
- _extract_json_field: basic extraction, nested fields, default values,
complex Python expressions, real-world cloud provider patterns, edge cases
- extract_api_error_message: all standard error field patterns (message,
error, error.message, error.error_message, reason), field priority order,
fallback behavior, real-world cloud provider error formats, 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>
Verify that every cloud provider's lib/common.sh correctly sources
shared/common.sh and exposes required shared functions. Tests run
each cloud's lib in a real bash subprocess to catch source chain
breaks, syntax errors, and missing function definitions.
Coverage:
- Source chain integrity for all 36 cloud lib files
- Required shared function availability (logging, OAuth, API, SSH)
- json_escape behavior (quotes, newlines, backslashes, tabs)
- validate_api_token and validate_server_name security
- calculate_retry_backoff bounds
- extract_api_error_message parsing
- Cross-cloud consistency (SSH_OPTS, API helpers)
- bash -n syntax check on all lib files
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 all required credentials (OPENROUTER_API_KEY + cloud auth vars) are
already configured, the Quick start section in `spawn <agent>` and
`spawn <cloud>` now shows a concise "credentials detected -- ready to go"
message with just the launch command, instead of showing export instructions
the user doesn't need.
Previously, the `hasCreds` variable was computed but unused in both
`printCloudQuickStart` and `cmdAgentInfo`. This change puts it to use
to give users a clear signal when they're ready to launch.
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>
Replace unsafe heredoc/echo patterns with inject_env_vars_ssh (Atlantic.Net)
and inject_env_vars_local (CodeSandbox) for API key injection. The previous
patterns embedded OPENROUTER_API_KEY values directly into shell command strings
without escaping, allowing potential command injection if the API key contained
shell metacharacters (quotes, backticks, dollar signs).
Affected scripts (11 total):
- atlanticnet: codex, continue, gemini, gptme, kilocode, opencode
- codesandbox: amazonq, gemini, goose, opencode, plandex
The safe helpers (generate_env_config) properly single-quote all values and
escape embedded single quotes, preventing shell interpretation of special chars.
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 file had 5 nearly-identical inline Node.js scripts, each repeating
the same require/init/async-IIFE/try-catch boilerplate. Extract two
shared helpers:
- _csb_sdk_eval: runs arbitrary JS with an authenticated SDK instance
- _csb_run_cmd: connects to a sandbox and runs a command (used by
run_server and interactive_session)
interactive_session was a verbatim copy of run_server — it now delegates
to run_server directly.
Net result: -96 lines, +49 lines (287 → 241 lines total).
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
- local/cline.sh: Add missing SPAWN_PROMPT non-interactive mode support,
replace manual sed -i.bak env var handling with inject_env_vars_local
(eliminates leftover .bak files), add installation verification
- local/plandex.sh: Replace manual shell config handling with
inject_env_vars_local for consistency, fix printf '%q' prompt escaping
that corrupted prompt text with literal backslashes
- local/aider.sh: Fix printf '%q' prompt escaping -- pass SPAWN_PROMPT
directly as quoted argument instead of shell-escaping it
- local/interpreter.sh: Same printf '%q' fix as aider.sh
- 7 local scripts: Standardize "Appending environment variables to
~/.zshrc..." to "Setting up environment variables..." for consistency
with all other cloud providers
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 a centralized `render_api` function that delegates to `generic_cloud_api`,
giving Render the same automatic retry logic (429/503/network errors with
exponential backoff) that all other providers already have.
- `_render_create_service`: raw curl POST -> `render_api POST`
- `_render_wait_for_service`: raw curl GET -> `render_api GET` + `_extract_json_field`
- `cleanup_server`: raw curl DELETE -> `render_api DELETE`
Also improves the wait loop with `INSTANCE_STATUS_POLL_DELAY` support and
better timeout messaging matching the standard provider pattern.
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 technical "Remediation steps:" with "How to fix:" and
"Remediation: Check <url>" with "Check your dashboard: <url>" across
14 cloud providers for clearer error guidance. Add actionable error
messages to Atlantic.Net create_server and SSH key registration failures.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Cover get_resource_name, get_validated_server_name, get_model_id_interactive,
interactive_pick, _display_and_select, and show_server_name_requirements --
all previously untested functions used by every agent/cloud script.
Tests exercise env-var bypass paths (critical for CI/non-interactive use),
validation rejection of injection attempts, boundary conditions, and menu
rendering output.
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>
Implemented local/amazonq.sh to run Amazon Q CLI directly on the user's local
machine. Uses the standard local provider pattern with OpenRouter API key
injection via OPENAI_API_KEY and OPENAI_BASE_URL environment variables.
Agent: gap-filler
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
The simplified security workflow passes github.event_name directly as
the reason parameter, which includes workflow_dispatch for manual
triggers. The trigger server was rejecting it with a 400 error.
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Simplify security workflow to match discovery/refactor pattern
Move mode-detection logic from the GitHub Actions workflow into
security.sh where it belongs. The workflow now passes github.event_name
directly as the reason parameter (like discovery.yml and refactor.yml),
and security.sh uses `gh issue view` to check labels when reason=issues.
- Remove 25-line if/elif/else reason-mapping block from security.yml
- Remove workflow_dispatch mode input (server-side handles it)
- Add `if:` label guard for issues (safe-to-work + team-building/security)
- Add `labeled` to issue trigger types
- Set cancel-in-progress: false (prevents killing long review_all runs)
- Bump cron to */5
- Handle schedule/workflow_dispatch → review_all in security.sh
- Keep backwards compat for direct team_building/triage reasons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: Add pre-cycle stale branch cleanup to security.sh
Clean up merged and stale security-related branches (team-building/*,
review-pr-*) and leftover worktrees before each cycle starts. Follows
the same pattern as qa-cycle.sh.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: Add pre-cycle stale branch cleanup to discovery.sh and refactor.sh
Each agent script now cleans up its own merged branches before starting:
- discovery.sh: add-*, impl-*, gap-filler-* branches
- refactor.sh: fix/*, refactor/*, test/*, ux/* branches
- (security.sh already added in prior commit)
- (qa-cycle.sh already had this)
Replaces the "branch pruning handled by security team" comments with
actual cleanup, following the qa-cycle.sh pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move mode-detection logic from the GitHub Actions workflow into
security.sh where it belongs. The workflow now passes github.event_name
directly as the reason parameter (like discovery.yml and refactor.yml),
and security.sh uses `gh issue view` to check labels when reason=issues.
- Remove 25-line if/elif/else reason-mapping block from security.yml
- Remove workflow_dispatch mode input (server-side handles it)
- Add `if:` label guard for issues (safe-to-work + team-building/security)
- Add `labeled` to issue trigger types
- Set cancel-in-progress: false (prevents killing long review_all runs)
- Bump cron to */5
- Handle schedule/workflow_dispatch → review_all in security.sh
- Keep backwards compat for direct team_building/triage reasons
Co-authored-by: Security Reviewer <security-reviewer@spawn.dev>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two UX improvements:
1. `spawn clouds` now shows a green "ready" indicator next to clouds where
credentials are already configured in the environment, making it immediately
clear which providers the user can use without additional setup.
2. `spawn list` now shows relative timestamps ("5 min ago", "yesterday",
"3d ago") instead of absolute dates, giving immediate temporal context.
Agent: ux-engineer
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace raw API JSON dumps with extracted error messages and actionable
troubleshooting steps for server creation and SSH key registration failures.
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>
Daytona now rejects explicit resource flags (--cpu, --memory, --disk)
when using snapshots. Switch to --class (default: small) which works
with all sandbox configurations. Explicit resource env vars are still
supported but auto-retry with --class on snapshot conflict.
Fixes#800
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>
Replace misleading "Appending environment variables to ~/.zshrc..."
with "Setting up environment variables..." to match all other cloud
providers. The old message incorrectly specified ~/.zshrc which could
confuse bash users.
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>
* feat: Add plandex on Atlantic.Net
Agent: gap-filler
* fix: address review comments for atlanticnet/plandex
- Use inject_env_vars_ssh instead of raw heredoc for env var injection
- Fix source fallback guard to match established pattern
- Add shellcheck source comment
- Fix README ordering (Plandex after OpenClaw)
- Add server details to success message
Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: B (Discovery Team) <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>