From a20451df9d8caa94e280ab6a68073d78d1664ff9 Mon Sep 17 00:00:00 2001 From: Ahmed Abushagur Date: Wed, 25 Mar 2026 16:04:11 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20installSpawnCli=20fails=20on=20Sprite=20?= =?UTF-8?q?=E2=80=94=20bun=20shim=20doesn't=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprite has a bun shim at /.sprite/bin/bun that delegates to $HOME/.bun/bin/bun, but that binary doesn't exist on fresh VMs. `command -v bun` returns true (finds the shim) so the install script skips bun installation, then bun fails when actually invoked. Fixed in two places: - installSpawnCli: source shell profiles, test `bun --version` (not just existence), and install bun fresh if it doesn't work - install.sh: replace `command -v bun` with `bun --version` to detect broken shims Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/cli/package.json | 2 +- packages/cli/src/shared/orchestrate.ts | 18 ++++++++++++------ sh/cli/install.sh | 7 +++++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index db51b7081..5d32d887c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "0.26.4", + "version": "0.26.5", "type": "module", "bin": { "spawn": "cli.js" diff --git a/packages/cli/src/shared/orchestrate.ts b/packages/cli/src/shared/orchestrate.ts index 949d6c5a2..50da47f29 100644 --- a/packages/cli/src/shared/orchestrate.ts +++ b/packages/cli/src/shared/orchestrate.ts @@ -115,13 +115,19 @@ function wrapWithRestartLoop(cmd: string): string { /** Install the spawn CLI on a remote VM. */ export async function installSpawnCli(runner: CloudRunner): Promise { logStep("Installing spawn CLI on VM..."); + // Build PATH explicitly — non-interactive bash skips .bashrc (PS1 guard), + // and some platforms (Sprite) have a broken bun shim that finds via + // `command -v` but doesn't actually work. We prepend all known bun + // locations so the real binary is found first, then test `bun --version` + // (not just existence) and install bun fresh if it doesn't work. + const installCmd = [ + 'export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}"', + 'export PATH="$BUN_INSTALL/bin:$HOME/.local/bin:$HOME/.npm-global/bin:/.sprite/languages/bun/bin:/usr/local/bin:$PATH"', + 'if ! bun --version >/dev/null 2>&1; then curl -fsSL https://bun.sh/install | bash && export PATH="$HOME/.bun/bin:$PATH"; fi', + "curl -fsSL https://openrouter.ai/labs/spawn/cli/install.sh | bash", + ].join("; "); const result = await asyncTryCatch(() => - withRetry( - "spawn CLI install", - () => wrapSshCall(runner.runServer("curl -fsSL https://openrouter.ai/labs/spawn/cli/install.sh | bash")), - 2, - 5, - ), + withRetry("spawn CLI install", () => wrapSshCall(runner.runServer(installCmd)), 2, 5), ); if (!result.ok) { logWarn("Spawn CLI install failed — recursive spawning will not be available on this VM"); diff --git a/sh/cli/install.sh b/sh/cli/install.sh index 8a804a576..dc1488c11 100755 --- a/sh/cli/install.sh +++ b/sh/cli/install.sh @@ -305,8 +305,11 @@ _SPAWN_ORIG_PATH="${PATH}" export BUN_INSTALL="${BUN_INSTALL:-${HOME}/.bun}" export PATH="${BUN_INSTALL}/bin:${HOME}/.local/bin:${PATH}" -if ! command -v bun &>/dev/null; then - log_step "bun not found. Installing bun..." +# Check that bun exists AND actually works. Some platforms (e.g. Sprite) +# have a bun shim that delegates to $HOME/.bun/bin/bun — if that binary +# doesn't exist, `command -v bun` returns 0 but `bun --version` fails. +if ! bun --version &>/dev/null; then + log_step "bun not found or not working. Installing bun..." # Download the bun installer to a temp file and verify its SHA-256 hash # before executing. This defends against a compromised bun.sh CDN or