fix(cli): foreground the WebUI browser

This commit is contained in:
Xubin Ren
2026-08-27 10:45:40 +08:00
parent b632186b5f
commit 2113870e27
3 changed files with 67 additions and 8 deletions
+5 -3
View File
@@ -23,6 +23,7 @@ from nanobot.cli.webui_support import (
_gateway_health_bind_note,
_gateway_health_url,
_host_for_local_browser,
_launch_browser,
_prepare_webui_bundle_for_gateway,
_print_foreground_port_conflict,
_tcp_endpoint_reachable,
@@ -864,7 +865,6 @@ def _run_gateway(
"""Wait for the gateway to bind, then point the user's browser at the webui."""
if not open_browser_url:
return
import webbrowser
from urllib.parse import urlparse
# Channels start asynchronously. When the caller supplies a backend
@@ -896,8 +896,10 @@ def _run_gateway(
await asyncio.sleep(0.1)
display_url = _webui_display_url(open_browser_url)
try:
webbrowser.open(open_browser_url)
console.print(f"[green]✓[/green] Opened browser at {display_url}")
if _launch_browser(open_browser_url):
console.print(f"[green]✓[/green] Opened browser at {display_url}")
else:
console.print(f"[yellow]Could not open browser; visit {display_url}[/yellow]")
except Exception as e:
console.print(f"[yellow]Could not open browser ({e}); visit {display_url}[/yellow]")
+21 -4
View File
@@ -1,7 +1,9 @@
"""Shared WebUI setup, URL, health, and browser helpers."""
import subprocess
import sys
import time
import webbrowser
from collections.abc import Callable
from pathlib import Path
from typing import TYPE_CHECKING, Any
@@ -40,6 +42,7 @@ __all__ = [
"_gateway_instance_command",
"_host_for_local_browser",
"_load_webui_setup_config",
"_launch_browser",
"_open_webui_browser",
"_prepare_webui_bundle_for_gateway",
"_print_foreground_port_conflict",
@@ -60,6 +63,20 @@ __all__ = [
console = Console()
def _launch_browser(url: str) -> bool:
"""Open *url* and request a foreground browser window."""
if sys.platform == "darwin":
result = subprocess.run(
["open", url],
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
return result.returncode == 0
return bool(webbrowser.open(url, new=2, autoraise=True))
def _confirm_webui_action(message: str, *, yes: bool) -> None:
"""Confirm a WebUI first-run mutation or fail clearly in non-interactive shells."""
if yes:
@@ -419,14 +436,14 @@ def _print_foreground_port_conflict(
def _open_webui_browser(url: str, *, wait: bool = True) -> None:
"""Open the WebUI in the user's default browser, with a copyable fallback."""
import webbrowser
if wait:
_wait_for_webui(url)
display_url = _webui_display_url(url)
try:
webbrowser.open(url)
console.print(f"[green]✓[/green] Opened WebUI: [cyan]{display_url}[/cyan]")
if _launch_browser(url):
console.print(f"[green]✓[/green] Opened WebUI: [cyan]{display_url}[/cyan]")
else:
console.print(f"[yellow]Could not open browser; visit {display_url}[/yellow]")
except Exception as exc:
console.print(f"[yellow]Could not open browser ({exc}); visit {display_url}[/yellow]")
+41 -1
View File
@@ -2534,7 +2534,11 @@ def test_webui_yes_still_refuses_invalid_custom_model_setup(
def test_open_webui_browser_redacts_bootstrap_secret(monkeypatch, capsys) -> None:
opened: list[str] = []
url = "http://127.0.0.1:8765/#/?bootstrapSecret=super-secret"
monkeypatch.setattr("webbrowser.open", lambda value: opened.append(value))
monkeypatch.setattr(
cli_webui_support,
"_launch_browser",
lambda value: opened.append(value) or True,
)
cli_webui_support._open_webui_browser(url, wait=False)
@@ -2544,6 +2548,42 @@ def test_open_webui_browser_redacts_bootstrap_secret(monkeypatch, capsys) -> Non
assert "super-secret" not in output
def test_open_webui_browser_reports_launch_failure(monkeypatch, capsys) -> None:
monkeypatch.setattr(cli_webui_support, "_launch_browser", lambda _value: False)
cli_webui_support._open_webui_browser("http://127.0.0.1:8765/", wait=False)
assert "Could not open browser; visit http://127.0.0.1:8765/" in _strip_ansi(
capsys.readouterr().out
)
def test_launch_browser_uses_macos_foreground_opener(monkeypatch) -> None:
seen: list[list[str]] = []
monkeypatch.setattr(cli_webui_support.sys, "platform", "darwin")
monkeypatch.setattr(
cli_webui_support.subprocess,
"run",
lambda command, **_kwargs: seen.append(command) or SimpleNamespace(returncode=0),
)
assert cli_webui_support._launch_browser("http://127.0.0.1:8765/") is True
assert seen == [["open", "http://127.0.0.1:8765/"]]
def test_launch_browser_uses_default_browser_off_macos(monkeypatch) -> None:
opened: list[tuple[str, int, bool]] = []
monkeypatch.setattr(cli_webui_support.sys, "platform", "linux")
monkeypatch.setattr(
cli_webui_support.webbrowser,
"open",
lambda url, *, new, autoraise: opened.append((url, new, autoraise)) or True,
)
assert cli_webui_support._launch_browser("http://127.0.0.1:8765/") is True
assert opened == [("http://127.0.0.1:8765/", 2, True)]
def test_webui_foreground_attaches_to_existing_managed_gateway(monkeypatch, tmp_path: Path) -> None:
config_file = tmp_path / "config.json"
config_file.write_text("{}")