diff --git a/hermes_cli/dep_ensure.py b/hermes_cli/dep_ensure.py index 03ddd80ef84..c06fc6db80a 100644 --- a/hermes_cli/dep_ensure.py +++ b/hermes_cli/dep_ensure.py @@ -1,7 +1,17 @@ """Lazy dependency bootstrapper for non-Python runtime deps. -Wraps install.sh --ensure to install node, browser, ripgrep, ffmpeg -on first use. Prompts interactively unless told not to. +Detection and prompting live here in Python — not in install.sh — because: + 1. shutil.which() works on every platform; install.sh needs bash. + 2. Detection is instant; spawning bash for a "is node installed?" check is waste. + 3. Python controls the UX (rich prompts, non-interactive fallback, TTY detection). + +install.sh is still the *installation* backend because it has 1900 lines of +battle-tested OS detection and package-manager logic (apt/brew/pacman/dnf/ +zypper/Termux/…). Reimplementing that in Python would be huge duplication. + +Deps that degrade gracefully (ripgrep → grep fallback, ffmpeg → skip conversion) +don't need ensure_dependency wired in — only hard-fail sites do (TUI needs node, +browser tool needs agent-browser). """ from __future__ import annotations diff --git a/hermes_cli/main.py b/hermes_cli/main.py index bb372c396f1..0b5e79fe9d9 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1042,6 +1042,13 @@ def _make_tui_argv(tui_dir: Path, tui_dev: bool) -> tuple[list[str], Path]: if env_node and os.path.isfile(env_node) and os.access(env_node, os.X_OK): return env_node path = shutil.which(bin) + if not path and bin == "node": + try: + from hermes_cli.dep_ensure import ensure_dependency + if ensure_dependency("node"): + path = shutil.which("node") + except Exception: + pass if not path: print(f"{bin} not found — install Node.js to use the TUI.") sys.exit(1) diff --git a/tools/browser_tool.py b/tools/browser_tool.py index c01d25a6f0b..b3eb24ee044 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -1703,7 +1703,23 @@ def _find_agent_browser() -> str: _agent_browser_resolved = True return _cached_agent_browser - # Nothing found — cache the failure so subsequent calls don't re-scan. + # Nothing found — try lazy installation before giving up. + try: + from hermes_cli.dep_ensure import ensure_dependency + if ensure_dependency("browser"): + recheck = shutil.which("agent-browser") + if not recheck and extended_path: + recheck = shutil.which("agent-browser", path=extended_path) + if not recheck: + hermes_nm = str(get_hermes_home() / "node_modules" / ".bin") + recheck = shutil.which("agent-browser", path=hermes_nm) + if recheck: + _cached_agent_browser = recheck + _agent_browser_resolved = True + return recheck + except Exception: + pass + _agent_browser_resolved = True raise FileNotFoundError( "agent-browser CLI not found. Install it with: "