feat(curator): add hermes curator list-archived command (#21236)

Lists the skills sitting in ~/.hermes/skills/.archive/ so users have
something to pass to `hermes curator restore`. `curator status` already
shows counts; this fills the name-discovery gap.

Archive layout is flat (`archive_skill` writes to `.archive/<skill>/`),
so the directory name IS the skill name — no frontmatter parsing
needed. Timestamped collision directories (`<skill>-<ts>`) are listed
literally; user can still pass them to `restore`.

Reshape of @EvilDrag0n's #20651, simplified: drop the frontmatter
rglob + preamble/trailer output + duplicate subcommand registration.

Co-authored-by: EvilDrag0n <lxl694522264@gmail.com>
This commit is contained in:
Teknium 2026-05-07 05:46:51 -07:00 committed by GitHub
parent 47bf5d7ecb
commit ae1f058b3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 31 additions and 2 deletions

View file

@ -205,6 +205,19 @@ def list_agent_created_skill_names() -> List[str]:
return sorted(set(names))
def list_archived_skill_names() -> List[str]:
"""Enumerate skills in ``~/.hermes/skills/.archive/``.
Archive layout is flat (``.archive/<skill>/``) as set by ``archive_skill``,
so the directory name is the skill name. Used by ``hermes curator
list-archived`` to help users pass a name to ``hermes curator restore``.
"""
archive_root = _archive_dir()
if not archive_root.exists():
return []
return sorted({p.name for p in archive_root.iterdir() if p.is_dir()})
def _read_skill_name(skill_md: Path, fallback: str) -> str:
"""Parse the `name:` field from a SKILL.md YAML frontmatter."""
try: