feat(skills): show enabled/disabled status in 'skills list' (#16129)

'hermes skills list' now shows every skill's enabled/disabled status
and accepts --enabled-only to filter down to what will actually load
for the active profile:

    hermes -p dario skills list --enabled-only

Previously the command was a flat catalog — it did not apply
skills.disabled from config.yaml, so there was no way to see the
live skill set for a profile without reading config by hand.
Profile switching already works via -p (swaps HERMES_HOME); this
just surfaces the result visibly.

Changes:
- hermes_cli/skills_hub.py: do_list adds a Status column and an
  enabled_only filter; summary reports enabled/disabled split
- hermes_cli/main.py: --enabled-only flag on 'skills list'
- /skills list slash command accepts --enabled-only too
- tests: 4 new (status column, disabled marking, enabled-only
  hiding, no platform leakage into get_disabled_skill_names);
  existing fixtures updated to accept skip_disabled kwarg

Reported by @mochizukimr on X.
This commit is contained in:
Teknium 2026-04-26 09:20:53 -07:00 committed by GitHub
parent eaa7e2db67
commit 0e2a53eab2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 136 additions and 16 deletions

View file

@ -56,7 +56,7 @@ def three_source_env(monkeypatch, hub_env):
import tools.skills_tool as skills_tool
monkeypatch.setattr(hub, "HubLockFile", lambda: _DummyLockFile([_HUB_ENTRY]))
monkeypatch.setattr(skills_tool, "_find_all_skills", lambda: list(_ALL_THREE_SKILLS))
monkeypatch.setattr(skills_tool, "_find_all_skills", lambda **_kwargs: list(_ALL_THREE_SKILLS))
monkeypatch.setattr(skills_sync, "_read_manifest", lambda: dict(_BUILTIN_MANIFEST))
return hub_env
@ -107,7 +107,7 @@ def test_do_list_initializes_hub_dir(monkeypatch, hub_env):
import tools.skills_sync as skills_sync
import tools.skills_tool as skills_tool
monkeypatch.setattr(skills_tool, "_find_all_skills", lambda: [])
monkeypatch.setattr(skills_tool, "_find_all_skills", lambda **_kwargs: [])
monkeypatch.setattr(skills_sync, "_read_manifest", lambda: {})
hub_dir = hub_env
@ -154,6 +154,74 @@ def test_do_list_filter_builtin(three_source_env):
assert "local-skill" not in output
def test_do_list_renders_status_column(three_source_env, monkeypatch):
"""Every list row should carry an enabled/disabled status (new in PR that
answered Mr Mochizuki's 'I just want to see what's live' question)."""
from agent import skill_utils
monkeypatch.setattr(skill_utils, "get_disabled_skill_names", lambda platform=None: set())
output = _capture()
assert "Status" in output
assert "enabled" in output.lower()
# Summary counts enabled skills.
assert "3 enabled, 0 disabled" in output
def test_do_list_marks_disabled_skills(three_source_env, monkeypatch):
from agent import skill_utils
# Simulate `skills.disabled: [hub-skill]` in config.
monkeypatch.setattr(
skill_utils, "get_disabled_skill_names",
lambda platform=None: {"hub-skill"},
)
output = _capture()
# Row still appears (no --enabled-only), but marked disabled
assert "hub-skill" in output
assert "disabled" in output.lower()
assert "2 enabled, 1 disabled" in output
def test_do_list_enabled_only_hides_disabled(three_source_env, monkeypatch):
from agent import skill_utils
monkeypatch.setattr(
skill_utils, "get_disabled_skill_names",
lambda platform=None: {"hub-skill"},
)
sink = StringIO()
console = Console(file=sink, force_terminal=False, color_system=None)
do_list(enabled_only=True, console=console)
output = sink.getvalue()
assert "hub-skill" not in output
assert "builtin-skill" in output
assert "local-skill" in output
assert "enabled only" in output.lower()
assert "2 enabled shown" in output
def test_do_list_platform_env_is_ignored(three_source_env, monkeypatch):
"""`hermes skills list` reads the active profile's config via
HERMES_HOME (swapped by -p), so it must NOT pass a platform arg to
``get_disabled_skill_names`` otherwise per-platform overrides
would silently leak in from HERMES_PLATFORM env."""
from agent import skill_utils
seen = {}
def _fake(platform=None):
seen["platform"] = platform
return set()
monkeypatch.setattr(skill_utils, "get_disabled_skill_names", _fake)
_capture()
assert seen["platform"] is None
def test_do_check_reports_available_updates(monkeypatch):
output = _capture_check(monkeypatch, [
{"name": "hub-skill", "source": "skills.sh", "status": "update_available"},