fix(plugins): alias-normalize enable/disable for nested category plugins (follow-up to #41076)

#41076 makes `hermes plugins list` discover nested category plugins (e.g.
observability/nemo_relay). This adds the missing enable/disable mutation path
so those plugins can actually be toggled, and fixes two incomplete-update
breakages on the #41076 base.

Before: `hermes plugins enable nemo_relay` -> "Plugin 'nemo_relay' is not
installed or bundled." (exit 1), because cmd_enable/cmd_disable went through
_plugin_exists(), which only checked top-level plugins/<name>/.

Changes:
- Add _resolve_plugin_key(): resolve a bare manifest/leaf name OR a full
  path-derived key (observability/nemo_relay) to the canonical key the runtime
  loader gates on, reusing #41076's _discover_all_plugins(). A bare leaf name
  ambiguous across two categories resolves to None rather than silently picking
  one.
- cmd_enable/cmd_disable resolve first, persist the canonical key, and drop any
  stale legacy bare-name alias so the enabled/disabled lists can't drift into a
  contradictory state. _plugin_exists delegates to the same resolver.
- Fix #41076 base breakages: _discover_all_plugins now returns 6-tuples, but
  web_server._merged_plugins_hub() still unpacked 5 (ValueError on the
  dashboard plugins-hub endpoint) and several test_plugins_cmd_list.py fixtures
  were still 5-tuples. Both updated; the hub status check is now key-aware.

Verified e2e on the real CLI + runtime loader (isolated HERMES_HOME):
`hermes plugins enable nemo_relay` writes observability/nemo_relay to
config.yaml and the loader then loads it (enabled=True, error=None); a stale
bare-name alias is cleared on disable; the dashboard _merged_plugins_hub() runs
without crashing. Adds resolution + enable/disable tests; full
tests/hermes_cli/test_plugins_cmd* + web_server plugin tests green.

Follow-up to #41076 (#41066). Branched from that PR's head.
This commit is contained in:
kshitijk4poor
2026-06-08 17:57:37 +05:30
parent ccacfdbd6d
commit 2b89afec79
4 changed files with 265 additions and 48 deletions
+9 -9
View File
@@ -18,9 +18,9 @@ def _args(**kwargs):
def test_filter_plugin_entries_enabled_only():
entries = [
("disk-cleanup", "2.0.0", "Bundled", "bundled", None),
("web-search-plus", "2.2.0", "Search", "git", None),
("old-plugin", "1.0.0", "Old", "user", None),
("disk-cleanup", "2.0.0", "Bundled", "bundled", None, "disk-cleanup"),
("web-search-plus", "2.2.0", "Search", "git", None, "web-search-plus"),
("old-plugin", "1.0.0", "Old", "user", None, "old-plugin"),
]
filtered = plugins_cmd._filter_plugin_entries(
@@ -35,9 +35,9 @@ def test_filter_plugin_entries_enabled_only():
def test_filter_plugin_entries_no_bundled():
entries = [
("disk-cleanup", "2.0.0", "Bundled", "bundled", None),
("drawthings-grpc", "0.3.0", "Draw Things", "user", None),
("web-search-plus", "2.2.0", "Search", "git", None),
("disk-cleanup", "2.0.0", "Bundled", "bundled", None, "disk-cleanup"),
("drawthings-grpc", "0.3.0", "Draw Things", "user", None, "drawthings-grpc"),
("web-search-plus", "2.2.0", "Search", "git", None, "web-search-plus"),
]
filtered = plugins_cmd._filter_plugin_entries(
@@ -52,8 +52,8 @@ def test_filter_plugin_entries_no_bundled():
def test_cmd_list_plain_compact_output(monkeypatch, capsys):
entries = [
("disk-cleanup", "2.0.0", "Bundled", "bundled", None),
("web-search-plus", "2.2.0", "Search", "git", None),
("disk-cleanup", "2.0.0", "Bundled", "bundled", None, "disk-cleanup"),
("web-search-plus", "2.2.0", "Search", "git", None, "web-search-plus"),
]
monkeypatch.setattr(plugins_cmd, "_discover_all_plugins", lambda: entries)
monkeypatch.setattr(plugins_cmd, "_get_enabled_set", lambda: {"web-search-plus"})
@@ -69,7 +69,7 @@ def test_cmd_list_plain_compact_output(monkeypatch, capsys):
def test_cmd_list_json_output(monkeypatch, capsys):
entries = [("web-search-plus", "2.2.0", "Search", "git", None)]
entries = [("web-search-plus", "2.2.0", "Search", "git", None, "web-search-plus")]
monkeypatch.setattr(plugins_cmd, "_discover_all_plugins", lambda: entries)
monkeypatch.setattr(plugins_cmd, "_get_enabled_set", lambda: {"web-search-plus"})
monkeypatch.setattr(plugins_cmd, "_get_disabled_set", lambda: set())