add moveing of tabs and groups, multi browser support, auto complite into terminal, extract html and adding testing
This commit is contained in:
+100
-14
@@ -59,22 +59,58 @@ main.add_command(session_group)
|
||||
@main.command("clients")
|
||||
def cmd_clients():
|
||||
"""Show connected browser clients."""
|
||||
try:
|
||||
clients = send_command("clients.list")
|
||||
except BrowserNotConnected as e:
|
||||
console.print(f"[red]Error:[/red] {e}")
|
||||
import json as _json
|
||||
from browser_cli.client import REGISTRY_PATH, DEFAULT_SOCKET
|
||||
|
||||
# Build a map of profile → socket path from the registry
|
||||
profiles: dict[str, str] = {}
|
||||
if REGISTRY_PATH.exists():
|
||||
try:
|
||||
profiles = _json.loads(REGISTRY_PATH.read_text())
|
||||
except Exception:
|
||||
pass
|
||||
if not profiles:
|
||||
profiles = {"default": DEFAULT_SOCKET}
|
||||
|
||||
all_clients = []
|
||||
for profile_name, sock_path in profiles.items():
|
||||
try:
|
||||
result = send_command("clients.list", profile=profile_name)
|
||||
for c in (result or []):
|
||||
c.setdefault("profile", profile_name)
|
||||
all_clients.append(c)
|
||||
except (BrowserNotConnected, RuntimeError):
|
||||
# Socket registered but browser no longer connected
|
||||
all_clients.append({"profile": profile_name, "name": "—", "version": "—", "platform": "disconnected"})
|
||||
|
||||
if not all_clients:
|
||||
console.print("[yellow]No browser clients found[/yellow]")
|
||||
sys.exit(1)
|
||||
|
||||
from rich.table import Table
|
||||
table = Table(show_header=True, header_style="bold cyan")
|
||||
table.add_column("Profile")
|
||||
table.add_column("Browser")
|
||||
table.add_column("Version")
|
||||
table.add_column("Platform")
|
||||
for c in (clients or []):
|
||||
table.add_row(c.get("name", ""), c.get("version", ""), c.get("platform", ""))
|
||||
for c in all_clients:
|
||||
table.add_row(c.get("profile", "default"), c.get("name", ""), c.get("version", ""), c.get("platform", ""))
|
||||
console.print(table)
|
||||
|
||||
|
||||
@main.command("rename-profile")
|
||||
@click.argument("alias")
|
||||
def cmd_rename_profile(alias):
|
||||
"""Set the profile alias used to identify this browser instance."""
|
||||
try:
|
||||
send_command("clients.rename_profile", {"alias": alias})
|
||||
except BrowserNotConnected as e:
|
||||
console.print(f"[red]Error:[/red] {e}")
|
||||
sys.exit(1)
|
||||
console.print(f"[green]Profile renamed to '{alias}'[/green]")
|
||||
console.print(" Restart the browser for the change to take effect.")
|
||||
|
||||
|
||||
# ── install ────────────────────────────────────────────────────────────────────
|
||||
|
||||
@main.command("install")
|
||||
@@ -82,17 +118,19 @@ def cmd_clients():
|
||||
def cmd_install(browser):
|
||||
"""Register the native messaging host and print extension load instructions."""
|
||||
|
||||
# Find the native_host.py path
|
||||
native_host_script = Path(__file__).parent / "native_host.py"
|
||||
if not native_host_script.exists():
|
||||
console.print(f"[red]Cannot find native_host.py at {native_host_script}[/red]")
|
||||
# Find the venv entry point for the native host (stable regardless of project location)
|
||||
venv_script = Path(sys.executable).parent / "browser-cli-native-host"
|
||||
if not venv_script.exists():
|
||||
console.print(f"[red]Cannot find browser-cli-native-host in venv ({venv_script})[/red]")
|
||||
console.print(" Run [cyan]uv sync[/cyan] first to install entry points.")
|
||||
sys.exit(1)
|
||||
|
||||
# Build a wrapper shell script so it's executable by Chrome
|
||||
wrapper_path = Path(__file__).parent.parent / "browser-cli-native-host"
|
||||
python_exe = sys.executable
|
||||
# Install wrapper to ~/.local/bin so the manifest path never changes
|
||||
local_bin = Path.home() / ".local" / "bin"
|
||||
local_bin.mkdir(parents=True, exist_ok=True)
|
||||
wrapper_path = local_bin / "browser-cli-native-host"
|
||||
wrapper_content = f"""#!/bin/sh
|
||||
exec "{python_exe}" "{native_host_script}" "$@"
|
||||
exec "{venv_script}" "$@"
|
||||
"""
|
||||
wrapper_path.write_text(wrapper_content)
|
||||
wrapper_path.chmod(wrapper_path.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
||||
@@ -143,5 +181,53 @@ exec "{python_exe}" "{native_host_script}" "$@"
|
||||
console.print(" After restarting Chrome, try: [cyan]browser-cli tabs list[/cyan]")
|
||||
|
||||
|
||||
# ── completion ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@main.command("completion")
|
||||
@click.argument("shell", type=click.Choice(["zsh", "bash", "fish"]))
|
||||
@click.option("--script", is_flag=True, help="Output the raw completion script instead of instructions")
|
||||
def cmd_completion(shell, script):
|
||||
"""Print shell completion setup instructions (or output the script with --script)."""
|
||||
if script:
|
||||
from click.shell_completion import BashComplete, ZshComplete, FishComplete
|
||||
cls = {"zsh": ZshComplete, "bash": BashComplete, "fish": FishComplete}[shell]
|
||||
comp = cls(main, {}, "browser-cli", "_BROWSER_CLI_COMPLETE")
|
||||
click.echo(comp.source())
|
||||
return
|
||||
|
||||
exe = sys.executable.replace("/python", "/browser-cli").replace("/python3", "/browser-cli")
|
||||
if not Path(exe).exists():
|
||||
exe = "browser-cli"
|
||||
|
||||
env_var = "_BROWSER_CLI_COMPLETE"
|
||||
|
||||
if shell == "zsh":
|
||||
console.print("[bold]Quickest setup — generate the file once:[/bold]")
|
||||
console.print()
|
||||
console.print(f" [cyan]uv run browser-cli completion zsh --script > ~/.zfunc/_browser-cli[/cyan]")
|
||||
console.print()
|
||||
console.print(" Then add these lines to [bold]~/.zshrc[/bold] (before any compinit call):")
|
||||
console.print(" [cyan]fpath=(~/.zfunc $fpath)[/cyan]")
|
||||
console.print(" [cyan]autoload -Uz compinit && compinit[/cyan]")
|
||||
console.print()
|
||||
console.print(" Reload: [cyan]exec zsh[/cyan]")
|
||||
console.print()
|
||||
console.print("[bold]Alternative — eval on every shell start (simpler but slower):[/bold]")
|
||||
console.print(f' [cyan]eval "$({env_var}=zsh_source {exe})"[/cyan]')
|
||||
elif shell == "bash":
|
||||
console.print("[bold]Quickest setup — generate the file once:[/bold]")
|
||||
console.print()
|
||||
console.print(f" [cyan]uv run browser-cli completion bash --script > ~/.bash_completion.d/browser-cli[/cyan]")
|
||||
console.print()
|
||||
console.print(" Reload: [cyan]source ~/.bashrc[/cyan]")
|
||||
console.print()
|
||||
console.print("[bold]Alternative — eval on every shell start:[/bold]")
|
||||
console.print(f' [cyan]eval "$({env_var}=bash_source {exe})"[/cyan]')
|
||||
elif shell == "fish":
|
||||
console.print("[bold]Setup:[/bold]")
|
||||
console.print()
|
||||
console.print(f" [cyan]uv run browser-cli completion fish --script > ~/.config/fish/completions/browser-cli.fish[/cyan]")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user