diff --git a/tests/tools/test_skills_tool.py b/tests/tools/test_skills_tool.py index 756e1e3b3b2..a99f5a1f68d 100644 --- a/tests/tools/test_skills_tool.py +++ b/tests/tools/test_skills_tool.py @@ -373,6 +373,26 @@ class TestSkillView: assert result["name"] == "my-skill" assert "Step 1" in result["content"] + def test_view_skill_by_frontmatter_name_when_dir_differs(self, tmp_path): + # The on-disk directory ("alias-dir") differs from the skill's + # frontmatter name ("real-skill-name"). skills_list() exposes the + # frontmatter name, so skill_view(name) must resolve it too. + skill_dir = tmp_path / "alias-dir" + skill_dir.mkdir(parents=True, exist_ok=True) + (skill_dir / "SKILL.md").write_text( + "---\n" + "name: real-skill-name\n" + "description: A skill whose directory name differs from its name.\n" + "---\n\n" + "# real-skill-name\n\n" + "Step 1: Do the thing.\n" + ) + with patch("tools.skills_tool.SKILLS_DIR", tmp_path): + raw = skill_view("real-skill-name") + result = json.loads(raw) + assert result["success"] is True + assert "Step 1" in result["content"] + def test_skill_view_applies_template_vars(self, tmp_path): with ( patch("tools.skills_tool.SKILLS_DIR", tmp_path), diff --git a/tools/skills_tool.py b/tools/skills_tool.py index 48274ccfec5..5fb1f561070 100644 --- a/tools/skills_tool.py +++ b/tools/skills_tool.py @@ -1032,10 +1032,21 @@ def skill_view( _record(None, categorized_path.with_suffix(".md")) # Strategy 2: recursive by directory name (catches nested skills - # like "foundations/runtime/explore-codebase" called by bare name). + # like "foundations/runtime/explore-codebase" called by bare name), + # plus frontmatter `name:` lookup. `skills_list()` exposes the + # frontmatter name, so `skill_view(name)` must accept it too even + # when the on-disk directory is a shorter category/alias. for found_skill_md in iter_skill_index_files(search_dir, "SKILL.md"): if found_skill_md.parent.name == name: _record(found_skill_md.parent, found_skill_md) + continue + try: + fm_content = found_skill_md.read_text(encoding="utf-8") + fm, _ = _parse_frontmatter(fm_content) + except Exception: + fm = {} + if fm.get("name") == name: + _record(found_skill_md.parent, found_skill_md) # Strategy 3: legacy flat .md files anywhere under the dir. for found_md in search_dir.rglob(f"{name}.md"):