mcp_execution_skill/
template.rs1use std::sync::LazyLock;
7
8use handlebars::Handlebars;
9use thiserror::Error;
10
11use crate::types::GenerateSkillResult;
12
13#[derive(Debug, Error)]
15pub enum TemplateError {
16 #[error("template rendering failed: {0}")]
18 RenderFailed(#[from] handlebars::RenderError),
19
20 #[error("template registration failed: {0}")]
22 RegistrationFailed(#[from] handlebars::TemplateError),
23}
24
25const SKILL_GENERATION_TEMPLATE: &str = include_str!("templates/skill-generation.hbs");
27
28static HANDLEBARS: LazyLock<Handlebars<'static>> = LazyLock::new(|| {
33 let mut hb = Handlebars::new();
34 hb.register_template_string("skill", SKILL_GENERATION_TEMPLATE)
35 .expect("embedded template must be valid Handlebars syntax");
36 hb
37});
38
39pub fn render_generation_prompt(context: &GenerateSkillResult) -> Result<String, TemplateError> {
65 let rendered = HANDLEBARS.render("skill", context)?;
67 Ok(rendered)
68}
69
70#[allow(dead_code)]
76pub fn get_prebuilt_prompt(context: &GenerateSkillResult) -> &str {
77 &context.generation_prompt
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::types::{SkillCategory, SkillTool, ToolExample};
84
85 fn create_test_context() -> GenerateSkillResult {
86 GenerateSkillResult {
87 server_id: "test".to_string(),
88 skill_name: "test-progressive".to_string(),
89 server_description: Some("Test server".to_string()),
90 categories: vec![SkillCategory {
91 name: "test".to_string(),
92 display_name: "Test".to_string(),
93 tools: vec![SkillTool {
94 name: "test_tool".to_string(),
95 typescript_name: "testTool".to_string(),
96 description: "Test tool description".to_string(),
97 keywords: vec!["test".to_string()],
98 required_params: vec!["param1".to_string()],
99 optional_params: vec![],
100 }],
101 }],
102 tool_count: 1,
103 example_tools: vec![ToolExample {
104 tool_name: "test_tool".to_string(),
105 description: "Test tool".to_string(),
106 cli_command: "node test.ts".to_string(),
107 params_json: "{}".to_string(),
108 }],
109 generation_prompt: "Pre-built prompt".to_string(),
110 output_path: "~/.claude/skills/test/SKILL.md".to_string(),
111 }
112 }
113
114 #[test]
115 fn test_render_generation_prompt() {
116 let context = create_test_context();
117 let result = render_generation_prompt(&context);
118
119 match result {
120 Ok(prompt) => {
121 assert!(prompt.contains("test"));
123 assert!(prompt.contains("SKILL.md"));
124 }
125 Err(e) => panic!("Template rendering failed: {e}"),
126 }
127 }
128
129 #[test]
130 fn test_get_prebuilt_prompt() {
131 let context = create_test_context();
132 let prompt = get_prebuilt_prompt(&context);
133
134 assert_eq!(prompt, "Pre-built prompt");
135 }
136}