fix(browser): add termux PATH fallbacks
Refactor browser tool PATH construction to include Termux directories (/data/data/com.termux/files/usr/bin, /data/data/com.termux/files/usr/sbin) so agent-browser and npx are discoverable on Android/Termux. Extracts _browser_candidate_path_dirs() and _merge_browser_path() helpers to centralize PATH construction shared between _find_agent_browser() and _run_browser_command(), replacing duplicated inline logic. Also fixes os.pathsep usage (was hardcoded ':') for cross-platform correctness. Cherry-picked from PR #9846.
This commit is contained in:
@@ -94,11 +94,21 @@ except ImportError:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Standard PATH entries for environments with minimal PATH (e.g. systemd services).
|
||||
# Includes macOS Homebrew paths (/opt/homebrew/* for Apple Silicon).
|
||||
_SANE_PATH = (
|
||||
"/opt/homebrew/bin:/opt/homebrew/sbin:"
|
||||
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
# Includes Android/Termux and macOS Homebrew locations needed for agent-browser,
|
||||
# npx, node, and Android's glibc runner (grun).
|
||||
_SANE_PATH_DIRS = (
|
||||
"/data/data/com.termux/files/usr/bin",
|
||||
"/data/data/com.termux/files/usr/sbin",
|
||||
"/opt/homebrew/bin",
|
||||
"/opt/homebrew/sbin",
|
||||
"/usr/local/sbin",
|
||||
"/usr/local/bin",
|
||||
"/usr/sbin",
|
||||
"/usr/bin",
|
||||
"/sbin",
|
||||
"/bin",
|
||||
)
|
||||
_SANE_PATH = os.pathsep.join(_SANE_PATH_DIRS)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
@@ -123,6 +133,28 @@ def _discover_homebrew_node_dirs() -> tuple[str, ...]:
|
||||
pass
|
||||
return tuple(dirs)
|
||||
|
||||
|
||||
def _browser_candidate_path_dirs() -> list[str]:
|
||||
"""Return ordered browser CLI PATH candidates shared by discovery and execution."""
|
||||
hermes_home = get_hermes_home()
|
||||
hermes_node_bin = str(hermes_home / "node" / "bin")
|
||||
return [hermes_node_bin, *list(_discover_homebrew_node_dirs()), *_SANE_PATH_DIRS]
|
||||
|
||||
|
||||
def _merge_browser_path(existing_path: str = "") -> str:
|
||||
"""Prepend browser-specific PATH fallbacks without reordering existing entries."""
|
||||
path_parts = [p for p in (existing_path or "").split(os.pathsep) if p]
|
||||
existing_parts = set(path_parts)
|
||||
prefix_parts: list[str] = []
|
||||
|
||||
for part in _browser_candidate_path_dirs():
|
||||
if not part or part in existing_parts or part in prefix_parts:
|
||||
continue
|
||||
if os.path.isdir(part):
|
||||
prefix_parts.append(part)
|
||||
|
||||
return os.pathsep.join(prefix_parts + path_parts)
|
||||
|
||||
# Throttle screenshot cleanup to avoid repeated full directory scans.
|
||||
_last_screenshot_cleanup_by_dir: dict[str, float] = {}
|
||||
|
||||
@@ -895,21 +927,10 @@ def _find_agent_browser() -> str:
|
||||
_agent_browser_resolved = True
|
||||
return which_result
|
||||
|
||||
# Build an extended search PATH including Homebrew and Hermes-managed dirs.
|
||||
# This covers macOS where the process PATH may not include Homebrew paths.
|
||||
extra_dirs: list[str] = []
|
||||
for d in ["/opt/homebrew/bin", "/usr/local/bin"]:
|
||||
if os.path.isdir(d):
|
||||
extra_dirs.append(d)
|
||||
extra_dirs.extend(_discover_homebrew_node_dirs())
|
||||
|
||||
hermes_home = get_hermes_home()
|
||||
hermes_node_bin = str(hermes_home / "node" / "bin")
|
||||
if os.path.isdir(hermes_node_bin):
|
||||
extra_dirs.append(hermes_node_bin)
|
||||
|
||||
if extra_dirs:
|
||||
extended_path = os.pathsep.join(extra_dirs)
|
||||
# Build an extended search PATH including Hermes-managed Node, macOS
|
||||
# versioned Homebrew installs, and fallback system dirs like Termux.
|
||||
extended_path = _merge_browser_path("")
|
||||
if extended_path:
|
||||
which_result = shutil.which("agent-browser", path=extended_path)
|
||||
if which_result:
|
||||
_cached_agent_browser = which_result
|
||||
@@ -924,10 +945,10 @@ def _find_agent_browser() -> str:
|
||||
_agent_browser_resolved = True
|
||||
return _cached_agent_browser
|
||||
|
||||
# Check common npx locations (also search extended dirs)
|
||||
# Check common npx locations (also search the extended fallback PATH)
|
||||
npx_path = shutil.which("npx")
|
||||
if not npx_path and extra_dirs:
|
||||
npx_path = shutil.which("npx", path=os.pathsep.join(extra_dirs))
|
||||
if not npx_path and extended_path:
|
||||
npx_path = shutil.which("npx", path=extended_path)
|
||||
if npx_path:
|
||||
_cached_agent_browser = "npx agent-browser"
|
||||
_agent_browser_resolved = True
|
||||
@@ -1046,24 +1067,9 @@ def _run_browser_command(
|
||||
|
||||
browser_env = {**os.environ}
|
||||
|
||||
# Ensure PATH includes Hermes-managed Node first, Homebrew versioned
|
||||
# node dirs (for macOS ``brew install node@24``), then standard system dirs.
|
||||
hermes_home = get_hermes_home()
|
||||
hermes_node_bin = str(hermes_home / "node" / "bin")
|
||||
|
||||
existing_path = browser_env.get("PATH", "")
|
||||
path_parts = [p for p in existing_path.split(":") if p]
|
||||
candidate_dirs = (
|
||||
[hermes_node_bin]
|
||||
+ list(_discover_homebrew_node_dirs())
|
||||
+ [p for p in _SANE_PATH.split(":") if p]
|
||||
)
|
||||
|
||||
for part in reversed(candidate_dirs):
|
||||
if os.path.isdir(part) and part not in path_parts:
|
||||
path_parts.insert(0, part)
|
||||
|
||||
browser_env["PATH"] = ":".join(path_parts)
|
||||
# Ensure subprocesses inherit the same browser-specific PATH fallbacks
|
||||
# used during CLI discovery.
|
||||
browser_env["PATH"] = _merge_browser_path(browser_env.get("PATH", ""))
|
||||
browser_env["AGENT_BROWSER_SOCKET_DIR"] = task_socket_dir
|
||||
|
||||
# Use temp files for stdout/stderr instead of pipes.
|
||||
|
||||
Reference in New Issue
Block a user