fix(install): find bun at standard install locations when PATH misses it (#762)

Fixes #707. shutil.which first, then ~/.bun/bin and the usual Homebrew, Linuxbrew, ~/.local/bin and /usr/local/bin locations, bun.exe on Windows, executable check on POSIX; the resolved path is used for every bun call and its directory is prepended to PATH for bun's own children.
This commit is contained in:
Ahmed authored and GitHub committed 2026-11-03 20:20:27 +01:00
1 parent a813602972
commit 87d1857139
2 files changed
+91 -4

No files matched your search

+38 -4
View File
@@ -30,6 +30,7 @@ install failed.
import argparse
import json
import os
import shutil
import subprocess
import sys
@@ -96,6 +97,30 @@ def install(cli_dirs: list[Path], bun: str, dry_run: bool, root: Path = ROOT, ru
return 0
_BUN_CANDIDATE_DIRS = (
"~/.bun/bin", # default for bun.sh installer (curl -fsSL https://bun.sh/install | bash)
"/opt/homebrew/bin", # Homebrew on Apple Silicon macOS
"/usr/local/bin", # Homebrew on Intel macOS / standard Linux
"/home/linuxbrew/.linuxbrew/bin", # Linuxbrew system
"~/.linuxbrew/bin", # Linuxbrew user
"~/.local/bin", # pipx / user local
"/usr/bin", # distro packages
)
def find_bun(candidate_dirs: tuple[str, ...] = _BUN_CANDIDATE_DIRS) -> str | None:
"""Return `bun` on PATH, or at a standard install location."""
found = shutil.which("bun")
if found:
return found
binary = "bun.exe" if sys.platform == "win32" else "bun"
for dir_path in candidate_dirs:
candidate = Path(dir_path).expanduser() / binary
if candidate.is_file() and (sys.platform == "win32" or os.access(candidate, os.X_OK)):
return str(candidate)
return None
def _force_utf8_output() -> None:
"""Write UTF-8 whatever the host's default encoding is (a fork's portal name may not be ASCII)."""
for stream in (sys.stdout, sys.stderr):
@@ -104,20 +129,29 @@ def _force_utf8_output() -> None:
reconfigure(encoding="utf-8")
def main() -> int:
def main(argv=None) -> int:
_force_utf8_output()
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("--dry-run", action="store_true", help="list what would be installed, run nothing")
args = ap.parse_args()
args = ap.parse_args(argv)
cli_dirs = discover()
if not cli_dirs:
print("No portal CLIs found under .agents/skills/*/cli/ - nothing to install.")
return 0
bun = shutil.which("bun")
bun = find_bun()
if not bun and not args.dry_run:
print("bun is not on PATH. Install it from https://bun.sh, open a new shell, and re-run.")
print(
"bun was not found on PATH and was not found at any of the usual install locations.\n"
' - installed via bun.sh? export PATH="$HOME/.bun/bin:$PATH"\n'
" - installed via Homebrew/Linuxbrew? brew install bun\n"
" - installed elsewhere? reinstall to a directory on PATH"
)
return 1
if bun:
bun_dir = str(Path(bun).parent)
if bun_dir not in os.environ.get("PATH", "").split(os.pathsep):
os.environ["PATH"] = bun_dir + os.pathsep + os.environ.get("PATH", "")
return install(cli_dirs, bun or "bun", args.dry_run)