MCPcopy
hub / github.com/github/spec-kit / HookExecutor

Class HookExecutor

src/specify_cli/extensions/__init__.py:2862–3507  ·  view source on GitHub ↗

Manages extension hook execution.

Source from the content-addressed store, hash-verified

2860
2861
2862class HookExecutor:
2863 """Manages extension hook execution."""
2864
2865 def __init__(self, project_root: Path):
2866 """Initialize hook executor.
2867
2868 Args:
2869 project_root: Root directory of the spec-kit project
2870 """
2871 self.project_root = project_root
2872 self.extensions_dir = project_root / ".specify" / "extensions"
2873 self.config_file = project_root / ".specify" / "extensions.yml"
2874 self._init_options_cache: Optional[Dict[str, Any]] = None
2875
2876 def _load_init_options(self) -> Dict[str, Any]:
2877 """Load persisted init options used to determine invocation style.
2878
2879 Uses the shared helper from specify_cli and caches values per executor
2880 instance to avoid repeated filesystem reads during hook rendering.
2881 """
2882 if self._init_options_cache is None:
2883 from .. import load_init_options
2884
2885 payload = load_init_options(self.project_root)
2886 self._init_options_cache = payload if isinstance(payload, dict) else {}
2887 return self._init_options_cache
2888
2889 @staticmethod
2890 def _skill_name_from_command(command: Any) -> str:
2891 """Map a command id like speckit.plan to speckit-plan skill name."""
2892 if not isinstance(command, str):
2893 return ""
2894 command_id = command.strip()
2895 if not command_id.startswith("speckit."):
2896 return ""
2897 return f"speckit-{command_id[len('speckit.') :].replace('.', '-')}"
2898
2899 def _render_hook_invocation(self, command: Any) -> str:
2900 """Render an agent-specific invocation string for a hook command."""
2901 if not isinstance(command, str):
2902 return ""
2903
2904 command_id = command.strip()
2905 if not command_id:
2906 return ""
2907
2908 init_options = self._load_init_options()
2909 selected_ai = init_options.get("ai")
2910 ai_skills_enabled = is_ai_skills_enabled(init_options)
2911
2912 dollar_skill_mode = is_dollar_skills_agent(selected_ai, ai_skills_enabled)
2913 kimi_skill_mode = selected_ai == "kimi"
2914 cline_mode = selected_ai == "cline"
2915
2916 skill_name = self._skill_name_from_command(command_id)
2917 if dollar_skill_mode and skill_name:
2918 return f"${skill_name}"
2919 if kimi_skill_mode and skill_name:

Calls

no outgoing calls