Validate skill input before execution. Error codes (matching TypeScript): 1 - Missing or invalid skill name 2 - Unknown skill (not found in registry) 4 - Skill has disable_model_invocation set 5 - Skill is not a prompt-based skill
(tool_input: dict[str, Any], context: ToolContext)
| 44 | # --------------------------------------------------------------------------- |
| 45 | |
| 46 | def _validate_skill_input(tool_input: dict[str, Any], context: ToolContext) -> ValidationResult: |
| 47 | """Validate skill input before execution. |
| 48 | |
| 49 | Error codes (matching TypeScript): |
| 50 | 1 - Missing or invalid skill name |
| 51 | 2 - Unknown skill (not found in registry) |
| 52 | 4 - Skill has disable_model_invocation set |
| 53 | 5 - Skill is not a prompt-based skill |
| 54 | """ |
| 55 | skill = tool_input.get("skill") |
| 56 | |
| 57 | # Legacy path: if using 'name' for legacy .py skills, skip validation |
| 58 | # (backward compat -- legacy skills don't go through the registry) |
| 59 | if not skill and tool_input.get("name"): |
| 60 | return ValidationResult.ok() |
| 61 | |
| 62 | if not skill or not isinstance(skill, str): |
| 63 | return ValidationResult.fail( |
| 64 | 'Missing skill name. Pass the slash command name as the skill parameter ' |
| 65 | '(e.g., skill: "commit" for /commit, skill: "review-pr" for /review-pr).', |
| 66 | error_code=1, |
| 67 | ) |
| 68 | |
| 69 | trimmed = skill.strip() |
| 70 | if not trimmed: |
| 71 | return ValidationResult.fail( |
| 72 | f"Invalid skill format: {skill}", |
| 73 | error_code=1, |
| 74 | ) |
| 75 | |
| 76 | # Remove leading slash if present (for compatibility) |
| 77 | command_name = trimmed.lstrip("/") |
| 78 | |
| 79 | # Populate the unified registry for the current cwd, then look up. |
| 80 | # The registry now includes managed/user/project disk skills (with |
| 81 | # nested namespacing like "git:commit"), bundled skills, and any |
| 82 | # MCP-provided skills. `get_registered_skill` falls back to bundled |
| 83 | # alias matching for back-compat. |
| 84 | from src.skills.loader import get_all_skills, get_registered_skill |
| 85 | |
| 86 | get_all_skills(project_root=context.workspace_root) |
| 87 | found = get_registered_skill(command_name) |
| 88 | |
| 89 | if found is None: |
| 90 | return ValidationResult.fail( |
| 91 | f"Unknown skill: {command_name}", |
| 92 | error_code=2, |
| 93 | ) |
| 94 | |
| 95 | # Check if model invocation is disabled |
| 96 | if getattr(found, "disable_model_invocation", False): |
| 97 | return ValidationResult.fail( |
| 98 | f"Skill {command_name} cannot be used with Skill tool due to disable-model-invocation", |
| 99 | error_code=4, |
| 100 | ) |
| 101 | |
| 102 | # Check if it's a prompt-based skill |
| 103 | if getattr(found, "type", "prompt") != "prompt": |
nothing calls this directly
no test coverage detected