use std::sync::LazyLock;
use handlebars::Handlebars;
use thiserror::Error;
use crate::types::GenerateSkillResult;
#[derive(Debug, Error)]
pub enum TemplateError {
#[error("template rendering failed: {0}")]
RenderFailed(#[from] handlebars::RenderError),
#[error("template registration failed: {0}")]
RegistrationFailed(#[from] handlebars::TemplateError),
}
const SKILL_GENERATION_TEMPLATE: &str = include_str!("templates/skill-generation.hbs");
static HANDLEBARS: LazyLock<Handlebars<'static>> = LazyLock::new(|| {
let mut hb = Handlebars::new();
hb.register_template_string("skill", SKILL_GENERATION_TEMPLATE)
.expect("embedded template must be valid Handlebars syntax");
hb
});
pub fn render_generation_prompt(context: &GenerateSkillResult) -> Result<String, TemplateError> {
let rendered = HANDLEBARS.render("skill", context)?;
Ok(rendered)
}
#[allow(dead_code)]
pub fn get_prebuilt_prompt(context: &GenerateSkillResult) -> &str {
&context.generation_prompt
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{SkillCategory, SkillTool, ToolExample};
fn create_test_context() -> GenerateSkillResult {
GenerateSkillResult {
server_id: "test".to_string(),
skill_name: "test-progressive".to_string(),
server_description: Some("Test server".to_string()),
categories: vec![SkillCategory {
name: "test".to_string(),
display_name: "Test".to_string(),
tools: vec![SkillTool {
name: "test_tool".to_string(),
typescript_name: "testTool".to_string(),
description: "Test tool description".to_string(),
keywords: vec!["test".to_string()],
required_params: vec!["param1".to_string()],
optional_params: vec![],
}],
}],
tool_count: 1,
example_tools: vec![ToolExample {
tool_name: "test_tool".to_string(),
description: "Test tool".to_string(),
cli_command: "node test.ts".to_string(),
params_json: "{}".to_string(),
}],
generation_prompt: "Pre-built prompt".to_string(),
output_path: "~/.claude/skills/test/SKILL.md".to_string(),
}
}
#[test]
fn test_render_generation_prompt() {
let context = create_test_context();
let result = render_generation_prompt(&context);
match result {
Ok(prompt) => {
assert!(prompt.contains("test"));
assert!(prompt.contains("SKILL.md"));
}
Err(e) => panic!("Template rendering failed: {e}"),
}
}
#[test]
fn test_get_prebuilt_prompt() {
let context = create_test_context();
let prompt = get_prebuilt_prompt(&context);
assert_eq!(prompt, "Pre-built prompt");
}
}