This commit is contained in:
LeonSGP 2026-04-24 16:29:59 -05:00 committed by GitHub
commit b49d00a8fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 33 additions and 2 deletions

View file

@ -241,6 +241,23 @@ class TestSkillViewQualifiedName:
assert result["success"] is False
assert "not found" in result["error"].lower()
def test_category_qualified_local_skill_falls_through(self, tmp_path, monkeypatch):
from tools.skills_tool import skill_view
local_skills = tmp_path / "local-skills"
skill_dir = local_skills / "productivity" / "ticktick"
skill_dir.mkdir(parents=True)
(skill_dir / "SKILL.md").write_text(
"---\nname: ticktick\ndescription: local categorized\n---\nTickTick body.\n"
)
monkeypatch.setattr("tools.skills_tool.SKILLS_DIR", local_skills)
result = json.loads(skill_view("productivity:ticktick"))
assert result["success"] is True
assert result["name"] == "ticktick"
assert "TickTick body." in result["content"]
def test_stale_entry_self_heals(self, tmp_path):
from tools.skills_tool import skill_view

View file

@ -839,6 +839,7 @@ def skill_view(name: str, file_path: str = None, task_id: str = None) -> str:
JSON string with skill content or error message
"""
try:
local_category_name: str | None = None
# ── Qualified name dispatch (plugin skills) ──────────────────
# Names containing ':' are routed to the plugin skill registry.
# Bare names fall through to the existing flat-tree scan below.
@ -893,8 +894,12 @@ def skill_view(name: str, file_path: str = None, task_id: str = None) -> str:
},
ensure_ascii=False,
)
# Plugin itself not found — fall through to flat-tree scan
# which will return a normal "not found" with suggestions.
# Plugin itself not found — fall through to flat-tree scan.
# Categorized local skills also use `category:skill` in config and
# gateway prompts, so preserve that form and translate it to the
# on-disk `category/skill` path during the local scan below.
if bare:
local_category_name = f"{namespace}/{bare}"
from agent.skill_utils import get_external_skills_dirs
@ -927,6 +932,15 @@ def skill_view(name: str, file_path: str = None, task_id: str = None) -> str:
elif direct_path.with_suffix(".md").exists():
skill_md = direct_path.with_suffix(".md")
break
if local_category_name:
categorized_path = search_dir / local_category_name
if categorized_path.is_dir() and (categorized_path / "SKILL.md").exists():
skill_dir = categorized_path
skill_md = categorized_path / "SKILL.md"
break
elif categorized_path.with_suffix(".md").exists():
skill_md = categorized_path.with_suffix(".md")
break
# Search by directory name across all dirs
if not skill_md: