feat(read): target any tab for page info and extraction
Testing / test (push) Successful in 40s
Testing / remote-protocol-compat (0.16.0) (push) Successful in 31s
Testing / remote-protocol-compat (0.15.0) (push) Successful in 39s

- Add --tab option to all extract commands and page info
- Thread tab_id through the SDK extract and page namespaces
- Route page.info with a tab_id to tabs.status for cross-tab metadata
- Accept tab_id in the MCP page_info, extract_text, extract_markdown tools
- Forward tabId in the extension page.info and extract.html handlers
- Keep the active tab as default when no tab is given

- Cover tab-scoped reads in API, CLI, and MCP tests
- Bump package and extension version to 0.16.7
- Refresh uv.lock with current dependency versions
This commit is contained in:
2026-08-28 11:19:02 +02:00
parent 6352d9994e
commit 914508e2db
11 changed files with 522 additions and 410 deletions
+25 -23
View File
@@ -131,39 +131,41 @@ class DomNS(Namespace):
})
class ExtractNS(Namespace):
"""Extract structured content from the active tab."""
"""Extract structured content from the active (or specified) tab."""
@sdk_command("extract.links", default=[])
def links(self) -> list[dict]:
"""Return links from the active tab."""
@sdk_command("extract.links", lambda self, tab_id=None: {"tabId": tab_id}, default=[])
def links(self, tab_id: int | None = None) -> list[dict]:
"""Return links from the active tab or *tab_id*."""
@sdk_command("extract.images", default=[])
def images(self) -> list[dict]:
"""Return images from the active tab."""
@sdk_command("extract.images", lambda self, tab_id=None: {"tabId": tab_id}, default=[])
def images(self, tab_id: int | None = None) -> list[dict]:
"""Return images from the active tab or *tab_id*."""
@sdk_command("extract.text", default="")
def text(self) -> str:
"""Return plain text from the active tab."""
@sdk_command("extract.text", lambda self, tab_id=None: {"tabId": tab_id}, default="")
def text(self, tab_id: int | None = None) -> str:
"""Return plain text from the active tab or *tab_id*."""
@sdk_command("extract.json", lambda self, selector: {"selector": selector})
def json(self, selector: str):
"""Extract JSON-like structured data from a selector."""
@sdk_command("extract.json", lambda self, selector, tab_id=None: {"selector": selector, "tabId": tab_id})
def json(self, selector: str, tab_id: int | None = None):
"""Extract JSON-like structured data from a selector in the active tab or *tab_id*."""
@sdk_command("extract.html", default="")
def html(self) -> str:
"""Return the full HTML source of the active tab."""
@sdk_command("extract.html", lambda self, tab_id=None: {"tabId": tab_id}, default="")
def html(self, tab_id: int | None = None) -> str:
"""Return the full HTML source of the active tab or *tab_id*."""
@sdk_command("extract.markdown", lambda self, selector=None: {"selector": selector}, mapper=_extract_markdown)
def markdown(self, selector: str | None = None) -> str:
"""Extract the page's main content as clean Markdown.
@sdk_command("extract.markdown", lambda self, selector=None, tab_id=None: {"selector": selector, "tabId": tab_id}, mapper=_extract_markdown)
def markdown(self, selector: str | None = None, tab_id: int | None = None) -> str:
"""Extract the page's main content as clean Markdown from the active tab or *tab_id*.
The extractor may return either Markdown or raw HTML; both are
normalized to Markdown here so SDK and CLI callers get identical output.
"""
class PageNS(Namespace):
"""Inspect the active page."""
"""Inspect the active page or a specified tab."""
@sdk_command("page.info", default={})
def info(self) -> dict:
"""Return title, URL, readyState, lang, and meta tags of the active tab."""
def info(self, tab_id: int | None = None) -> dict:
"""Return metadata for the active page, or tab status for *tab_id*."""
if tab_id is not None:
return self.command("tabs.status", {"tabId": tab_id}) or {}
return self.command("page.info", {}) or {}