This commit is contained in:
+71
-24
@@ -28,6 +28,7 @@ from browser_cli.client import (
|
||||
active_browser_targets,
|
||||
display_browser_name,
|
||||
)
|
||||
from browser_cli.platform import install_base_dir, is_windows
|
||||
|
||||
console = Console()
|
||||
|
||||
@@ -56,6 +57,14 @@ NATIVE_HOST_DIRS = {
|
||||
},
|
||||
}
|
||||
|
||||
WINDOWS_NATIVE_HOST_REGISTRY_KEYS = {
|
||||
"chrome": [r"Software\Google\Chrome\NativeMessagingHosts"],
|
||||
"chromium": [r"Software\Chromium\NativeMessagingHosts"],
|
||||
"brave": [r"Software\BraveSoftware\Brave-Browser\NativeMessagingHosts"],
|
||||
"edge": [r"Software\Microsoft\Edge\NativeMessagingHosts"],
|
||||
"vivaldi": [r"Software\Vivaldi\NativeMessagingHosts"],
|
||||
}
|
||||
|
||||
|
||||
def _rename_target_profile(target_browser: str | None) -> str | None:
|
||||
if target_browser:
|
||||
@@ -82,10 +91,9 @@ def _ensure_unique_browser_alias(alias: str, target_browser: str | None) -> None
|
||||
|
||||
|
||||
def _native_host_wrapper_path() -> Path:
|
||||
if sys.platform == "darwin":
|
||||
base_dir = Path.home() / "Library" / "Application Support" / "browser-cli"
|
||||
else:
|
||||
base_dir = Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share")) / "browser-cli"
|
||||
base_dir = install_base_dir()
|
||||
if is_windows():
|
||||
return base_dir / "libexec" / "native-host.cmd"
|
||||
return base_dir / "libexec" / "native-host"
|
||||
|
||||
|
||||
@@ -93,6 +101,30 @@ def _native_host_script_path() -> Path:
|
||||
return _native_host_wrapper_path().with_name("native_host.py")
|
||||
|
||||
|
||||
def _windows_registry_views():
|
||||
import winreg
|
||||
|
||||
return [0, getattr(winreg, "KEY_WOW64_32KEY", 0), getattr(winreg, "KEY_WOW64_64KEY", 0)]
|
||||
|
||||
|
||||
def _register_windows_native_host(browser: str, manifest_path: Path) -> list[str]:
|
||||
import winreg
|
||||
|
||||
installed = []
|
||||
for key_path in WINDOWS_NATIVE_HOST_REGISTRY_KEYS[browser]:
|
||||
full_key = f"{key_path}\\{NATIVE_HOST_NAME}"
|
||||
for view in _windows_registry_views():
|
||||
try:
|
||||
access = winreg.KEY_WRITE | view
|
||||
key = winreg.CreateKeyEx(winreg.HKEY_CURRENT_USER, full_key, 0, access)
|
||||
with key:
|
||||
winreg.SetValueEx(key, "", 0, winreg.REG_SZ, str(manifest_path))
|
||||
installed.append(f"HKCU\\{full_key}")
|
||||
except OSError as e:
|
||||
console.print(f"[yellow]Could not write registry key {full_key}: {e}[/yellow]")
|
||||
return installed
|
||||
|
||||
|
||||
def _project_version() -> str:
|
||||
pyproject_path = Path(__file__).resolve().parent.parent / "pyproject.toml"
|
||||
try:
|
||||
@@ -235,12 +267,16 @@ def cmd_install(browser):
|
||||
native_host_script_path = _native_host_script_path()
|
||||
wrapper_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(Path(__file__).with_name("native_host.py"), native_host_script_path)
|
||||
native_host_script_path.chmod(
|
||||
native_host_script_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
||||
)
|
||||
wrapper_content = f'#!/bin/sh\nexec "{sys.executable}" "{native_host_script_path}" "$@"\n'
|
||||
wrapper_path.write_text(wrapper_content)
|
||||
wrapper_path.chmod(wrapper_path.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
||||
if not is_windows():
|
||||
native_host_script_path.chmod(
|
||||
native_host_script_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
||||
)
|
||||
wrapper_content = f'#!/bin/sh\nexec "{sys.executable}" "{native_host_script_path}" "$@"\n'
|
||||
wrapper_path.write_text(wrapper_content)
|
||||
wrapper_path.chmod(wrapper_path.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
||||
else:
|
||||
wrapper_content = f'@echo off\r\n"{sys.executable}" "{native_host_script_path}" %*\r\n'
|
||||
wrapper_path.write_text(wrapper_content, encoding="utf-8")
|
||||
|
||||
# Ask for extension ID
|
||||
ext_urls = {
|
||||
@@ -269,30 +305,41 @@ def cmd_install(browser):
|
||||
"allowed_origins": [f"chrome-extension://{extension_id}/"],
|
||||
}
|
||||
|
||||
# Write to OS native messaging dirs
|
||||
platform = "darwin" if sys.platform == "darwin" else "linux"
|
||||
dirs = NATIVE_HOST_DIRS[browser][platform]
|
||||
|
||||
installed = []
|
||||
for d in dirs:
|
||||
try:
|
||||
d.mkdir(parents=True, exist_ok=True)
|
||||
manifest_path = d / f"{NATIVE_HOST_NAME}.json"
|
||||
manifest_path.write_text(json.dumps(manifest, indent=2))
|
||||
installed.append(manifest_path)
|
||||
except Exception as e:
|
||||
console.print(f"[yellow]Could not write to {d}: {e}[/yellow]")
|
||||
if is_windows():
|
||||
manifest_dir = wrapper_path.parent
|
||||
manifest_dir.mkdir(parents=True, exist_ok=True)
|
||||
manifest_path = manifest_dir / f"{NATIVE_HOST_NAME}.json"
|
||||
manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
|
||||
installed = _register_windows_native_host(browser, manifest_path)
|
||||
else:
|
||||
platform = "darwin" if sys.platform == "darwin" else "linux"
|
||||
dirs = NATIVE_HOST_DIRS[browser][platform]
|
||||
|
||||
for d in dirs:
|
||||
try:
|
||||
d.mkdir(parents=True, exist_ok=True)
|
||||
manifest_path = d / f"{NATIVE_HOST_NAME}.json"
|
||||
manifest_path.write_text(json.dumps(manifest, indent=2))
|
||||
installed.append(manifest_path)
|
||||
except Exception as e:
|
||||
console.print(f"[yellow]Could not write to {d}: {e}[/yellow]")
|
||||
|
||||
if not installed:
|
||||
console.print("[red]Failed to install native host manifest[/red]")
|
||||
sys.exit(1)
|
||||
|
||||
for p in installed:
|
||||
console.print(f"[green]✓[/green] Wrote native host manifest: {p}")
|
||||
if is_windows():
|
||||
console.print(f"[green]✓[/green] Registered native host: {p}")
|
||||
else:
|
||||
console.print(f"[green]✓[/green] Wrote native host manifest: {p}")
|
||||
console.print(f"[green]✓[/green] Installed native host script: {native_host_script_path}")
|
||||
console.print(f"[green]✓[/green] Installed native host wrapper: {wrapper_path}")
|
||||
if is_windows():
|
||||
console.print("\n[green]✓[/green] Wrote native host manifest:", manifest_path)
|
||||
|
||||
console.print(f"\n[bold]Step 2:[/bold] Restart {browser.capitalize()} completely (Cmd/Ctrl+Q, then reopen)")
|
||||
console.print(f"\n[bold]Step 2:[/bold] Restart {browser.capitalize()} completely (quit app, then reopen)")
|
||||
console.print("\n[green bold]✓ Installation complete![/green bold]")
|
||||
console.print(" After restarting the browser, try: [cyan]browser-cli tabs list[/cyan]")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user