Commit graph

27 commits

Author SHA1 Message Date
L
6633873ccc
refactor: replace Python with jq in Hetzner lib, fix /lab → /labs URLs (#827)
Hetzner lib: replace all Python JSON parsing with jq. Uses the
/datacenters API as the authoritative source for server type
availability (server_types.available), cross-referenced with
/server_types for specs and pricing. jq is auto-installed if missing.

URLs: update openrouter.ai/lab/spawn → openrouter.ai/labs/spawn
across all READMEs and CLI source.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-12 23:14:11 -08:00
A
6c7ced54dd
fix: replace log_warn with log_step/log_info for non-warning messages (#604)
Agent: ux-engineer

Many shell scripts misused log_warn (yellow) for normal progress/status
messages, making routine operations appear alarming. This fixes 59 files:

- Progress messages -> log_step (cyan): "Injecting environment variables...",
  "Attaching volume...", "Powering on instance...", "Retrieving server IP...",
  "Terminating sandbox/server...", "Creating datacenter...", "Importing SSH key...",
  "Deleting service/app...", "Modal not authenticated. Running setup..."
- Informational notices -> log_info (green): WhatsApp QR code authentication
  notices (30 nanoclaw scripts), codespace delete hints (14 scripts),
  "Appending environment variables to ~/.zshrc..." (6 local scripts),
  credential prompt hints, package update skipped, app reuse notices

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-12 03:24:30 -08:00
A
11cf3a188e
refactor: replace custom credential/polling logic with shared helpers in kamatera and ovh (#564)
Kamatera: Replace _load_kamatera_config, _validate_kamatera_credentials, and
ensure_kamatera_token (62 lines of custom env/config/prompt/validate/save logic)
with ensure_multi_credentials (5 lines).

OVH: Replace _ovh_prompt_credentials, ensure_ovh_authenticated (72 lines of
custom credential management) with ensure_multi_credentials (8 lines).
Replace wait_for_ovh_instance (38 lines of custom polling with backoff) with
generic_wait_for_instance (8 lines).

Net: -175 lines, same behavior, consistent patterns across providers.

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>
2026-02-11 17:54:23 -08:00
A
7c693db35b
refactor: extract check_ssh_key_by_fingerprint into shared helper (#552)
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>
2026-02-11 16:12:07 -08:00
A
c8d7ea23e6
refactor: simplify BinaryLane wait loop and fix log_warn in 7 cloud polling loops (#538)
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>
2026-02-11 14:59:51 -08:00
A
be5f9f1087
refactor: extract get_validated_server_name to eliminate 18 duplicate get_server_name functions (#535)
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>
2026-02-11 14:42:09 -08:00
A
0835b35a36
fix: use log_step (cyan) for progress messages instead of log_warn (yellow) (#534)
~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>
2026-02-11 14:37:43 -08:00
A
8e5f9d46d4
refactor: reduce complexity in try_oauth_flow and ensure_ovh_authenticated (#454)
Extract helpers from the two longest functions in shared code:

- try_oauth_flow() (60 -> 37 lines): Extract _init_oauth_session() for
  temp dir + CSRF state setup, and _await_oauth_callback() for browser
  open + timeout handling
- ensure_ovh_authenticated() (67 -> 28 lines): Extract _ovh_prompt_credentials()
  for the interactive credential prompting, validation, and saving

Agent: complexity-hunter

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-11 06:28:54 -08:00
A
c1e009a66e
refactor: replace custom config loaders with shared helpers in 3 cloud libs (#444)
Replace inline Python config loading (`_load_*_config`) and custom JSON
save functions (`_save_*_config`) in OVH, UpCloud, and Contabo with the
shared `_load_json_config_fields` and `_save_json_config` helpers.

Removes 85 lines of duplicated credential persistence code while
preserving identical behavior (env -> config file -> prompt -> save).

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>
2026-02-11 04:56:01 -08:00
A
fdc5d5e58b
refactor: extract shared SSH helpers to eliminate ~410 lines of duplication (#429)
Add ssh_run_server, ssh_upload_file, ssh_interactive_session, and
ssh_verify_connectivity to shared/common.sh. These four functions
were copy-pasted identically across 21 cloud provider lib files,
differing only in SSH username (root vs ubuntu).

Providers now set SSH_USER and delegate to the shared helpers via
one-line wrappers, reducing each provider's lib by ~20 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>
2026-02-11 03:45:18 -08:00
A
6debf956a3
refactor: Extract helpers from complex OVH and Latitude functions (#384)
OVH: Extract _ovh_extract_public_ipv4() and _ovh_extract_status() from
wait_for_ovh_instance() to reduce inline Python and improve readability.

Latitude: Extract _latitude_extract_error(), _latitude_get_ssh_key_ids(),
and _latitude_build_server_body() from create_server() and
latitude_register_ssh_key(). Deduplicates error extraction logic used in
two places.

Agent: complexity-hunter

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-11 01:00:42 -08:00
A
81bab47a74
fix: Escape API keys in continue.sh JSON configs to prevent injection (#374)
Replace vulnerable heredoc patterns across 27 continue.sh scripts with
setup_continue_config() helper that uses json_escape() + upload_config_file()
to safely handle API keys containing special characters like quotes or braces.

Also fix _save_token_to_config() in shared/common.sh which had the same
unescaped heredoc vulnerability for local token storage.

Relates to #104

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>
2026-02-11 00:13:19 -08:00
Ahmed Abushagur
8b9f9a0e5a
QA-Bot setup (#335)
* feat: testing

* feat: auto-fix dead apis

* fix: mock works

* feat: new fixtures

* fix: more clouds tested

* fix: dry run fix

* fix: civo valid size

* fix: civo result wait

* feat: fixtures

* feat: per cloud agent
2026-02-10 19:51:07 -08:00
A
f74b23d679
feat: Implement ovh/continue.sh script (#333)
Add Continue CLI agent deployment script for OVHcloud. Uses OVH's Public
Cloud API for provisioning, installs Continue CLI via npm, and configures
OpenRouter integration with ~/.continue/config.json.

Agent: gap-filler-ovh-continue

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
2026-02-10 19:17:15 -08:00
A
0826005239
refactor: Decompose long functions in Vultr and OVH providers (#228)
Vultr create_server (93 lines) decomposed into:
- _vultr_build_instance_body: builds JSON request body
- _wait_for_vultr_instance: polls until instance is active
Also fixed bash 3.x compat issue: ((attempt++)) -> attempt=$((attempt + 1))

OVH create_ovh_instance (80 lines) decomposed into:
- _ovh_resolve_resources: resolves image/flavor/SSH key IDs
- _ovh_build_instance_body: builds JSON request body

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>
2026-02-10 12:48:39 -08:00
Sprite
cf46b42e3f fix: Remove double-quoting in json_escape printf callers
json_escape() returns a fully-quoted JSON string (e.g. "value") via
Python's json.dumps(). Callers using printf templates were wrapping
the result in additional quotes ("%s"), producing invalid JSON like
""value"". Remove the redundant quotes from all printf format strings
so json_escape's quotes are used directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-10 20:04:30 +00:00
A
009f3454fc
feat: Add Cline and gptme on OVHcloud (#126)
Implement ovh/cline.sh and ovh/gptme.sh using OVH
primitives. Both scripts provision an OVHcloud instance,
install the agent, inject OpenRouter credentials, and
launch an interactive session.

Agent: gap-filler

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 20:18:28 -08:00
A
05fa33ead3
feat: Add Goose and Open Interpreter on OVHcloud (#123)
Implement ovh/goose.sh and ovh/interpreter.sh using OVH
primitives. Both scripts provision an OVHcloud instance,
install the agent, inject OpenRouter credentials, and
launch an interactive session.

Agent: gap-filler-2

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 20:17:21 -08:00
A
9efa451326
feat: Add OpenCode and Plandex on OVHcloud (#122)
Implement ovh/opencode.sh and ovh/plandex.sh using OVH
primitives. Both scripts provision an OVHcloud instance,
install the agent, inject OpenRouter credentials, and
launch an interactive session.

Agent: gap-filler-5

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 20:17:02 -08:00
A
9b4cb00a40
feat: Add Gemini CLI and Amazon Q CLI on OVHcloud (#121)
Implement ovh/gemini.sh and ovh/amazonq.sh using OVH
primitives. Both scripts provision an OVHcloud instance,
install the agent, inject OpenRouter credentials, and
launch an interactive session.

Agent: gap-filler-3

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 20:16:22 -08:00
A
c302bc010d
feat: Add OpenClaw and NanoClaw on OVHcloud (#120)
Implement ovh/openclaw.sh and ovh/nanoclaw.sh using OVH
primitives from lib/common.sh. Both scripts provision an
OVHcloud instance, install the agent, inject OpenRouter
credentials, and launch an interactive session.

Agent: gap-filler-1

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 20:16:12 -08:00
A
16ee8e3461
refactor: Extract helpers from complex cloud provider functions (#118)
- kamatera: Replace 65-line kamatera_api() with generic_cloud_api_custom_auth (65 -> 8 lines)
- kamatera: Extract _load_kamatera_config() and _validate_kamatera_credentials() from ensure_kamatera_token()
- ovh: Extract _load_ovh_config() and _save_ovh_config() from ensure_ovh_authenticated() (79 -> 47 lines)
- upcloud: Extract _load_upcloud_config() from ensure_upcloud_credentials() (69 -> 49 lines)
- upcloud: Extract _wait_for_upcloud_server_ip() from create_server() (58 -> 39 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>
2026-02-09 19:51:31 -08:00
A
e533a0c365
feat: Add kilocode scripts for runpod, upcloud, binarylane, genesiscloud, latitude, ovh, kamatera (#115)
Agent: gap-filler

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 19:46:31 -08:00
A
a24dc101e3
fix: Eliminate heredoc injection, eval, and API key exposure (#108)
- Replace unquoted heredocs with printf + json_escape for all JSON
  config files containing credentials (8 cloud providers + shared lib)
- Replace eval with printf -v for safe indirect variable assignment
- Move RunPod API key from URL query param to api-key header

Fixes #104, Fixes #105, Fixes #106

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 11:19:34 -08:00
A
27973bfb28
refactor: Reduce complexity across CLI and cloud provider libs (#103)
* refactor: Extract duplicated prompt flag parsing into extractFlagValue helper

The --prompt and --prompt-file argument extraction in main() shared identical
patterns for flag detection, value validation, and args splicing. Extracted
into a reusable extractFlagValue() function that handles all three concerns.

Agent: complexity-hunter

* refactor: Consolidate multiple python3 JSON reads into single calls

OVH, Kamatera, and UpCloud each spawned separate python3 processes to
read different fields from the same JSON config file. Consolidate into
a single python3 call per file, printing all fields at once and reading
them with bash read. Also fixes OVH using string interpolation for the
file path instead of the safer sys.argv[1] pattern.

Agent: complexity-hunter

* refactor: Extract flyctl auth and token validation from ensure_fly_token

Split the 75-line ensure_fly_token into focused helpers:
- _try_flyctl_auth: encapsulates flyctl CLI token retrieval
- _validate_fly_token: encapsulates API validation with error reporting

The main function is now a clear sequential flow of token source attempts.

Agent: complexity-hunter

* refactor: Deduplicate retry backoff logic in kamatera_api

The two error branches (network error and HTTP 429/503) had identical
interval update and attempt increment code. Restructure with early
return for success, then unified backoff at the end of the loop.

Agent: complexity-hunter

* refactor: Remove unnecessary async IIFE wrapper in validateAndGetAgent

The function wrapped its body in `return (async () => { ... })()` when
it can simply be declared as `async function` directly.

Agent: complexity-hunter

---------

Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
2026-02-09 10:26:03 -08:00
A
b0f924b511
fix: Prevent Python/shell injection via env vars and triple-quote strings (#102)
- Fix triple-quote injection in SSH keys (Scaleway, UpCloud), userdata
  (BinaryLane), init scripts (Civo, Kamatera), and GraphQL queries
  (RunPod) by passing data via stdin/json_escape instead of inline
  string interpolation
- Add input validation for all cloud provider env vars (region, type,
  plan, etc.) using validate_region_name/validate_resource_name to block
  shell metacharacters before they reach Python string interpolation
- Validate Modal image name as Python identifier to prevent code injection
- Validate numeric env vars (RAM, GPU count, disk size) across all providers

Affects: 19 cloud provider lib/common.sh files
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>
2026-02-09 10:22:39 -08:00
A
a49c0874a9
feat: Add OVHcloud provider with 3 agents (#93)
Add OVHcloud Public Cloud as a new cloud provider with signature-based
API authentication (Application Key + Secret + Consumer Key).

Implements:
- ovh/lib/common.sh with OVH API wrapper, instance lifecycle, SSH key management
- ovh/claude.sh, ovh/aider.sh, ovh/codex.sh agent scripts
- manifest.json entries for all 13 agents (3 implemented, 10 missing)
- ovh/README.md with setup instructions

OVH defaults: d2-2 flavor, GRA7 region, Ubuntu 24.04

Agent: cloud-scout

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-09 09:40:28 -08:00