fix(curator): scan nested archive subdirs in restore_skill

restore_skill() in tools/skill_usage.py used archive_root.iterdir(), which
only walked the top level of .archive/. Skills archived under nested layouts
(e.g. .archive/openclaw-imports/<skill>/ from older archive paths or
external imports) were invisible to both the exact-match and prefix-match
candidate scans, surfacing as a misleading "skill '<name>' not found in
archive" error even though the directory existed on disk.

Switch both candidate scans to archive_root.rglob('*') so the lookup
descends into category subdirectories.

Fixes #17942
This commit is contained in:
0xDevNinja 2026-04-30 17:55:27 +05:30 committed by Teknium
parent 7913d6a90f
commit 564a649e6a
2 changed files with 40 additions and 3 deletions

View file

@ -315,6 +315,41 @@ def test_restore_skill_moves_back(skills_home):
assert get_record("temp-skill")["state"] == "active"
def test_restore_skill_finds_nested_archive_subdir(skills_home):
"""Skills archived under nested category subdirs (e.g.
.archive/<category>/<skill>/) left behind by older archive layouts or
external imports must still be restorable by name."""
from tools.skill_usage import restore_skill, get_record
skills_dir = skills_home / "skills"
nested = skills_dir / ".archive" / "openclaw-imports" / "nested-skill"
nested.mkdir(parents=True)
(nested / "SKILL.md").write_text(
"---\nname: nested-skill\ndescription: x\n---\n", encoding="utf-8",
)
ok, msg = restore_skill("nested-skill")
assert ok, msg
assert (skills_dir / "nested-skill" / "SKILL.md").exists()
assert not nested.exists()
assert get_record("nested-skill")["state"] == "active"
def test_restore_skill_finds_nested_timestamped_prefix(skills_home):
"""Prefix-match path (timestamped dupes) must also descend into nested
archive subdirs, not just .archive/ top-level."""
from tools.skill_usage import restore_skill
skills_dir = skills_home / "skills"
nested = skills_dir / ".archive" / "imports" / "dup-skill-20260101000000"
nested.mkdir(parents=True)
(nested / "SKILL.md").write_text(
"---\nname: dup-skill\ndescription: x\n---\n", encoding="utf-8",
)
ok, msg = restore_skill("dup-skill")
assert ok, msg
assert (skills_dir / "dup-skill" / "SKILL.md").exists()
def test_archive_collision_gets_suffix(skills_home):
from tools.skill_usage import archive_skill
skills_dir = skills_home / "skills"