Commit graph

10 commits

Author SHA1 Message Date
A
9e309f1ff5
fix(security): escape single quotes in standard SSH enter-agent path (#1902)
The standard SSH path in cmdEnterAgent() interpolated remoteCmd into a
single-quoted bash -lc wrapper without escaping embedded single quotes.
If launch_cmd (from history.json) or the manifest's launch/pre_launch
fields contained a single quote, the shell quoting would break, allowing
unintended command execution on the remote server.

The Fly.io path already had this escaping (PR #1880, #1893) but the
generic SSH fallback did not. This adds the same replace(/'/g, "'\\''")
pattern used everywhere else in the codebase.

Agent: security-auditor

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 22:06:13 -08:00
A
40417d845d
fix: use single-quote escaping for restart loop in interactiveSession (#1893)
JSON.stringify double-quoting caused two bugs in the restart wrapper:
1. Literal \n instead of newlines (bash doesn't interpret \n in "...")
2. Shell variables ($vars) expanded to empty strings before script ran

Affected clouds: fly, gcp, hetzner, digitalocean, aws.
Daytona already had the correct single-quote escaping.

Co-authored-by: spawn-bot <spawn-bot@openrouter.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 18:47:23 -05:00
A
d423ea57d5
refactor: deduplicate pickToTTY as wrapper around pickToTTYWithActions (#1891)
Fixes #1890

Agent: complexity-hunter

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-24 17:48:57 -05:00
A
5b9ceef060
perf: replace child_process.spawn with Bun.spawn for interactive sessions (#1888)
Using Node's child_process.spawn() to launch interactive SSH/shell sessions
from inside a Bun process adds unnecessary overhead: an extra process fork,
PTY negotiation indirection, and a forced Bun→Node stdio context switch.

Switch all interactiveSession() functions to Bun.spawn() with
stdio: ["inherit","inherit","inherit"], which hands off file descriptors
directly without forking a Node wrapper process.

Also removes the 500ms hardcoded sleep in orchestrate.ts that was a
band-aid for the old child_process handoff latency. The synchronous
prepareStdinForHandoff() is sufficient on its own.

Affected clouds: hetzner, aws, gcp, digitalocean, fly, daytona, sprite, local
Also fixes runInteractiveCommand() in commands.ts (spawn connect).

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 15:17:53 -05:00
A
2a1ed4164e
fix(gcp): add network/subnet flags to fix custom VPC subnet mode (#1883)
GCP instance creation was failing with 'Invalid value for field
resource.networkInterfaces[0].subnetwork' when the project VPC uses
custom subnet mode. Add --network and --subnet flags defaulting to
'default', with GCP_NETWORK and GCP_SUBNET env var overrides for
custom VPC setups.

Fixes #1882

Agent: issue-fixer

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-24 14:27:46 -05:00
A
0edc588629
fix(daytona): use single-quote escaping in interactiveSession to prevent shell injection (#1880)
Replace JSON.stringify double-quoting with single-quote escaping for the
cmd argument in interactiveSession(). Double-quoted strings in bash allow
$() and ${} expansion, making the previous pattern vulnerable to injection
if cmd ever contained shell metacharacters. Single-quoted strings prevent
ALL shell expansion, matching the defense-in-depth approach Fly already uses.

Fixes #1879

Agent: issue-fixer

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-24 12:28:26 -05:00
A
c701b745ab
fix: add process supervision restart loop for agents on cloud VMs (#1862)
When an agent process dies on a cloud VM (SIGTERM, OOM, crash), it now
automatically restarts after 5 seconds, up to 10 times. Clean exits
(code 0) break out immediately. Local execution is unaffected.

Fixes #1860

Agent: code-health

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-24 02:51:31 -05:00
A
9f6bc423ac
fix: add swap space before ZeroClaw install to prevent OOM on nano instances (#1851)
* fix: add swap space before ZeroClaw install to prevent OOM on nano instances

ZeroClaw's Rust compilation gets OOM-killed on nano_3_0 (512 MB) — build
fails at a random dependency each run. Add ensureSwapSpace() that creates
a 1 GB swap file before running the installer:

- Idempotent: skips silently if swap already exists
- Non-fatal: logs a warning if sudo fails (larger instances won't need it)
- Timeout bumped from 5 min to 10 min (swap-backed builds are slower)
- Defense-in-depth: --prefer-prebuilt avoids compilation in the common
  case, but fallback source builds still need memory

Fixes #1840

Agent: issue-fixer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add input validation to ensureSwapSpace() to prevent command injection

Validate sizeMb is a positive integer before interpolating into shell
commands, as requested in security review.

Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-23 23:12:13 -08:00
A
f5f020d250
feat: Result monad in shared + Claude Code fixtures + SPA Result adoption (#1858)
* refactor: split SPA into helpers + main, add build script and tests

Split slack-bot.ts into helpers.ts (pure functions) and main.ts (entry
point) for testability. Add build.ts to bundle SPA into spa.js. Add
spa.test.ts with 19 tests covering stream parsing and text helpers.

Improved streaming: tool_use and tool_result events get their own Slack
messages instead of concatenating everything into one. Prompt is passed
via stdin to avoid CLI flag parsing issues with user content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: drop build.ts — run main.ts directly via bun

Bun runs TypeScript natively, no bundling step needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: move Result monad to shared, add Claude Code fixtures, use Result in SPA

- Move Result type/Ok/Err from packages/cli/src/shared/result.ts to
  packages/shared/src/result.ts and re-export from @openrouter/spawn-shared
- Update CLI imports (ui.ts) to use the shared package
- Add fixtures/claude-code/ with realistic stream-json events covering
  all event types (assistant text, tool_use, user tool_result, result)
- Refactor SPA helpers to return Result<T> instead of throwing/returning null:
  loadState() → Result<State>, saveState() → Result<void>,
  downloadSlackFile() → Result<string>, addMapping() → Result<void>
- Update main.ts call sites to handle Result returns
- Update SPA tests to import events from fixtures and test Result returns
- Bump CLI version 0.10.0 → 0.10.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: biome format issues in aws.test.ts, aws.ts, daytona.ts

Expand inline objects/arrays to multi-line format to satisfy biome
formatter rules. No logic changes.

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>
2026-02-23 22:48:51 -08:00
A
65f6f1be32
feat: Bun workspace monorepo — packages/cli + packages/shared (#1853)
Restructure the repo as a Bun workspace monorepo:

- Move cli/ → packages/cli/
- Create packages/shared/ (@openrouter/spawn-shared) with type-guards and parse utilities
- Add root package.json with workspace configuration
- Update all CLI imports to use @openrouter/spawn-shared
- Deduplicate toRecord/toObjectArray helpers from 4 cloud modules
- Update SPA (slack-bot) to use shared package instead of local toObj()
- Update 48 agent shell scripts for new packages/cli/ path
- Update install.sh, install.ps1, e2e, and test scripts
- Update all GitHub workflows, .gitignore, pre-commit hooks
- Update CLAUDE.md, README.md, and skill prompt references
- Pin all dependency versions (no ^ ranges)
- Bump CLI version 0.9.1 → 0.10.0

All 1908 tests pass. Lint clean. All 8 cloud bundles build.

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-23 22:07:05 -08:00
Renamed from cli/package.json (Browse further)