189 lines
5.0 KiB
Python
189 lines
5.0 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Test script to verify local skills are properly set up."""
|
||
|
|
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from adapters.base import InboundMessage, MessageType
|
||
|
|
from adapters.skill_integration import SkillInvoker
|
||
|
|
|
||
|
|
|
||
|
|
def test_skill_discovery() -> bool:
|
||
|
|
"""Test that skills are discovered correctly."""
|
||
|
|
print("=" * 60)
|
||
|
|
print("Testing Skill Discovery")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
invoker = SkillInvoker()
|
||
|
|
skills = invoker.list_available_skills()
|
||
|
|
|
||
|
|
print(f"\nFound {len(skills)} skill(s):")
|
||
|
|
for skill in skills:
|
||
|
|
print(f" + {skill}")
|
||
|
|
|
||
|
|
if not skills:
|
||
|
|
print(" ! No skills found!")
|
||
|
|
print(
|
||
|
|
" Create skills in: "
|
||
|
|
".claude/skills/<skill-name>/SKILL.md"
|
||
|
|
)
|
||
|
|
|
||
|
|
return len(skills) > 0
|
||
|
|
|
||
|
|
|
||
|
|
def test_skill_info() -> bool:
|
||
|
|
"""Test skill info retrieval."""
|
||
|
|
print("\n" + "=" * 60)
|
||
|
|
print("Testing Skill Info")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
invoker = SkillInvoker()
|
||
|
|
skills = invoker.list_available_skills()
|
||
|
|
|
||
|
|
for skill in skills:
|
||
|
|
info = invoker.get_skill_info(skill)
|
||
|
|
print(f"\n/{skill}:")
|
||
|
|
|
||
|
|
if info:
|
||
|
|
fields = [
|
||
|
|
("Name", "name"),
|
||
|
|
("Description", "description"),
|
||
|
|
("User-invocable", "user-invocable"),
|
||
|
|
("Disable auto-invoke", "disable-model-invocation"),
|
||
|
|
("Allowed tools", "allowed-tools"),
|
||
|
|
("Context", "context"),
|
||
|
|
("Agent", "agent"),
|
||
|
|
("Path", "path"),
|
||
|
|
]
|
||
|
|
for label, key in fields:
|
||
|
|
print(f" {label}: {info.get(key, 'N/A')}")
|
||
|
|
|
||
|
|
body_preview = info.get("body", "")[:100]
|
||
|
|
print(f" Instructions preview: {body_preview}...")
|
||
|
|
else:
|
||
|
|
print(" ! Could not load skill info")
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
def test_skill_structure() -> bool:
|
||
|
|
"""Test skill directory structure."""
|
||
|
|
print("\n" + "=" * 60)
|
||
|
|
print("Testing Skill Structure")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
skills_dir = Path(".claude/skills")
|
||
|
|
|
||
|
|
if not skills_dir.exists():
|
||
|
|
print(
|
||
|
|
" ! Skills directory not found: "
|
||
|
|
".claude/skills/"
|
||
|
|
)
|
||
|
|
return False
|
||
|
|
|
||
|
|
print(f"\nSkills directory: {skills_dir.absolute()}")
|
||
|
|
|
||
|
|
for skill_dir in skills_dir.iterdir():
|
||
|
|
if not skill_dir.is_dir():
|
||
|
|
continue
|
||
|
|
|
||
|
|
skill_md = skill_dir / "SKILL.md"
|
||
|
|
examples_dir = skill_dir / "examples"
|
||
|
|
|
||
|
|
md_icon = "+" if skill_md.exists() else "x"
|
||
|
|
ex_icon = "+" if examples_dir.exists() else "-"
|
||
|
|
|
||
|
|
print(f"\n {skill_dir.name}/")
|
||
|
|
print(f" SKILL.md: {md_icon}")
|
||
|
|
print(f" examples/: {ex_icon} (optional)")
|
||
|
|
|
||
|
|
if examples_dir.exists():
|
||
|
|
for ef in examples_dir.glob("*.md"):
|
||
|
|
print(f" - {ef.name}")
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
def test_preprocessor() -> bool:
|
||
|
|
"""Test skill preprocessor logic."""
|
||
|
|
print("\n" + "=" * 60)
|
||
|
|
print("Testing Skill Preprocessor")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
test_message = InboundMessage(
|
||
|
|
platform="test",
|
||
|
|
user_id="test123",
|
||
|
|
username="testuser",
|
||
|
|
text="/adapter-dev create WhatsApp adapter",
|
||
|
|
channel_id="test-channel",
|
||
|
|
thread_id=None,
|
||
|
|
reply_to_id=None,
|
||
|
|
message_type=MessageType.TEXT,
|
||
|
|
metadata={},
|
||
|
|
raw=None,
|
||
|
|
)
|
||
|
|
|
||
|
|
print(f"\nTest message: {test_message.text}")
|
||
|
|
|
||
|
|
if not test_message.text.startswith("/"):
|
||
|
|
return False
|
||
|
|
|
||
|
|
parts = test_message.text.split(maxsplit=1)
|
||
|
|
skill_name = parts[0][1:]
|
||
|
|
args = parts[1] if len(parts) > 1 else ""
|
||
|
|
|
||
|
|
print(f" Detected skill: {skill_name}")
|
||
|
|
print(f" Arguments: {args}")
|
||
|
|
|
||
|
|
invoker = SkillInvoker()
|
||
|
|
if skill_name in invoker.list_available_skills():
|
||
|
|
print(" + Skill exists and can be invoked")
|
||
|
|
return True
|
||
|
|
|
||
|
|
print(" ! Skill not found")
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> bool:
|
||
|
|
"""Run all tests."""
|
||
|
|
print("\nAjarbot Skills Test Suite\n")
|
||
|
|
|
||
|
|
results = [
|
||
|
|
("Skill Discovery", test_skill_discovery()),
|
||
|
|
("Skill Info", test_skill_info()),
|
||
|
|
("Skill Structure", test_skill_structure()),
|
||
|
|
("Skill Preprocessor", test_preprocessor()),
|
||
|
|
]
|
||
|
|
|
||
|
|
print("\n" + "=" * 60)
|
||
|
|
print("Test Summary")
|
||
|
|
print("=" * 60)
|
||
|
|
|
||
|
|
for test_name, passed in results:
|
||
|
|
status = "+ PASS" if passed else "x FAIL"
|
||
|
|
print(f" {status}: {test_name}")
|
||
|
|
|
||
|
|
passed_count = sum(1 for _, p in results if p)
|
||
|
|
total_count = len(results)
|
||
|
|
|
||
|
|
print(f"\n{passed_count}/{total_count} tests passed")
|
||
|
|
|
||
|
|
if passed_count == total_count:
|
||
|
|
print("\nAll tests passed! Skills are ready to use.")
|
||
|
|
print("\nNext steps:")
|
||
|
|
print(" 1. Try invoking a skill: /adapter-dev")
|
||
|
|
print(
|
||
|
|
" 2. Test in bot: "
|
||
|
|
"python example_bot_with_skills.py"
|
||
|
|
)
|
||
|
|
print(" 3. Create your own skills in: .claude/skills/")
|
||
|
|
else:
|
||
|
|
print("\nSome tests failed. Check the output above.")
|
||
|
|
|
||
|
|
return passed_count == total_count
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
success = main()
|
||
|
|
sys.exit(0 if success else 1)
|