Implement comprehensive browser path discovery for Windows
This commit is contained in:
77
cli.py
77
cli.py
@@ -120,6 +120,63 @@ def _parse_reasoning_config(effort: str) -> dict | None:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _get_chrome_debug_candidates(system: str) -> list[str]:
|
||||||
|
"""Return likely browser executables for local CDP auto-launch."""
|
||||||
|
candidates: list[str] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
|
||||||
|
def _add_candidate(path: str | None) -> None:
|
||||||
|
if not path:
|
||||||
|
return
|
||||||
|
normalized = os.path.normcase(os.path.normpath(path))
|
||||||
|
if normalized in seen:
|
||||||
|
return
|
||||||
|
if os.path.isfile(path):
|
||||||
|
candidates.append(path)
|
||||||
|
seen.add(normalized)
|
||||||
|
|
||||||
|
def _add_from_path(*names: str) -> None:
|
||||||
|
for name in names:
|
||||||
|
_add_candidate(shutil.which(name))
|
||||||
|
|
||||||
|
if system == "Darwin":
|
||||||
|
for app in (
|
||||||
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||||
|
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
||||||
|
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
||||||
|
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
||||||
|
):
|
||||||
|
_add_candidate(app)
|
||||||
|
elif system == "Windows":
|
||||||
|
_add_from_path(
|
||||||
|
"chrome.exe", "msedge.exe", "brave.exe", "chromium.exe",
|
||||||
|
"chrome", "msedge", "brave", "chromium",
|
||||||
|
)
|
||||||
|
|
||||||
|
for base in (
|
||||||
|
os.environ.get("ProgramFiles"),
|
||||||
|
os.environ.get("ProgramFiles(x86)"),
|
||||||
|
os.environ.get("LOCALAPPDATA"),
|
||||||
|
):
|
||||||
|
if not base:
|
||||||
|
continue
|
||||||
|
for parts in (
|
||||||
|
("Google", "Chrome", "Application", "chrome.exe"),
|
||||||
|
("Chromium", "Application", "chrome.exe"),
|
||||||
|
("Chromium", "Application", "chromium.exe"),
|
||||||
|
("BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
|
||||||
|
("Microsoft", "Edge", "Application", "msedge.exe"),
|
||||||
|
):
|
||||||
|
_add_candidate(os.path.join(base, *parts))
|
||||||
|
else:
|
||||||
|
_add_from_path(
|
||||||
|
"google-chrome", "google-chrome-stable", "chromium-browser",
|
||||||
|
"chromium", "brave-browser", "microsoft-edge",
|
||||||
|
)
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
|
||||||
def load_cli_config() -> Dict[str, Any]:
|
def load_cli_config() -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Load CLI configuration from config files.
|
Load CLI configuration from config files.
|
||||||
@@ -4838,27 +4895,9 @@ class HermesCLI:
|
|||||||
|
|
||||||
Returns True if a launch command was executed (doesn't guarantee success).
|
Returns True if a launch command was executed (doesn't guarantee success).
|
||||||
"""
|
"""
|
||||||
import shutil
|
|
||||||
import subprocess as _sp
|
import subprocess as _sp
|
||||||
|
|
||||||
candidates = []
|
candidates = _get_chrome_debug_candidates(system)
|
||||||
if system == "Darwin":
|
|
||||||
# macOS: try common app bundle locations
|
|
||||||
for app in (
|
|
||||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
||||||
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
||||||
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
||||||
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
||||||
):
|
|
||||||
if os.path.isfile(app):
|
|
||||||
candidates.append(app)
|
|
||||||
else:
|
|
||||||
# Linux: try common binary names
|
|
||||||
for name in ("google-chrome", "google-chrome-stable", "chromium-browser",
|
|
||||||
"chromium", "brave-browser", "microsoft-edge"):
|
|
||||||
path = shutil.which(name)
|
|
||||||
if path:
|
|
||||||
candidates.append(path)
|
|
||||||
|
|
||||||
if not candidates:
|
if not candidates:
|
||||||
return False
|
return False
|
||||||
|
|||||||
43
tests/test_cli_browser_connect.py
Normal file
43
tests/test_cli_browser_connect.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"""Tests for CLI browser CDP auto-launch helpers."""
|
||||||
|
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from cli import HermesCLI
|
||||||
|
|
||||||
|
|
||||||
|
class TestChromeDebugLaunch:
|
||||||
|
def test_windows_launch_uses_browser_found_on_path(self):
|
||||||
|
captured = {}
|
||||||
|
|
||||||
|
def fake_popen(cmd, **kwargs):
|
||||||
|
captured["cmd"] = cmd
|
||||||
|
captured["kwargs"] = kwargs
|
||||||
|
return object()
|
||||||
|
|
||||||
|
with patch("cli.shutil.which", side_effect=lambda name: r"C:\Chrome\chrome.exe" if name == "chrome.exe" else None), \
|
||||||
|
patch("cli.os.path.isfile", side_effect=lambda path: path == r"C:\Chrome\chrome.exe"), \
|
||||||
|
patch("subprocess.Popen", side_effect=fake_popen):
|
||||||
|
assert HermesCLI._try_launch_chrome_debug(9333, "Windows") is True
|
||||||
|
|
||||||
|
assert captured["cmd"] == [r"C:\Chrome\chrome.exe", "--remote-debugging-port=9333"]
|
||||||
|
assert captured["kwargs"]["start_new_session"] is True
|
||||||
|
|
||||||
|
def test_windows_launch_falls_back_to_common_install_dirs(self, monkeypatch):
|
||||||
|
captured = {}
|
||||||
|
installed = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
|
||||||
|
|
||||||
|
def fake_popen(cmd, **kwargs):
|
||||||
|
captured["cmd"] = cmd
|
||||||
|
captured["kwargs"] = kwargs
|
||||||
|
return object()
|
||||||
|
|
||||||
|
monkeypatch.setenv("ProgramFiles", r"C:\Program Files")
|
||||||
|
monkeypatch.delenv("ProgramFiles(x86)", raising=False)
|
||||||
|
monkeypatch.delenv("LOCALAPPDATA", raising=False)
|
||||||
|
|
||||||
|
with patch("cli.shutil.which", return_value=None), \
|
||||||
|
patch("cli.os.path.isfile", side_effect=lambda path: path == installed), \
|
||||||
|
patch("subprocess.Popen", side_effect=fake_popen):
|
||||||
|
assert HermesCLI._try_launch_chrome_debug(9222, "Windows") is True
|
||||||
|
|
||||||
|
assert captured["cmd"] == [installed, "--remote-debugging-port=9222"]
|
||||||
Reference in New Issue
Block a user