fix(browser): avoid bogus Chrome launch fallback
Detect an actual Chrome/Chromium executable before printing a manual CDP launch command, including common WSL-mounted Windows browser paths, so /browser connect does not suggest google-chrome when it is unavailable.
This commit is contained in:
committed by
Teknium
parent
f10a3df632
commit
69ff114ee2
6
cli.py
6
cli.py
@@ -6630,8 +6630,12 @@ class HermesCLI:
|
|||||||
else:
|
else:
|
||||||
print(" ⚠ Could not auto-launch Chrome")
|
print(" ⚠ Could not auto-launch Chrome")
|
||||||
sys_name = _plat.system()
|
sys_name = _plat.system()
|
||||||
|
chrome_cmd = manual_chrome_debug_command(_port, sys_name)
|
||||||
|
if chrome_cmd:
|
||||||
print(f" Launch Chrome manually:")
|
print(f" Launch Chrome manually:")
|
||||||
print(f" {manual_chrome_debug_command(_port, sys_name)}")
|
print(f" {chrome_cmd}")
|
||||||
|
else:
|
||||||
|
print(" No Chrome/Chromium executable found in this environment")
|
||||||
else:
|
else:
|
||||||
print(f" ⚠ Port {_port} is not reachable at {cdp_url}")
|
print(f" ⚠ Port {_port} is not reachable at {cdp_url}")
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
@@ -64,6 +65,14 @@ def get_chrome_debug_candidates(system: str) -> list[str]:
|
|||||||
"google-chrome", "google-chrome-stable", "chromium-browser",
|
"google-chrome", "google-chrome-stable", "chromium-browser",
|
||||||
"chromium", "brave-browser", "microsoft-edge",
|
"chromium", "brave-browser", "microsoft-edge",
|
||||||
)
|
)
|
||||||
|
for base in ("/mnt/c/Program Files", "/mnt/c/Program Files (x86)"):
|
||||||
|
for parts in (
|
||||||
|
("Google", "Chrome", "Application", "chrome.exe"),
|
||||||
|
("Chromium", "Application", "chrome.exe"),
|
||||||
|
("BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
|
||||||
|
("Microsoft", "Edge", "Application", "msedge.exe"),
|
||||||
|
):
|
||||||
|
add(os.path.join(base, *parts))
|
||||||
|
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
@@ -72,27 +81,29 @@ def chrome_debug_data_dir() -> str:
|
|||||||
return str(get_hermes_home() / "chrome-debug")
|
return str(get_hermes_home() / "chrome-debug")
|
||||||
|
|
||||||
|
|
||||||
def manual_chrome_debug_command(port: int = DEFAULT_BROWSER_CDP_PORT, system: str | None = None) -> str:
|
def _chrome_debug_args(port: int) -> list[str]:
|
||||||
|
return [
|
||||||
|
f"--remote-debugging-port={port}",
|
||||||
|
f"--user-data-dir={chrome_debug_data_dir()}",
|
||||||
|
"--no-first-run",
|
||||||
|
"--no-default-browser-check",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def manual_chrome_debug_command(port: int = DEFAULT_BROWSER_CDP_PORT, system: str | None = None) -> str | None:
|
||||||
system = system or platform.system()
|
system = system or platform.system()
|
||||||
data_dir = chrome_debug_data_dir()
|
candidates = get_chrome_debug_candidates(system)
|
||||||
|
if candidates:
|
||||||
|
return " ".join(shlex.quote(part) for part in [candidates[0], *_chrome_debug_args(port)])
|
||||||
|
|
||||||
if system == "Darwin":
|
if system == "Darwin":
|
||||||
return (
|
return (
|
||||||
'open -a "Google Chrome" --args'
|
'open -a "Google Chrome" --args'
|
||||||
f" --remote-debugging-port={port}"
|
f" --remote-debugging-port={port}"
|
||||||
f' --user-data-dir="{data_dir}"'
|
f' --user-data-dir="{chrome_debug_data_dir()}"'
|
||||||
" --no-first-run --no-default-browser-check"
|
|
||||||
)
|
|
||||||
if system == "Windows":
|
|
||||||
return (
|
|
||||||
f"chrome.exe --remote-debugging-port={port}"
|
|
||||||
f' --user-data-dir="{data_dir}"'
|
|
||||||
" --no-first-run --no-default-browser-check"
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
f"google-chrome --remote-debugging-port={port}"
|
|
||||||
f' --user-data-dir="{data_dir}"'
|
|
||||||
" --no-first-run --no-default-browser-check"
|
" --no-first-run --no-default-browser-check"
|
||||||
)
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def try_launch_chrome_debug(port: int = DEFAULT_BROWSER_CDP_PORT, system: str | None = None) -> bool:
|
def try_launch_chrome_debug(port: int = DEFAULT_BROWSER_CDP_PORT, system: str | None = None) -> bool:
|
||||||
@@ -105,10 +116,7 @@ def try_launch_chrome_debug(port: int = DEFAULT_BROWSER_CDP_PORT, system: str |
|
|||||||
subprocess.Popen(
|
subprocess.Popen(
|
||||||
[
|
[
|
||||||
candidates[0],
|
candidates[0],
|
||||||
f"--remote-debugging-port={port}",
|
*_chrome_debug_args(port),
|
||||||
f"--user-data-dir={chrome_debug_data_dir()}",
|
|
||||||
"--no-first-run",
|
|
||||||
"--no-default-browser-check",
|
|
||||||
],
|
],
|
||||||
stdout=subprocess.DEVNULL,
|
stdout=subprocess.DEVNULL,
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import os
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from cli import HermesCLI
|
from cli import HermesCLI
|
||||||
|
from hermes_cli.browser_connect import manual_chrome_debug_command
|
||||||
|
|
||||||
|
|
||||||
def _assert_chrome_debug_cmd(cmd, expected_chrome, expected_port):
|
def _assert_chrome_debug_cmd(cmd, expected_chrome, expected_port):
|
||||||
@@ -55,3 +56,26 @@ class TestChromeDebugLaunch:
|
|||||||
assert HermesCLI._try_launch_chrome_debug(9222, "Windows") is True
|
assert HermesCLI._try_launch_chrome_debug(9222, "Windows") is True
|
||||||
|
|
||||||
_assert_chrome_debug_cmd(captured["cmd"], installed, 9222)
|
_assert_chrome_debug_cmd(captured["cmd"], installed, 9222)
|
||||||
|
|
||||||
|
def test_manual_command_uses_detected_linux_browser(self):
|
||||||
|
with patch("hermes_cli.browser_connect.shutil.which", side_effect=lambda name: "/usr/bin/chromium" if name == "chromium" else None), \
|
||||||
|
patch("hermes_cli.browser_connect.os.path.isfile", side_effect=lambda path: path == "/usr/bin/chromium"):
|
||||||
|
command = manual_chrome_debug_command(9222, "Linux")
|
||||||
|
|
||||||
|
assert command is not None
|
||||||
|
assert command.startswith("/usr/bin/chromium --remote-debugging-port=9222")
|
||||||
|
|
||||||
|
def test_manual_command_uses_wsl_windows_chrome_when_available(self):
|
||||||
|
chrome = "/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"
|
||||||
|
|
||||||
|
with patch("hermes_cli.browser_connect.shutil.which", return_value=None), \
|
||||||
|
patch("hermes_cli.browser_connect.os.path.isfile", side_effect=lambda path: path == chrome):
|
||||||
|
command = manual_chrome_debug_command(9222, "Linux")
|
||||||
|
|
||||||
|
assert command is not None
|
||||||
|
assert command.startswith(f"'{chrome}' --remote-debugging-port=9222")
|
||||||
|
|
||||||
|
def test_manual_command_returns_none_when_linux_browser_missing(self):
|
||||||
|
with patch("hermes_cli.browser_connect.shutil.which", return_value=None), \
|
||||||
|
patch("hermes_cli.browser_connect.os.path.isfile", return_value=False):
|
||||||
|
assert manual_chrome_debug_command(9222, "Linux") is None
|
||||||
|
|||||||
@@ -2904,14 +2904,15 @@ def test_browser_manage_connect_default_local_reports_launch_hint(monkeypatch):
|
|||||||
)
|
)
|
||||||
with patch.dict(sys.modules, {"tools.browser_tool": fake}):
|
with patch.dict(sys.modules, {"tools.browser_tool": fake}):
|
||||||
_stub_urlopen(monkeypatch, ok=False)
|
_stub_urlopen(monkeypatch, ok=False)
|
||||||
with patch("hermes_cli.browser_connect.try_launch_chrome_debug", return_value=False):
|
with patch("hermes_cli.browser_connect.try_launch_chrome_debug", return_value=False), \
|
||||||
|
patch("hermes_cli.browser_connect.get_chrome_debug_candidates", return_value=[]):
|
||||||
resp = server.handle_request(
|
resp = server.handle_request(
|
||||||
{"id": "1", "method": "browser.manage", "params": {"action": "connect"}}
|
{"id": "1", "method": "browser.manage", "params": {"action": "connect"}}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert resp["error"]["code"] == 5031
|
assert resp["error"]["code"] == 5031
|
||||||
assert "Start Chrome with remote debugging" in resp["error"]["message"]
|
assert "No Chrome/Chromium executable was found" in resp["error"]["message"]
|
||||||
assert "google-chrome --remote-debugging-port=9222" in resp["error"]["message"]
|
assert "--remote-debugging-port=9222" in resp["error"]["message"]
|
||||||
assert "BROWSER_CDP_URL" not in os.environ
|
assert "BROWSER_CDP_URL" not in os.environ
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4762,10 +4762,18 @@ def _is_default_local_cdp(parsed) -> bool:
|
|||||||
def _browser_connect_error(url: str, port: int) -> str:
|
def _browser_connect_error(url: str, port: int) -> str:
|
||||||
from hermes_cli.browser_connect import manual_chrome_debug_command
|
from hermes_cli.browser_connect import manual_chrome_debug_command
|
||||||
|
|
||||||
|
command = manual_chrome_debug_command(port)
|
||||||
|
if not command:
|
||||||
|
return (
|
||||||
|
f"Chrome is not reachable at {url}. "
|
||||||
|
"No Chrome/Chromium executable was found in this environment; "
|
||||||
|
f"install one or start Chrome with --remote-debugging-port={port}, then retry /browser connect."
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
f"Chrome is not reachable at {url}. "
|
f"Chrome is not reachable at {url}. "
|
||||||
"Start Chrome with remote debugging, then retry /browser connect:\n"
|
"Start Chrome with remote debugging, then retry /browser connect:\n"
|
||||||
f"{manual_chrome_debug_command(port)}"
|
f"{command}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user