diff --git a/cli/cli.py b/cli/cli.py index d5291c4f..6740667f 100644 --- a/cli/cli.py +++ b/cli/cli.py @@ -5,6 +5,7 @@ from cli import __version__ from cli.commands.skill import skill from cli.commands.process import start, stop, restart, update, status, logs from cli.commands.context import context +from cli.commands.install import install_browser HELP_TEXT = """Usage: cow COMMAND [ARGS]... @@ -21,6 +22,7 @@ Commands: status Show CowAgent running status. logs View CowAgent logs. skill Manage CowAgent skills. + install-browser Install browser tool (Playwright + Chromium). Tip: You can also send /help, /skill list, etc. in agent chat.""" @@ -67,6 +69,7 @@ main.add_command(update) main.add_command(status) main.add_command(logs) main.add_command(context) +main.add_command(install_browser) if __name__ == '__main__': diff --git a/cli/commands/install.py b/cli/commands/install.py new file mode 100644 index 00000000..55d909b8 --- /dev/null +++ b/cli/commands/install.py @@ -0,0 +1,63 @@ +"""cow install-browser - Install Playwright + Chromium for the browser tool.""" + +import os +import sys +import subprocess + +import click + + +def _has_display() -> bool: + """Check if a graphical display is available (Linux only).""" + return bool(os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY")) + + +def _is_headless_linux() -> bool: + """True when running on a Linux server without a display.""" + return sys.platform == "linux" and not _has_display() + + +@click.command("install-browser") +def install_browser(): + """Install browser tool dependencies (Playwright + Chromium).""" + python = sys.executable + + # Step 1: Install playwright package + click.echo(click.style("[1/3] Installing playwright Python package...", fg="yellow")) + ret = subprocess.call([python, "-m", "pip", "install", "playwright"]) + if ret != 0: + click.echo(click.style("Failed to install playwright package.", fg="red")) + raise SystemExit(1) + click.echo(click.style("playwright package installed.", fg="green")) + click.echo() + + # Step 2: System dependencies (Linux only) + if sys.platform == "linux": + click.echo(click.style("[2/3] Installing system dependencies (Linux)...", fg="yellow")) + ret = subprocess.call([python, "-m", "playwright", "install-deps", "chromium"]) + if ret != 0: + click.echo(click.style( + "Could not auto-install system deps (may need sudo).\n" + f" Run manually: sudo {python} -m playwright install-deps chromium", + fg="yellow", + )) + else: + click.echo(click.style(f"[2/3] Skipping system deps (not needed on {sys.platform}).", fg="yellow")) + click.echo() + + # Step 3: Install Chromium (headless shell on Linux servers, full elsewhere) + click.echo(click.style("[3/3] Installing Chromium browser...", fg="yellow")) + cmd = [python, "-m", "playwright", "install", "chromium"] + if _is_headless_linux(): + cmd.append("--only-shell") + click.echo(" (headless-only mode for Linux server)") + elif sys.platform == "linux": + click.echo(" (full browser for Linux desktop)") + + ret = subprocess.call(cmd) + if ret != 0: + click.echo(click.style("Failed to install Chromium.", fg="red")) + raise SystemExit(1) + + click.echo() + click.echo(click.style("Browser tool ready! Restart CowAgent to enable it.", fg="green")) diff --git a/run.sh b/run.sh index f72320d1..0ee3aa0c 100755 --- a/run.sh +++ b/run.sh @@ -585,6 +585,7 @@ start_project() { echo -e " ${GREEN}cow status${NC} Check status" echo -e " ${GREEN}cow logs${NC} View logs" echo -e " ${GREEN}cow update${NC} Update and restart" + echo -e " ${GREEN}cow install-browser${NC} Install browser tool" else echo -e " ${GREEN}./run.sh stop${NC} Stop the service" echo -e " ${GREEN}./run.sh restart${NC} Restart the service"