Files
browser-cli/browser_cli/commands/doctor.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

74 lines
3.0 KiB
Python

from __future__ import annotations
import shutil
import click
from rich.console import Console
from rich.table import Table
from browser_cli.commands import handle_errors, client_from_ctx
from browser_cli.client import active_browser_targets
from browser_cli.constants import NATIVE_HOST_DIRS, NATIVE_HOST_NAME
from browser_cli.platform import is_windows
from browser_cli.version_manager import project_version
console = Console()
def _status(ok: bool) -> str:
return "[green]OK[/green]" if ok else "[red]FAIL[/red]"
@click.command("doctor")
@click.option("--remote", "check_remote", is_flag=True, help="Also probe the configured remote endpoint")
@handle_errors
def cmd_doctor(check_remote):
"""Diagnose browser-cli installation, extension, and connection health."""
rows: list[tuple[str, bool, str]] = []
version = project_version()
rows.append(("Python package", version != "unknown", version))
rows.append(("browser-cli executable", shutil.which("browser-cli") is not None, shutil.which("browser-cli") or "not on PATH"))
manifest_notes = []
if not is_windows():
import sys
platform = "darwin" if sys.platform == "darwin" else "linux"
for browser, by_platform in NATIVE_HOST_DIRS.items():
for directory in by_platform.get(platform, []):
path = directory / f"{NATIVE_HOST_NAME}.json"
if path.exists():
manifest_notes.append(f"{browser}: {path}")
rows.append(("Native host manifest", bool(manifest_notes), "; ".join(manifest_notes) or "not found for common browsers"))
try:
targets = active_browser_targets(include_remotes=check_remote)
rows.append(("Browser registry", bool(targets), f"{len(targets)} active target(s)"))
except Exception as exc:
rows.append(("Browser registry", False, str(exc)))
client = client_from_ctx()
try:
clients = client.clients()
rows.append(("Connection", True, f"{len(clients)} client(s) responded"))
ext_versions = sorted({str(c.get("extensionVersion", "unknown")) for c in clients if isinstance(c, dict)})
if ext_versions:
rows.append(("Extension version", version in ext_versions, ", ".join(ext_versions)))
except Exception as exc:
rows.append(("Connection", False, str(exc)))
try:
info = client.extension.info()
caps = info.get("capabilities") or []
rows.append(("Extension info", True, f"v{info.get('version', 'unknown')} · {len(caps)} capabilities"))
except Exception as exc:
rows.append(("Extension info", False, f"not available ({exc})"))
table = Table(show_header=True, header_style="bold cyan")
table.add_column("Check")
table.add_column("Status")
table.add_column("Details")
for name, ok, detail in rows:
table.add_row(name, _status(ok), detail)
console.print(table)
failed = [name for name, ok, _ in rows if not ok and name in {"Connection", "Browser registry"}]
if failed:
raise SystemExit(1)