fix(spawn): resolve bun executable with PATH fallback#8
Merged
Conversation
Closes #6. Reported by Axel on macOS: starting the telegram bridge crashed with `Error: ENOENT: no such file or directory, posix_spawn '/Users/axelneff/.bun/bin/bun'`. Both child-process spawn sites in the server hardcode the path that launched the running interpreter (`process.execPath`): - bridge-supervisor.ts:102 — spawning the telegram bridge subprocess - index.ts:242 — `scheduleRestart` re-execing the deck server That path is the correct binary 99% of the time but captures the bun location AT DECK BOOT — not 'wherever bun is now.' If the user reinstalls bun via Homebrew / asdf / mise after the deck started, or uninstalls the official-installer copy at `~/.bun/bin/bun`, `process.execPath` still references the dead path. `Bun.spawn` does NOT search PATH for cmd[0]; it goes straight to posix_spawn and ENOENTs. New `apps/server/src/runtime-bun.ts` adds `resolveBunExecutable()`: 1. Try `process.execPath` — fast path, exists for normal users. 2. Fall back to `Bun.which("bun")` — searches PATH the way the user's shell would. 3. Throw a clear actionable error if neither resolves. Memoized for the process lifetime. Both spawn sites now route through this resolver. 4 new tests covering the existing-path case, memoization, the stale- execPath fallback, and the both-missing error path. Server suite still green (177/177), typecheck across 4 packages clean. Out of scope: - Periodically re-validating the cached path (a bun binary that moves mid-deck-run is too rare to engineer for; just restart the deck). - Telegram bridge UI improvements to surface the resolution failure more clearly than the raw posix_spawn error. The error message is already actionable; UI polish is separate.
bjb2
added a commit
that referenced
this pull request
May 29, 2026
…fixes See CHANGELOG.md for the full release notes. Bumps all 4 package.json versions to 0.6.0 in lockstep (root, server, web, protocol). Adds docs/upgrading.md as the canonical place for version-by-version migration notes — explicitly documents that the new onboarding wizard silently settles for existing users (any session OR moved welcome task short-circuits the gate), so this is a non-breaking upgrade. Headline changes since v0.5.0: - Onboarding wizard at /onboarding for fresh installs (#9) - Model picker subscription badge + placeholder-key suppression + 401-recovery hint (#7, closes #4) - OAuth flow 5-min timeout + stale eviction + drained cancel (#7, closes #5) - Bun executable PATH fallback (#8, closes #6) - README install section rewritten + LF normalization + private template stash on pack 177 -> 181 server tests (4 new from user's parallel Windows rename-fix WIP that landed; my onboarding work adds 4 of those). Typecheck clean across 4 packages.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6.
The bug
Reported by Axel on macOS. Starting the telegram bridge crashed with:
That path is
~/.bun/bin/bun— the default install location for the official Bun installer. But the file isn't there. Most likely: Axel installed Bun via Homebrew (or asdf/mise/proto) after the deck started, and the original~/.bun/bin/bunwas gone or moved. The deck server captured the old path at boot viaprocess.execPathand kept using it for child spawns.Root cause
Two spots in the server spawn Bun child processes using
process.execPathdirectly:apps/server/src/bridge-supervisor.ts:102apps/server/src/index.ts:242scheduleRestartre-execs the deck serverprocess.execPathis the path to the binary that started the current interpreter — captured AT PROCESS START, not "wherever bun lives now."Bun.spawndoes NOT search PATH forcmd[0]; it goes straight to posix_spawn / CreateProcess andENOENTs when the captured path is dead.Fix
New
apps/server/src/runtime-bun.tswithresolveBunExecutable():process.execPathfirst — fast path, correct for normal users.Bun.which("bun")— searches PATH the way the user's shell would, finds wherever Bun lives now.Memoized for the process lifetime (a working Bun binary doesn't move mid-process). Both spawn sites route through the resolver.
Verification
Bun.which, both-missing throws with clear errorFiles touched
Out of scope
posix_spawnerror (the new error message is already actionable; UI work is separate)