Files
browser-cli/browser_cli/sdk/navigation.py
T
daniel156161 3e3b8d529c
Testing / test (push) Failing after 15s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 46s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 47s
fix: make navigation no-focus by default
- Change nav open and open-wait to avoid activating newly created tabs unless
  --focus is explicitly requested.
- Send background=true for default opens so older or remote extensions also
  avoid stealing focus even if they ignore the new focus flag.
- Remove the redundant --bg flag from navigation and search CLI commands now
  that no-focus/background behavior is the default.
- Thread focus support through the sync SDK, async SDK, tab helpers, and
  workflow decorators.
- Update README and demo usage to document the new default and --focus opt-in.
- Bump package and extension metadata to 0.12.3.
- Add regression coverage for CLI help, wire payloads, and extension behavior.
2026-06-14 13:59:15 +02:00

83 lines
3.0 KiB
Python

"""Navigation namespace: ``b.nav.*``."""
from __future__ import annotations
from browser_cli.models import Tab
from browser_cli.sdk.base import Namespace, sdk_command
def _open_args(self, url, *, background=False, focus=False, window=None, group=None):
return {"url": url, "background": background or not focus, "focus": focus, "window": window, "group": group}
def _tab_args(self, tab_id=None):
return {"tabId": tab_id}
class NavigationNS(Namespace):
"""Open URLs, navigate history, and focus tabs."""
@sdk_command("navigate.open", _open_args)
def open(
self,
url: str,
*,
background: bool = False,
focus: bool = False,
window: str | None = None,
group: str | None = None,
) -> None:
"""Open *url* in a new tab without stealing OS focus by default."""
def open_wait(
self,
url: str,
*,
timeout: float = 30.0,
background: bool = False,
focus: bool = False,
window: str | None = None,
group: str | None = None,
) -> Tab:
"""Open *url* in a new tab and block until fully loaded. Returns the Tab."""
return self.require_tab(
self.command("navigate.open_wait", {
"url": url, "timeout": int(timeout * 1000),
"background": background or not focus, "focus": focus, "window": window, "group": group,
}),
"navigate.open_wait returned unexpected data",
)
@sdk_command("navigate.reload", _tab_args)
def reload(self, tab_id: int | None = None) -> None:
"""Reload the active tab or a specific tab."""
@sdk_command("navigate.hard_reload", _tab_args)
def hard_reload(self, tab_id: int | None = None) -> None:
"""Hard-reload the active tab or a specific tab."""
@sdk_command("navigate.back", _tab_args)
def back(self, tab_id: int | None = None) -> None:
"""Navigate back in the active tab or a specific tab."""
@sdk_command("navigate.forward", _tab_args)
def forward(self, tab_id: int | None = None) -> None:
"""Navigate forward in the active tab or a specific tab."""
@sdk_command("navigate.focus", lambda self, pattern: {"pattern": pattern})
def focus(self, pattern: str) -> dict | None:
"""Focus the first tab whose URL matches *pattern*. Returns the matched tab info, if any."""
@sdk_command("navigate.to", lambda self, tab_id, url: {"tabId": tab_id, "url": url})
def to(self, tab_id: int, url: str) -> None:
"""Navigate a specific tab to *url* in place."""
def search(
self, engine: str, query: str, *,
background: bool = False, focus: bool = False, window: str | None = None, group: str | None = None,
) -> None:
"""Open a search query in the given engine (e.g. 'google', 'youtube', 'ddg')."""
from urllib.parse import quote_plus
from browser_cli.commands.search import ENGINES
template = ENGINES.get(engine)
if template is None:
raise ValueError(f"Unknown search engine '{engine}'. Available: {', '.join(ENGINES)}")
url = template.format(query=quote_plus(query))
self.command("navigate.open", {"url": url, "background": background or not focus, "focus": focus, "window": window, "group": group})