mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-22 11:24:18 +00:00
## Problem `spawn cursor local` fails on macOS with four cascading errors: ```bash chmod: /usr/local/bin/caddy: No such file or directory bash: line 4: caddy: command not found bash: /etc/hosts: Permission denied bash: line 24: setsid: command not found ``` These occur in packages/cli/src/shared/cursor-proxy.ts (setupCursorProxy and startCursorProxy). Even though local/agents.ts wires runLocal as the runServer callback, the proxy scripts it constructs were written exclusively for Linux: 1. Caddy downloads the wrong binary — `setupCursorProxy` calls `https://caddyserver.com/api/download?os=linux&arch=amd64` unconditionally. On macOS this downloads a Linux ELF binary that immediately fails to execute. 2. Caddy install path is root-owned on macOS — the script writes to `/usr/local/bin/caddy`. On macOS this directory either doesn't exist (no Homebrew) or is owned by a system process, so `chmod +x` immediately fails without sudo. 3. `/etc/hosts` is read-only without root on macOS — the domain-spoofing step runs echo `"127.0.0.1 ..." >> /etc/hosts` directly, which fails with Permission denied because `/etc/hosts` is only writable by root on macOS (unlike some Linux setups where the invoking user may own it). 4. `setsid` is Linux-only — the non-systemd fallback in startCursorProxy calls `setsid` to detach backend processes. `setsid` is a util-linux command; it doesn't ship on macOS (or BSD, or Windows). `nohup … &` is the portable equivalent. The downstream symptom of all four: Caddy never starts, the proxy is never listening, and Cursor's auth exchange fails — which surfaces as "The provided API key is invalid" even when the key is valid. ## Fix - OS/arch detection — query `process.platform` and `process.arch` (already available in Bun) to select the correct Caddy download (os=darwin, arch=arm64 | amd64 for macOS; os=linux for Linux). - User-writable install path — install Caddy to `~/.local/bin/caddy` (guaranteed writable, always exists after `mkdir -p`) instead of `/usr/local/bin/`. Add `~/.local/bin` to `PATH` in the execution environment. - `sudo` for `/etc/hosts` — prefix the `sed` and `echo` host entries with `sudo`. Wrap in a try/catch with a clear fallback message if `sudo` isn't available (some sandboxed environments). - Replace `setsid` with `nohup` — swap `setsid $NODE ...` for `nohup $NODE ... < /dev/null >> /tmp/cursor-proxy.log 2>&1 &` in the non-systemd branch. `nohup` is POSIX and present on macOS, Linux, and BSD. ## Affected code - `packages/cli/src/shared/cursor-proxy.ts` — `installCaddy` shell fragment, `hosts-spoofing` fragment, `startCursorProxy` non-systemd branch - No changes to the CloudRunner interface, tests, or other agents ## Testing Tested on macOS (Apple Silicon, M3) with SPAWN_CLI_DIR pointing at a local build: - `spawn cursor local` completes all setup steps without errors - Caddy starts on port 443, unary backend on 18644, bidi backend on 18645 - Cursor authenticates and routes completions through OpenRouter |
||
|---|---|---|
| .. | ||
| cli | ||
| shared | ||