feat(tabs): reuse an open tab instead of duplicating a page
Testing / remote-protocol-compat (0.15.0) (push) Successful in 42s
Testing / remote-protocol-compat (0.16.0) (push) Successful in 47s
Testing / test (push) Successful in 50s

- Add browser_cli/url_match.py with a canonical URL key for tab matching
- Canonicalize scheme, host, default ports, www., trailing slash, query order
- Support reuse modes none, exact, similar and origin via normalize_mode()
- Pick the closest match when several tabs qualify, preferring identical URLs
- Skip the reload when the reused tab already shows the requested page
- Expose nav.reusable_tab() so callers can look up a tab without side effects
- Accept reuse/reuse_domain/reuse_title in tabs.open(), not just nav.open()
- Add --reuse-exact to nav open and nav open-wait; --reuse is now fuzzy
- Default MCP tabs_open to reuse="similar" and return a reused flag
- Tell MCP agents in the server instructions to reuse before opening
- Document the reuse modes in README for MCP, CLI and Python API
- Cover url_match, SDK reuse paths and MCP reuse behaviour with new tests
- Bump package and extension version to 0.16.9
- Refresh uv.lock for the updated dependency set
This commit is contained in:
2026-10-19 10:47:56 +02:00
parent 6c0f77e416
commit 7cb034dfc2
12 changed files with 600 additions and 203 deletions
+17 -1
View File
@@ -5,6 +5,7 @@ from collections.abc import Callable, Iterable
from browser_cli.models import BrowserCounts, Tab
from browser_cli.sdk.base import Namespace
from browser_cli.url_match import needs_navigation
# Keep SDK-driven bulk closes comfortably below the native-host response
# timeout. The extension can close larger batches, but real browsers may take
@@ -32,14 +33,29 @@ class TabsNS(Namespace):
focus: bool = False,
window: str | None = None,
group: str | None = None,
reuse: bool | str = False,
reuse_domain: bool = False,
reuse_title: str | None = None,
) -> Tab:
"""Open *url* in a new tab and return a bound :class:`Tab`.
Set ``wait=True`` to block until the page reaches ``readyState=complete``.
Pass ``focus=True`` to explicitly bring the created tab/window forward.
``reuse=True`` navigates an already-open tab with a nearly identical URL
instead of creating a duplicate.
"""
if wait:
return self._c.nav.open_wait(url, timeout=timeout, background=background, focus=focus, window=window, group=group)
return self._c.nav.open_wait(
url, timeout=timeout, background=background, focus=focus, window=window, group=group,
reuse=reuse, reuse_domain=reuse_domain, reuse_title=reuse_title,
)
existing = self._c.nav.reusable_tab(url, reuse=reuse, reuse_domain=reuse_domain, reuse_title=reuse_title)
if existing is not None:
if needs_navigation(existing.url, url):
self._c.nav.to(existing.id, url)
if focus:
self.activate(existing.id)
return self.status(existing.id)
return self.require_tab(
self.command("navigate.open", {"url": url, "background": background or not focus, "focus": focus, "window": window, "group": group}),
"navigate.open returned unexpected data",