from __future__ import annotations import json import time from dataclasses import asdict, is_dataclass import click from rich.console import Console from browser_cli.commands import client_from_ctx, handle_errors console = Console() def _snapshot(client): tabs = client.tabs.list() return {str(t.id): asdict(t) if is_dataclass(t) else dict(t) for t in tabs} def _emit(event, json_output: bool): if json_output: click.echo(json.dumps(event, default=str), flush=True) else: kind = event.get("type") tab = event.get("tab") or {} console.print(f"[cyan]{kind}[/cyan] {tab.get('id', '')} {tab.get('title') or ''} [dim]{tab.get('url') or ''}[/dim]") @click.command("events") @click.option("--interval", type=float, default=1.0, show_default=True, help="Polling interval in seconds") @click.option("--once", is_flag=True, help="Emit initial snapshot and exit") @click.option("--json", "json_output", is_flag=True, default=True, help="Emit JSON Lines (default)") @click.option("--pretty", is_flag=True, help="Render human-readable events instead of JSON") @handle_errors def cmd_events(interval: float, once: bool, json_output: bool, pretty: bool): """Stream tab events as JSON Lines using a lightweight polling watcher.""" json_output = json_output and not pretty client = client_from_ctx() previous = _snapshot(client) for tab in previous.values(): _emit({"type": "tabs.snapshot", "tab": tab}, json_output) if once: return while True: time.sleep(interval) current = _snapshot(client) for tab_id, tab in current.items(): if tab_id not in previous: _emit({"type": "tabs.created", "tab": tab}, json_output) elif tab != previous[tab_id]: _emit({"type": "tabs.updated", "tab": tab, "previous": previous[tab_id]}, json_output) for tab_id, tab in previous.items(): if tab_id not in current: _emit({"type": "tabs.closed", "tab": tab}, json_output) previous = current