mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
cua-driver was only installed once on toolset enable: `_run_post_setup` early-returns when the binary is already on PATH, so upstream fixes (e.g. v0.1.6 Safari window-focus fix) never reached existing users without manual reinstall. Two refresh points now: - `hermes update` re-runs the upstream installer at the end of the update if cua-driver is on PATH (macOS-only, no-op otherwise). Ties driver freshness to the user-controlled update cadence — no startup latency, no per-launch GitHub API call. - `hermes computer-use install --upgrade` for manual force-refresh. The upstream `install.sh` always pulls the latest release, so re-running is the canonical upgrade path. No version-comparison logic needed. `hermes computer-use status` now shows the installed version, and points at `--upgrade` for refreshing.
115 lines
5.6 KiB
Python
115 lines
5.6 KiB
Python
"""Tests for ``install_cua_driver`` upgrade semantics.
|
|
|
|
The cua-driver upstream installer always pulls the latest release tag, so
|
|
re-running it is the canonical upgrade path. ``install_cua_driver(upgrade=True)``
|
|
must:
|
|
|
|
* Be macOS-only — no-op silently on Linux/Windows so ``hermes update`` can
|
|
call it unconditionally without warning every non-macOS user.
|
|
* Re-run the installer even when the binary is already on PATH (this is the
|
|
fix for the "we only pulled cua-driver once on enable" complaint).
|
|
* Preserve original ``upgrade=False`` behaviour for the toolset-enable flow:
|
|
skip if installed, install otherwise, warn on non-macOS.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
class TestInstallCuaDriverUpgrade:
|
|
def test_upgrade_on_non_macos_is_silent_noop(self):
|
|
"""``hermes update`` calls install_cua_driver(upgrade=True) for every
|
|
user. On Linux/Windows it must return False without printing the
|
|
"macOS-only; skipping" warning that the toolset-enable path emits."""
|
|
from hermes_cli import tools_config
|
|
|
|
with patch.object(tools_config, "_print_warning") as warn, \
|
|
patch("platform.system", return_value="Linux"):
|
|
assert tools_config.install_cua_driver(upgrade=True) is False
|
|
warn.assert_not_called()
|
|
|
|
def test_non_upgrade_on_non_macos_warns(self):
|
|
"""The toolset-enable path (upgrade=False) should still warn loudly
|
|
when the user tries to enable Computer Use on a non-macOS host."""
|
|
from hermes_cli import tools_config
|
|
|
|
with patch.object(tools_config, "_print_warning") as warn, \
|
|
patch("platform.system", return_value="Linux"):
|
|
assert tools_config.install_cua_driver(upgrade=False) is False
|
|
warn.assert_called()
|
|
|
|
def test_upgrade_on_macos_with_binary_runs_installer(self):
|
|
"""When cua-driver is already on PATH and upgrade=True, we must
|
|
re-run the upstream installer (this is the fix for the bug report).
|
|
"""
|
|
from hermes_cli import tools_config
|
|
|
|
with patch("platform.system", return_value="Darwin"), \
|
|
patch.object(tools_config.shutil, "which",
|
|
side_effect=lambda n: "/usr/local/bin/" + n
|
|
if n in ("cua-driver", "curl") else None), \
|
|
patch.object(tools_config, "_run_cua_driver_installer",
|
|
return_value=True) as runner, \
|
|
patch("subprocess.run"):
|
|
assert tools_config.install_cua_driver(upgrade=True) is True
|
|
runner.assert_called_once()
|
|
# Refresh path uses non-verbose mode so we don't re-print the
|
|
# "grant macOS permissions" block on every `hermes update`.
|
|
kwargs = runner.call_args.kwargs
|
|
assert kwargs.get("verbose") is False
|
|
|
|
def test_upgrade_on_macos_without_binary_runs_installer(self):
|
|
"""upgrade=True with cua-driver missing must still trigger an
|
|
install — equivalent to a fresh install. (Don't silently no-op.)"""
|
|
from hermes_cli import tools_config
|
|
|
|
with patch("platform.system", return_value="Darwin"), \
|
|
patch.object(tools_config.shutil, "which",
|
|
side_effect=lambda n: "/usr/bin/curl" if n == "curl" else None), \
|
|
patch.object(tools_config, "_run_cua_driver_installer",
|
|
return_value=True) as runner:
|
|
assert tools_config.install_cua_driver(upgrade=True) is True
|
|
runner.assert_called_once()
|
|
|
|
def test_non_upgrade_on_macos_with_binary_skips_install(self):
|
|
"""Original toolset-enable behaviour: cua-driver already installed
|
|
+ upgrade=False → confirm and return without re-running installer.
|
|
This is the behaviour that ``hermes tools`` (re)enable depends on,
|
|
so the new helper must not regress it."""
|
|
from hermes_cli import tools_config
|
|
|
|
with patch("platform.system", return_value="Darwin"), \
|
|
patch.object(tools_config.shutil, "which",
|
|
side_effect=lambda n: "/usr/local/bin/" + n
|
|
if n in ("cua-driver", "curl") else None), \
|
|
patch.object(tools_config, "_run_cua_driver_installer") as runner, \
|
|
patch("subprocess.run"):
|
|
assert tools_config.install_cua_driver(upgrade=False) is True
|
|
runner.assert_not_called()
|
|
|
|
def test_non_upgrade_on_macos_without_binary_runs_installer(self):
|
|
"""Original fresh-install path must still work."""
|
|
from hermes_cli import tools_config
|
|
|
|
with patch("platform.system", return_value="Darwin"), \
|
|
patch.object(tools_config.shutil, "which",
|
|
side_effect=lambda n: "/usr/bin/curl" if n == "curl" else None), \
|
|
patch.object(tools_config, "_run_cua_driver_installer",
|
|
return_value=True) as runner:
|
|
assert tools_config.install_cua_driver(upgrade=False) is True
|
|
runner.assert_called_once()
|
|
|
|
def test_upgrade_without_curl_does_not_crash(self):
|
|
"""If curl isn't on PATH we can't refresh — must warn and return
|
|
the current install state, not raise."""
|
|
from hermes_cli import tools_config
|
|
|
|
# cua-driver present, curl missing.
|
|
def _which(name):
|
|
return "/usr/local/bin/cua-driver" if name == "cua-driver" else None
|
|
|
|
with patch("platform.system", return_value="Darwin"), \
|
|
patch.object(tools_config.shutil, "which", side_effect=_which), \
|
|
patch.object(tools_config, "_print_warning"):
|
|
assert tools_config.install_cua_driver(upgrade=True) is True
|