From 7c2fa9a9ac5f1acf860d329c2f3e82d4354f6835 Mon Sep 17 00:00:00 2001 From: Daniel Dolezal Date: Thu, 9 Apr 2026 08:46:50 +0200 Subject: [PATCH] move socket path into /tmp/.browser_cli subfolder with registry --- browser_cli/cli.py | 10 +++++++++- browser_cli/client.py | 32 ++++++++++++++++++++++++-------- browser_cli/native_host.py | 6 ++++-- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/browser_cli/cli.py b/browser_cli/cli.py index 2c99db3..d8249b9 100755 --- a/browser_cli/cli.py +++ b/browser_cli/cli.py @@ -41,8 +41,16 @@ NATIVE_HOST_DIRS = { @click.group() -def main(): +@click.option( + "--browser", default=None, metavar="ALIAS", + help="Browser profile alias to target (required when multiple browsers are active).", +) +@click.pass_context +def main(ctx, browser): """Control your running browser from the terminal via a Chrome extension.""" + ctx.ensure_object(dict) + if browser: + os.environ["BROWSER_CLI_PROFILE"] = browser # ── Sub-command groups ───────────────────────────────────────────────────────── diff --git a/browser_cli/client.py b/browser_cli/client.py index 2c7912f..f934569 100644 --- a/browser_cli/client.py +++ b/browser_cli/client.py @@ -5,8 +5,8 @@ Used by both the CLI and the public Python API. Profile selection order: 1. Explicit `profile` argument to send_command() 2. BROWSER_CLI_PROFILE environment variable - 3. First entry in /tmp/browser-cli-registry.json - 4. Fallback: /tmp/browser-cli-default.sock + 3. First entry in /tmp/.browser_cli/registry.json + 4. Fallback: /tmp/.browser_cli/default.sock """ import json import os @@ -16,14 +16,20 @@ import uuid from pathlib import Path from typing import Any -REGISTRY_PATH = Path("/tmp/browser-cli-registry.json") -DEFAULT_SOCKET = "/tmp/browser-cli-default.sock" +SOCKET_DIR = Path("/tmp/.browser_cli") +REGISTRY_PATH = SOCKET_DIR / "registry.json" +DEFAULT_SOCKET = str(SOCKET_DIR / "default.sock") class BrowserNotConnected(Exception): """Raised when the native host socket is not available.""" +def _active_sockets(reg: dict) -> dict: + """Return only entries whose socket file exists on disk.""" + return {k: v for k, v in reg.items() if Path(v).exists()} + + def _resolve_socket(profile: str | None = None) -> str: """Return the socket path for the given profile (or auto-detect).""" target = profile or os.environ.get("BROWSER_CLI_PROFILE") @@ -37,14 +43,24 @@ def _resolve_socket(profile: str | None = None) -> str: except Exception: pass safe = target.replace(" ", "_").replace("/", "_") - return f"/tmp/browser-cli-{safe}.sock" + return str(SOCKET_DIR / f"{safe}.sock") - # Auto-detect: use first registered entry + # Auto-detect: error when multiple browser instances are active if REGISTRY_PATH.exists(): try: reg = json.loads(REGISTRY_PATH.read_text()) - if reg: - return next(iter(reg.values())) + active = _active_sockets(reg) + if len(active) > 1: + aliases = list(active.keys()) + examples = "\n".join(f" browser-cli --browser {a} ..." for a in aliases) + raise BrowserNotConnected( + f"Multiple browser instances are active: {', '.join(aliases)}\n" + f"Use --browser to select one:\n{examples}" + ) + if active: + return next(iter(active.values())) + except BrowserNotConnected: + raise except Exception: pass diff --git a/browser_cli/native_host.py b/browser_cli/native_host.py index 999c2cb..7b2b2fd 100644 --- a/browser_cli/native_host.py +++ b/browser_cli/native_host.py @@ -20,7 +20,8 @@ import threading import uuid from pathlib import Path -REGISTRY_PATH = Path("/tmp/browser-cli-registry.json") +SOCKET_DIR = Path("/tmp/.browser_cli") +REGISTRY_PATH = SOCKET_DIR / "registry.json" DEFAULT_ALIAS = "default" SOCKET_PATH: str = "" # set after hello handshake @@ -71,7 +72,7 @@ def _registry_remove(alias: str) -> None: def _socket_path_for(alias: str) -> str: safe = alias.replace(" ", "_").replace("/", "_") - return f"/tmp/browser-cli-{safe}.sock" + return str(SOCKET_DIR / f"{safe}.sock") # --- Thread A: read messages from extension (stdin) --- @@ -202,6 +203,7 @@ def main(): PENDING[msg_id] = q write_native_message(sys.stdout.buffer, first_msg) + SOCKET_DIR.mkdir(mode=0o700, exist_ok=True) sock_path = _socket_path_for(alias) _registry_add(alias, sock_path)