Files
browser-cli/browser_cli/commands/clients.py
T
daniel156161 6fa931aa36
Testing / remote-protocol-compat (0.9.5) (push) Successful in 56s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 59s
Testing / test (push) Successful in 1m1s
Build & Publish Package / publish (push) Successful in 33s
Package Extension / package-extension (push) Successful in 36s
feat: harden remote serve and reuse connections
- Gate TCP serve commands with safe-by-default policies, per-key allow tokens, per-key rate limiting, and audit labels.
- Reuse authenticated encrypted remote sessions and parallelize/caches multi-browser fanout to reduce repeated handshake roundtrips.
- Increase paged native-host batch size with extension-side byte budgeting to speed large tab listings safely.
- Point install output at public Chrome Web Store / Firefox AMO listings by default, with --dev preserving unpacked workflows.
- Share search-engine metadata between CLI and SDK and bump the package/extension version to 0.16.0.
- Cover the new security, pooling, paging, install, and fanout behavior with expanded Python and extension tests.
2026-06-18 14:24:15 +02:00

107 lines
3.3 KiB
Python

"""Click commands for inspecting connected browser clients."""
from __future__ import annotations
import os
import sys
import click
from rich.console import Console
from browser_cli.client import (
BrowserNotConnected,
REGISTRY_PATH,
active_browser_targets,
collect_browser_clients,
send_command,
)
from browser_cli.commands.rendering import print_browser_grouped_table_rows
from browser_cli.registry import load_registry
console = Console()
def _rename_target_profile(target_browser: str | None) -> str | None:
if target_browser:
return target_browser
active = active_browser_targets()
if len(active) == 1:
return active[0].profile
return None
def _ensure_unique_browser_alias(alias: str, target_browser: str | None) -> None:
target_profile = _rename_target_profile(target_browser)
profiles: dict[str, str] = load_registry(REGISTRY_PATH)
if alias in profiles and alias != target_profile:
raise click.ClickException(f"Browser alias '{alias}' already exists")
@click.group("clients", invoke_without_command=True)
@click.pass_context
def clients_group(ctx):
"""Inspect and manage connected browser clients."""
if ctx.invoked_subcommand is not None:
return
browser_alias = (ctx.obj or {}).get("browser")
remote = (ctx.obj or {}).get("remote") or os.environ.get("BROWSER_CLI_REMOTE")
key = (ctx.obj or {}).get("key")
try:
all_clients = collect_browser_clients(
browser_alias=browser_alias,
remote=remote,
key=key,
registry_path=REGISTRY_PATH,
)
except (BrowserNotConnected, RuntimeError) as e:
console.print(f"[red]Error:[/red] {e}")
sys.exit(1)
if not all_clients:
console.print("[yellow]No browser clients found. Start a browser with the extension enabled first.[/yellow]")
sys.exit(1)
_print_clients(all_clients)
def _print_clients(all_clients: list) -> None:
groups = {c.get("profileGroup") for c in all_clients if c.get("profileGroup")}
grouped = bool(groups and groups != {"local"})
columns = [
("Browser", lambda item: item.get("name", "")),
("Version", lambda item: item.get("version", "")),
("Extension Version", lambda item: item.get("extensionVersion", "")),
]
print_browser_grouped_table_rows(
all_clients,
columns,
console=console,
empty_message="[yellow]No browser clients found. Start a browser with the extension enabled first.[/yellow]",
browser_getter=lambda item: item.get("profile", ""),
group_getter=lambda item: item.get("profileGroup", "") if grouped else "",
browser_header="Profile",
)
@clients_group.command("rename")
@click.option(
"--browser",
"target_browser",
default=None,
metavar="ALIAS",
help="Browser profile alias to rename. Overrides the global --browser option for this command.",
)
@click.argument("alias")
@click.pass_context
def cmd_clients_rename(ctx, target_browser, alias):
"""Set the profile alias used to identify this browser instance."""
root_obj = ctx.find_root().obj or {}
selected_browser = target_browser or root_obj.get("browser")
try:
_ensure_unique_browser_alias(alias, selected_browser)
send_command("clients.rename_profile", {"alias": alias}, profile=selected_browser)
except BrowserNotConnected as e:
console.print(f"[red]Error:[/red] {e}")
sys.exit(1)
console.print(f"[green]Profile renamed to '{alias}'[/green]")