Files
hermes-agent/tests/tui_gateway/test_plugins_manage_install.py
T
Teknium dcb3e27b23 feat(desktop): streamline catalog UX — reviewed-entry install flow, update chips, actionable drift badge
- Catalog picks skip the raw-git ceremony: reviewed heading instead of the
  scare card, no force toggle, enable pre-checked; success toast offers
  'Restart gateway' inline; missing-env warning deep-links to Tools & Keys.
- plugins.manage list now carries catalog provenance (sidecar) + a backend-
  computed update_available; new 'update' action re-pins catalog installs
  to the current catalog SHA (non-catalog installs refused — CLI-owned).
- Capabilities rows show tier chip + 'Update to <sha>' button; catalog picks
  for an already-current install are refused with a toast instead of the
  modal reopening.
- Settings drift badge is now a button: opens the dual-target modal
  pre-filled (agent half only, sidecar repo+pin when present).
2026-08-29 00:37:09 -07:00

123 lines
3.4 KiB
Python

"""Gateway plugins.manage install action."""
from unittest.mock import patch
from tui_gateway import server
def test_plugins_manage_install_success():
payload = {
"ok": True,
"plugin_name": "hello-world",
"warnings": [],
"missing_env": [],
"after_install_path": None,
"enabled": True,
}
with patch(
"hermes_cli.plugins_cmd.dashboard_install_plugin",
return_value=payload,
) as mock_install:
resp = server.handle_request(
{
"id": "1",
"method": "plugins.manage",
"params": {
"action": "install",
"repo": "owner/hello-world",
"force": True,
"enable": False,
},
}
)
assert "result" in resp
assert resp["result"]["plugin_name"] == "hello-world"
mock_install.assert_called_once_with(
"owner/hello-world",
force=True,
enable=False,
catalog_name=None,
)
def test_plugins_manage_install_missing_identifier():
resp = server.handle_request(
{
"id": "1",
"method": "plugins.manage",
"params": {"action": "install"},
}
)
assert "error" in resp
assert "identifier" in resp["error"]["message"]
def test_plugins_manage_install_failure():
with patch(
"hermes_cli.plugins_cmd.dashboard_install_plugin",
return_value={"ok": False, "error": "Git clone failed"},
):
resp = server.handle_request(
{
"id": "1",
"method": "plugins.manage",
"params": {
"action": "install",
"identifier": "bad/repo",
},
}
)
assert "error" in resp
assert "Git clone failed" in resp["error"]["message"]
def test_plugins_manage_install_catalog_name_only():
"""A catalog pick needs no identifier — the backend resolves repo + pin."""
payload = {"ok": True, "plugin_name": "weather-plugin", "enabled": False}
with patch(
"hermes_cli.plugins_cmd.dashboard_install_plugin",
return_value=payload,
) as mock_install:
resp = server.handle_request(
{
"id": "1",
"method": "plugins.manage",
"params": {
"action": "install",
"catalog_name": "weather-plugin",
"enable": False,
},
}
)
assert "result" in resp
mock_install.assert_called_once_with(
"",
force=False,
enable=False,
catalog_name="weather-plugin",
)
def test_plugins_manage_update_requires_catalog_sidecar(tmp_path, monkeypatch):
"""Non-catalog installs are refused — their update flows stay CLI-owned."""
import hermes_cli.plugins_cmd as plugins_cmd
plugins_root = tmp_path / "plugins"
(plugins_root / "plain-git-plugin").mkdir(parents=True)
monkeypatch.setattr(plugins_cmd, "_plugins_dir", lambda: plugins_root)
resp = server.handle_request(
{
"id": "1",
"method": "plugins.manage",
"params": {"action": "update", "name": "plain-git-plugin"},
}
)
assert "error" in resp
assert "not a catalog install" in resp["error"]["message"]