refactor: modularize auth transport and markdown
Testing / remote-protocol-compat (0.9.5) (push) Successful in 1m4s
Testing / test (push) Successful in 1m22s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 1m7s
Package Extension / package-extension (push) Successful in 1m1s
Build & Publish Package / publish (push) Successful in 1m5s

- Split auth into focused package modules for agent keys, file keys,
  signing, and post-quantum transport helpers while keeping the public
  browser_cli.auth import surface intact.
- Move transport encoding internals into a package with separate codec and
  binary-hoisting helpers, preserving browser_cli.transport compatibility.
- Extract remote TCP auth/socket helpers and serve challenge setup out of the
  runtime paths to make connection handling easier to reason about.
- Move the extension markdown extractor into a dedicated content/markdown
  folder with separate root selection, code normalization, renderer, and utils.
- Centralize CLI Rich rendering helpers for tab/window tree and table output,
  and add rendering tests for the shared builders.
- Remove local typing ignores in SDK/decorator/script plumbing and bump the
  package and extension version to 0.15.3.
This commit is contained in:
2026-06-15 01:23:57 +02:00
parent 0b43408a8d
commit 7cb2a8b618
34 changed files with 1502 additions and 1325 deletions
+13 -85
View File
@@ -2,65 +2,25 @@ import base64
import binascii
import click
from browser_cli.commands import client_from_ctx, gentle_mode_option, handle_errors, print_counts, tab_option
from browser_cli.commands.rendering import no_wrap_text, print_tree, shorten, tab_tree_label, tree_title_limit, tree_url_limit
from browser_cli.commands.rendering import build_tabs_tree, print_table_rows, print_tree
from rich.console import Console
from rich.table import Table
from rich.text import Text
from rich.tree import Tree
console = Console()
def _group_tree_label(group_id: int, group, *, title_limit: int) -> Text:
title = getattr(group, "title", "") or f"Group {group_id}"
color = getattr(group, "color", "") or "group"
count = getattr(group, "tab_count", 0) or 0
collapsed = bool(getattr(group, "collapsed", False))
label = no_wrap_text()
label.append(shorten(title, title_limit), style="bold")
meta = [color]
if count:
meta.append(f"{count} tab" + ("" if count == 1 else "s"))
if collapsed:
meta.append("collapsed")
label.append(" (" + ", ".join(meta) + ")", style="dim")
return label
def _tab_sort_key(tab):
return (
tab.browser or "",
tab.window_id,
getattr(tab, "index", 0),
tab.group_id if tab.group_id is not None else -1,
tab.id,
)
def _print_tabs(tabs, *, show_browser: bool = False) -> None:
if not tabs:
console.print("[yellow]No tabs found[/yellow]")
return
table = Table(show_header=True, header_style="bold cyan")
columns = []
if show_browser:
table.add_column("Browser", no_wrap=True)
table.add_column("ID", style="dim", no_wrap=True)
table.add_column("Window", no_wrap=True)
table.add_column("Active", width=7)
table.add_column("Muted", width=7)
table.add_column("Title")
table.add_column("URL")
for t in tabs:
active = "[green]✓[/green]" if t.active else ""
muted = "[yellow]✓[/yellow]" if t.muted else ""
row = [
(t.browser or "") if show_browser else None,
str(t.id),
str(t.window_id),
active,
muted,
(t.title or "")[:60],
(t.url or "")[:80],
]
table.add_row(*[value for value in row if value is not None])
console.print(table)
columns.append(("Browser", lambda tab: tab.browser or ""))
columns.extend([
("ID", lambda tab: tab.id),
("Window", lambda tab: tab.window_id),
("Active", lambda tab: "[green]✓[/green]" if tab.active else ""),
("Muted", lambda tab: "[yellow]✓[/yellow]" if tab.muted else ""),
("Title", lambda tab: (tab.title or "")[:60]),
("URL", lambda tab: (tab.url or "")[:80]),
])
print_table_rows(tabs, columns, console=console, empty_message="[yellow]No tabs found[/yellow]")
@click.group("tabs")
def tabs_group():
@@ -79,39 +39,7 @@ def tabs_list():
def tabs_tree(show_urls):
"""Show tabs grouped as a window/group tree."""
client = client_from_ctx()
tabs = sorted(client.tabs.list(), key=_tab_sort_key)
title_limit = tree_title_limit(console=console, show_browser=any(t.browser for t in tabs), show_urls=show_urls)
url_limit = tree_url_limit(title_limit, console=console)
group_info = {
(group.browser or "local", group.id): group
for group in client.groups.list()
}
root = Tree("[bold]Tabs[/bold]")
browsers = {}
windows = {}
groups = {}
show_browser = any(t.browser for t in tabs)
for tab in tabs:
browser_key = tab.browser or "local"
browser_node = browsers.get(browser_key)
if browser_node is None:
browser_node = root.add(Text(browser_key, style="bold cyan")) if show_browser else root
browsers[browser_key] = browser_node
win_key = (browser_key, tab.window_id)
win_node = windows.get(win_key)
if win_node is None:
win_node = browser_node.add(f"Window {tab.window_id}")
windows[win_key] = win_node
if tab.group_id is None:
win_node.add(tab_tree_label(tab, title_limit=title_limit, show_urls=show_urls, url_limit=url_limit))
continue
group_key = (browser_key, tab.window_id, tab.group_id)
group_node = groups.get(group_key)
group = group_info.get((browser_key, tab.group_id))
if group_node is None:
group_node = win_node.add(_group_tree_label(tab.group_id, group, title_limit=title_limit))
groups[group_key] = group_node
group_node.add(tab_tree_label(tab, title_limit=title_limit, show_urls=show_urls, url_limit=url_limit))
root = build_tabs_tree(client.tabs.list(), client.groups.list(), console=console, show_urls=show_urls)
print_tree(root, console=console)
@tabs_group.command("close")