vtcode_core/skills/
enhanced_harness.rs1use crate::tools::generation_helpers::GenerationHelper;
7use anyhow::Result;
8use serde_json::Value;
9use std::path::PathBuf;
10
11pub struct EnhancedSkillResult {
13 pub message: String,
14 pub generated_files: Vec<String>,
15 pub metadata: Value,
16}
17
18pub struct EnhancedSkillHarness {
20 workspace_root: PathBuf,
21 helper: GenerationHelper,
22}
23
24impl EnhancedSkillHarness {
25 pub fn new(workspace_root: PathBuf) -> Self {
26 Self {
27 workspace_root: workspace_root.clone(),
28 helper: GenerationHelper::new(workspace_root),
29 }
30 }
31
32 pub async fn execute_skill_with_verification(
34 &self,
35 skill_name: &str,
36 output_filename: Option<&str>,
37 skill_logic: impl FnOnce() -> Result<()>,
38 ) -> Result<EnhancedSkillResult> {
39 skill_logic()?;
41
42 let mut verification_messages = Vec::new();
44 let mut generated_files = Vec::new();
45
46 if let Some(filename) = output_filename {
47 let verification = self.helper.verify_and_report(filename).await?;
48 verification_messages.push(verification.clone());
49 generated_files.push(filename.to_string());
50 }
51
52 let message = if verification_messages.is_empty() {
54 format!("✓ Skill '{}' executed successfully", skill_name)
55 } else {
56 format!(
57 "✓ Skill '{}' executed successfully\n\n{}",
58 skill_name,
59 verification_messages.join("\n")
60 )
61 };
62
63 Ok(EnhancedSkillResult {
64 message,
65 generated_files,
66 metadata: serde_json::json!({
67 "skill_name": skill_name,
68 "workspace_root": self.workspace_root.display().to_string(),
69 }),
70 })
71 }
72
73 pub async fn create_file_generation_response(
75 &self,
76 file_type: &str,
77 filename: &str,
78 generation_details: Option<&str>,
79 ) -> Result<String> {
80 let verification = self.helper.verify_and_report(filename).await?;
81
82 let details_section = if let Some(details) = generation_details {
83 format!("\n\n{}", details)
84 } else {
85 String::new()
86 };
87
88 Ok(format!(
89 "✓ Generated {}: {}\n\n{}{}",
90 file_type, filename, verification, details_section
91 ))
92 }
93
94 pub async fn create_sample_response(
96 &self,
97 file_type: &str,
98 generator_code: impl FnOnce(&PathBuf) -> Result<()>,
99 ) -> Result<String> {
100 let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
102 let filename = format!("sample_{}_{}", file_type.to_lowercase(), timestamp);
103 let filepath = self.workspace_root.join(&filename);
104
105 generator_code(&filepath)?;
107
108 self.create_file_generation_response(
110 file_type,
111 &filename,
112 Some("This is a sample file. You can modify the content as needed."),
113 )
114 .await
115 }
116}
117
118pub async fn execute_file_generation_skill(
120 workspace_root: PathBuf,
121 skill_name: &str,
122 filename: &str,
123 success_message: Option<&str>,
124) -> Result<String> {
125 let harness = EnhancedSkillHarness::new(workspace_root);
126
127 let verification = harness.helper.verify_and_report(filename).await?;
128
129 let message = if let Some(custom_msg) = success_message {
130 format!("{}\n\n{}", custom_msg, verification)
131 } else {
132 format!("✓ Skill '{}' completed.\n\n{}", skill_name, verification)
133 };
134
135 Ok(message)
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use tempfile::TempDir;
142
143 #[tokio::test]
144 async fn test_enhanced_harness_creation() {
145 let temp_dir = TempDir::new().unwrap();
146 let harness = EnhancedSkillHarness::new(temp_dir.path().to_path_buf());
147
148 assert_eq!(harness.workspace_root, temp_dir.path().to_path_buf());
150 }
151
152 #[tokio::test]
153 async fn test_execute_skill_with_verification() {
154 let temp_dir = TempDir::new().unwrap();
155 let harness = EnhancedSkillHarness::new(temp_dir.path().to_path_buf());
156
157 let result = harness
159 .execute_skill_with_verification("test-skill", None, || Ok(()))
160 .await
161 .unwrap();
162
163 assert!(result.message.contains("test-skill"));
164 assert!(result.message.contains("executed successfully"));
165 assert!(result.generated_files.is_empty());
166 }
167
168 #[tokio::test]
169 async fn test_create_file_generation_response() {
170 let temp_dir = TempDir::new().unwrap();
171 let harness = EnhancedSkillHarness::new(temp_dir.path().to_path_buf());
172
173 let response = harness
174 .create_file_generation_response("PDF", "nonexistent.pdf", None)
175 .await
176 .unwrap();
177
178 assert!(response.contains("Generated PDF"));
179 assert!(response.contains("nonexistent.pdf"));
180 }
181
182 #[tokio::test]
183 async fn test_quick_execution_helper() {
184 let temp_dir = TempDir::new().unwrap();
185 let result = execute_file_generation_skill(
186 temp_dir.path().to_path_buf(),
187 "test-skill",
188 "test.pdf",
189 Some("Custom success message"),
190 )
191 .await
192 .unwrap();
193
194 assert!(result.contains("Custom success message"));
195 }
196}