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
- 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.
107 lines
3.3 KiB
Python
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]")
|