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)