"""Helper script for Robot Framework skill registry smoke tests. Usage: python helper_skill_registry.py Commands: register-and-get Register a skill and retrieve it list-filter Register skills and list with namespace filter update-skill Register and update a skill duplicate-reject Verify duplicate skill names are rejected remove-skill Register and remove a skill """ from __future__ import annotations import sys from pathlib import Path # Ensure src is on the path src_dir = str(Path(__file__).resolve().parents[1] / "src") if src_dir not in sys.path: sys.path.insert(0, src_dir) from sqlalchemy import create_engine, event, text # noqa: E402 from sqlalchemy.orm import Session, sessionmaker # noqa: E402 from cleveragents.application.services.skill_registry_service import ( # noqa: E402 SkillRegistryService, ) from cleveragents.domain.models.core.skill import Skill # noqa: E402 from cleveragents.infrastructure.database.models import Base # noqa: E402 from cleveragents.infrastructure.database.repositories import ( # noqa: E402 DuplicateSkillError, SkillRepository, ) def _enable_fk_pragma(dbapi_conn, _connection_record): # type: ignore[no-untyped-def] """Enable SQLite foreign key enforcement per connection.""" cursor = dbapi_conn.cursor() cursor.execute("PRAGMA foreign_keys=ON") cursor.close() def _setup() -> tuple[SkillRegistryService, sessionmaker[Session]]: """Create an in-memory DB and return the service + session factory.""" engine = create_engine("sqlite:///:memory:", echo=False) event.listen(engine, "connect", _enable_fk_pragma) Base.metadata.create_all(engine) factory: sessionmaker[Session] = sessionmaker(bind=engine) repo = SkillRepository(session_factory=factory) svc = SkillRegistryService(skill_repo=repo) return svc, factory def _commit(factory: sessionmaker[Session]) -> None: """Commit the pending transaction on the shared connection.""" session = factory() try: session.execute(text("SELECT 1")) session.commit() finally: session.close() def _make_skill(name: str, description: str = "Test skill") -> Skill: return Skill(name=name, description=description) def cmd_register_and_get() -> None: svc, factory = _setup() skill = _make_skill("local/test-tool", "A test skill") svc.add_skill(skill) _commit(factory) result = svc.get_skill("local/test-tool") assert result is not None, "Skill not found" assert result.name == "local/test-tool" print("skill-registry-ok") def cmd_list_filter() -> None: svc, factory = _setup() svc.add_skill(_make_skill("local/tool-a", "Tool A")) svc.add_skill(_make_skill("local/tool-b", "Tool B")) svc.add_skill(_make_skill("devops/deploy", "Deploy")) _commit(factory) all_skills = svc.list_skills() assert len(all_skills) == 3 local_skills = svc.list_skills(namespace="local") assert len(local_skills) == 2 print("skill-list-ok") def cmd_update_skill() -> None: svc, factory = _setup() svc.add_skill(_make_skill("local/updatable", "Original")) _commit(factory) updated = _make_skill("local/updatable", "Updated desc") svc.update_skill(updated) _commit(factory) result = svc.get_skill("local/updatable") assert result is not None assert result.description == "Updated desc" print("skill-update-ok") def cmd_duplicate_reject() -> None: svc, factory = _setup() svc.add_skill(_make_skill("local/dup-test", "First")) _commit(factory) try: svc.add_skill(_make_skill("local/dup-test", "Second")) _commit(factory) print("FAIL: should have raised DuplicateSkillError") sys.exit(1) except DuplicateSkillError: print("skill-duplicate-reject-ok") except Exception as exc: # tenacity may wrap the error; unwrap if needed cause = exc.__cause__ or exc if isinstance(cause, DuplicateSkillError): print("skill-duplicate-reject-ok") else: print(f"FAIL: unexpected {type(exc).__name__}: {exc}") sys.exit(1) def cmd_remove_skill() -> None: svc, factory = _setup() svc.add_skill(_make_skill("local/removable", "Removable")) _commit(factory) result = svc.remove_skill("local/removable") _commit(factory) assert result is True check = svc.get_skill("local/removable") assert check is None print("skill-remove-ok") COMMANDS = { "register-and-get": cmd_register_and_get, "list-filter": cmd_list_filter, "update-skill": cmd_update_skill, "duplicate-reject": cmd_duplicate_reject, "remove-skill": cmd_remove_skill, } if __name__ == "__main__": if len(sys.argv) < 2 or sys.argv[1] not in COMMANDS: print(f"Usage: {sys.argv[0]} <{'|'.join(COMMANDS)}>", file=sys.stderr) sys.exit(1) COMMANDS[sys.argv[1]]()