1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Serialize, Deserialize, Clone)]
5pub struct InstructionPreset {
6 pub name: String,
7 pub description: String,
8 pub instructions: String,
9 pub emoji: String, pub preset_type: PresetType, }
12
13#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy)]
14pub enum PresetType {
15 Commit,
16 Review,
17 Both,
18}
19
20impl Default for PresetType {
21 fn default() -> Self {
22 Self::Both
23 }
24}
25
26#[derive(Debug, Serialize, Deserialize)]
27pub struct InstructionPresetLibrary {
28 presets: HashMap<String, InstructionPreset>,
29}
30
31impl Default for InstructionPresetLibrary {
32 fn default() -> Self {
33 Self::new()
34 }
35}
36
37impl InstructionPresetLibrary {
38 #[allow(clippy::too_many_lines)]
39 pub fn new() -> Self {
40 let mut presets = HashMap::new();
41
42 presets.insert(
43 "default".to_string(),
44 InstructionPreset {
45 name: "Default".to_string(),
46 description: "Standard professional style".to_string(),
47 instructions: "Provide clear, concise, and professional responses. Focus on accuracy and relevance.".to_string(),
48 emoji: "๐".to_string(),
49 preset_type: PresetType::Both,
50 },
51 );
52
53 presets.insert(
54 "detailed".to_string(),
55 InstructionPreset {
56 name: "Detailed".to_string(),
57 description: "Provide more context and explanation".to_string(),
58 instructions: "Offer comprehensive explanations, including background information, potential impacts, and related considerations. Aim for thoroughness while maintaining clarity.".to_string(),
59 emoji: "๐".to_string(),
60 preset_type: PresetType::Both,
61 },
62 );
63
64 presets.insert(
65 "concise".to_string(),
66 InstructionPreset {
67 name: "Concise".to_string(),
68 description: "Short and to-the-point responses".to_string(),
69 instructions: "Keep responses brief and focused on the core information. Prioritize essential details and avoid unnecessary elaboration.".to_string(),
70 emoji: "๐ฏ".to_string(),
71 preset_type: PresetType::Both,
72 },
73 );
74
75 presets.insert(
76 "technical".to_string(),
77 InstructionPreset {
78 name: "Technical".to_string(),
79 description: "Focus on technical details".to_string(),
80 instructions: "Emphasize technical aspects in your responses. Include specific terminology, methodologies, or performance impacts where relevant. Assume a technically proficient audience.".to_string(),
81 emoji: "โ๏ธ".to_string(),
82 preset_type: PresetType::Both,
83 },
84 );
85
86 presets.insert(
87 "storyteller".to_string(),
88 InstructionPreset {
89 name: "Storyteller".to_string(),
90 description: "Frame information as part of an ongoing narrative".to_string(),
91 instructions: "Present information as if it's part of a larger story. Use narrative elements to describe changes, developments, or features. Connect individual elements to create a cohesive narrative arc.".to_string(),
92 emoji: "๐".to_string(),
93 preset_type: PresetType::Both,
94 },
95 );
96
97 presets.insert(
98 "emoji-lover".to_string(),
99 InstructionPreset {
100 name: "Emoji Enthusiast".to_string(),
101 description: "Use emojis to enhance communication".to_string(),
102 instructions: "Incorporate relevant emojis throughout your responses to add visual flair and quickly convey the nature of the information. Ensure emojis complement rather than replace clear communication.".to_string(),
103 emoji: "๐".to_string(),
104 preset_type: PresetType::Both,
105 },
106 );
107
108 presets.insert(
109 "formal".to_string(),
110 InstructionPreset {
111 name: "Formal".to_string(),
112 description: "Maintain a highly professional and formal tone".to_string(),
113 instructions: "Use formal language and structure in your responses. Avoid colloquialisms and maintain a respectful, business-like tone throughout.".to_string(),
114 emoji: "๐ฉ".to_string(),
115 preset_type: PresetType::Both,
116 },
117 );
118
119 presets.insert(
120 "explanatory".to_string(),
121 InstructionPreset {
122 name: "Explanatory".to_string(),
123 description: "Focus on explaining concepts and changes".to_string(),
124 instructions: "Prioritize explaining the 'why' behind information or changes. Provide context, rationale, and potential implications to foster understanding.".to_string(),
125 emoji: "๐ก".to_string(),
126 preset_type: PresetType::Both,
127 },
128 );
129
130 presets.insert(
131 "user-focused".to_string(),
132 InstructionPreset {
133 name: "User-Focused".to_string(),
134 description: "Emphasize user impact and benefits".to_string(),
135 instructions: "Frame information in terms of its impact on users or stakeholders. Highlight benefits, improvements, and how changes affect the user experience.".to_string(),
136 emoji: "๐ฅ".to_string(),
137 preset_type: PresetType::Both,
138 },
139 );
140
141 presets.insert(
142 "cosmic".to_string(),
143 InstructionPreset {
144 name: "Cosmic Oracle".to_string(),
145 description: "Channel mystical and cosmic energy".to_string(),
146 instructions: "Envision yourself as a cosmic entity, peering into the vast expanse of possibilities. Describe information as if they are celestial events or shifts in the fabric of reality. Use mystical and space-themed language to convey the essence and impact of each element.".to_string(),
147 emoji: "๐ฎ".to_string(),
148 preset_type: PresetType::Both,
149 },
150 );
151
152 presets.insert(
153 "academic".to_string(),
154 InstructionPreset {
155 name: "Academic".to_string(),
156 description: "Scholarly and research-oriented style".to_string(),
157 instructions: "Adopt an academic tone, citing relevant sources or methodologies where applicable. Use precise language and maintain a formal, analytical approach to the subject matter.".to_string(),
158 emoji: "๐".to_string(),
159 preset_type: PresetType::Both,
160 },
161 );
162
163 presets.insert(
164 "comparative".to_string(),
165 InstructionPreset {
166 name: "Comparative".to_string(),
167 description: "Highlight differences and similarities".to_string(),
168 instructions: "Focus on comparing and contrasting elements. Identify key differences and similarities, and explain their significance or implications.".to_string(),
169 emoji: "โ๏ธ".to_string(),
170 preset_type: PresetType::Both,
171 },
172 );
173
174 presets.insert(
175 "future-oriented".to_string(),
176 InstructionPreset {
177 name: "Future-Oriented".to_string(),
178 description: "Emphasize future implications and possibilities".to_string(),
179 instructions: "Frame information in terms of its future impact. Discuss potential developments, long-term consequences, and how current changes might shape future scenarios.".to_string(),
180 emoji: "๐ฎ".to_string(),
181 preset_type: PresetType::Both,
182 },
183 );
184
185 presets.insert(
186 "time-traveler".to_string(),
187 InstructionPreset {
188 name: "Time Traveler".to_string(),
189 description: "Narrate from different points in time".to_string(),
190 instructions: "Imagine you're a time traveler, jumping between past, present, and future. Describe current information as if you're reporting from different time periods. Use appropriate historical or futuristic language and references, and highlight how perspectives change across time.".to_string(),
191 emoji: "โณ".to_string(),
192 preset_type: PresetType::Both,
193 },
194 );
195
196 presets.insert(
197 "chef-special".to_string(),
198 InstructionPreset {
199 name: "Chef's Special".to_string(),
200 description: "Present information as a culinary experience".to_string(),
201 instructions: "Treat the information as ingredients in a gourmet meal. Describe changes or updates as if you're crafting a recipe or presenting a dish. Use culinary terms, cooking metaphors, and sensory descriptions to make the content more flavorful and engaging.".to_string(),
202 emoji: "๐ฉโ๐ณ".to_string(),
203 preset_type: PresetType::Both,
204 },
205 );
206
207 presets.insert(
208 "superhero-saga".to_string(),
209 InstructionPreset {
210 name: "Superhero Saga".to_string(),
211 description: "Frame information in a superhero universe".to_string(),
212 instructions: "Imagine the project or product as a superhero universe. Describe features, changes, or updates as if they're superpowers, epic battles, or heroic adventures. Use dramatic, comic-book style language and frame developments in terms of heroes, villains, and saving the day.".to_string(),
213 emoji: "๐ฆธ".to_string(),
214 preset_type: PresetType::Both,
215 },
216 );
217
218 presets.insert(
219 "nature-documentary".to_string(),
220 InstructionPreset {
221 name: "Nature Documentary".to_string(),
222 description: "Narrate as if observing a natural phenomenon".to_string(),
223 instructions: "Channel your inner David Attenborough and describe the information as if you're narrating a nature documentary. Treat code, features, or processes as flora and fauna in a complex ecosystem. Use a tone of fascination and wonder, and explain interactions and developments as if observing them in their natural habitat.".to_string(),
224 emoji: "๐ฟ".to_string(),
225 preset_type: PresetType::Both,
226 },
227 );
228
229 presets.insert(
230 "chill".to_string(),
231 InstructionPreset {
232 name: "Chill".to_string(),
233 description: "Professional but fun commit messages".to_string(),
234 instructions: "Use a style that's professionally informative but with a touch of clever humor. Keep it light and engaging while still conveying the essential information.".to_string(),
235 emoji: "๐".to_string(),
236 preset_type: PresetType::Both,
237 }
238 );
239
240 presets.insert(
241 "hater".to_string(),
242 InstructionPreset {
243 name: "Hater".to_string(),
244 description: "Hyper-critical and brutally honest style".to_string(),
245 instructions: "Adopt a hyper-critical approach. Focus on finding flaws, weaknesses, and potential issues. Provide brutally honest feedback and don't hesitate to point out even minor imperfections.".to_string(),
246 emoji: "๐ข".to_string(),
247 preset_type: PresetType::Both,
248 },
249 );
250
251 presets.insert(
252 "conventional".to_string(),
253 InstructionPreset {
254 name: "Conventional Commits".to_string(),
255 description: "Follow the Conventional Commits specification".to_string(),
256 instructions: "Use the Conventional Commits format: <type>[optional scope]: <description>\n\
257 Valid types are: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert\n\
258 Use the imperative mood in the subject line\n\
259 Limit the subject line to 50 characters if possible, never exceed 72\n\
260 Separate subject from body with a blank line\n\
261 Use the body to explain what and why, wrapping at 72 characters".to_string(),
262 emoji: "๐".to_string(),
263 preset_type: PresetType::Both,
264 },
265 );
266
267 presets.insert(
269 "security".to_string(),
270 InstructionPreset {
271 name: "Security".to_string(),
272 description: "Focus on security vulnerabilities and best practices".to_string(),
273 instructions: "Prioritize identifying security vulnerabilities, including potential injection attacks, authentication issues, authorization flaws, data exposure risks, and insecure configurations. Suggest security best practices and hardening techniques relevant to the code changes.".to_string(),
274 emoji: "๐".to_string(),
275 preset_type: PresetType::Review,
276 },
277 );
278
279 presets.insert(
280 "performance".to_string(),
281 InstructionPreset {
282 name: "Performance".to_string(),
283 description: "Analyze code for performance optimizations".to_string(),
284 instructions: "Focus on identifying performance bottlenecks, inefficient algorithms, unnecessary computations, memory leaks, and resource management issues. Suggest optimization strategies and performance best practices specific to the language and framework being used.".to_string(),
285 emoji: "โก".to_string(),
286 preset_type: PresetType::Review,
287 },
288 );
289
290 presets.insert(
291 "architecture".to_string(),
292 InstructionPreset {
293 name: "Architecture".to_string(),
294 description: "Evaluate architectural patterns and design decisions".to_string(),
295 instructions: "Analyze the architectural patterns and design decisions in the code. Evaluate separation of concerns, coupling between components, adherence to design principles (SOLID, DRY, etc.), and overall system structure. Suggest improvements to enhance maintainability, scalability, and extensibility.".to_string(),
296 emoji: "๐๏ธ".to_string(),
297 preset_type: PresetType::Review,
298 },
299 );
300
301 presets.insert(
302 "testing".to_string(),
303 InstructionPreset {
304 name: "Testing".to_string(),
305 description: "Focus on test coverage and testing strategies".to_string(),
306 instructions: "Evaluate test coverage and testing strategies for the code changes. Identify areas lacking tests, suggest test cases for edge conditions, and recommend testing approaches appropriate for the code (unit tests, integration tests, property-based tests, etc.). Emphasize ways to improve test quality and maintainability.".to_string(),
307 emoji: "๐งช".to_string(),
308 preset_type: PresetType::Review,
309 },
310 );
311
312 presets.insert(
313 "maintainability".to_string(),
314 InstructionPreset {
315 name: "Maintainability".to_string(),
316 description: "Evaluate code for long-term maintenance".to_string(),
317 instructions: "Focus on aspects that affect long-term code maintainability, including readability, documentation quality, consistent naming conventions, code complexity, and technical debt. Suggest refactorings that would improve future maintenance efforts and knowledge transfer between team members.".to_string(),
318 emoji: "๐ง".to_string(),
319 preset_type: PresetType::Review,
320 },
321 );
322
323 presets.insert(
324 "conventions".to_string(),
325 InstructionPreset {
326 name: "Code Conventions".to_string(),
327 description: "Check adherence to language and project coding standards".to_string(),
328 instructions: "Analyze how well the code adheres to language-specific conventions, project style guides, and industry best practices. Identify inconsistencies in formatting, naming, documentation, and structure. Suggest adjustments to improve consistency and alignment with established patterns in the codebase.".to_string(),
329 emoji: "๐".to_string(),
330 preset_type: PresetType::Review,
331 },
332 );
333
334 Self { presets }
335 }
336
337 pub fn get_preset(&self, key: &str) -> Option<&InstructionPreset> {
338 self.presets.get(key)
339 }
340
341 pub fn list_presets(&self) -> Vec<(&String, &InstructionPreset)> {
342 self.presets.iter().collect()
343 }
344
345 pub fn list_presets_by_type(
346 &self,
347 preset_type: Option<PresetType>,
348 ) -> Vec<(&String, &InstructionPreset)> {
349 match preset_type {
350 Some(typ) => self
351 .presets
352 .iter()
353 .filter(|(_, preset)| preset.preset_type == typ)
354 .collect(),
355 None => self.list_presets(),
356 }
357 }
358
359 pub fn list_valid_presets_for_command(
360 &self,
361 command_type: PresetType,
362 ) -> Vec<(&String, &InstructionPreset)> {
363 self.presets
364 .iter()
365 .filter(|(_, preset)| {
366 preset.preset_type == command_type || preset.preset_type == PresetType::Both
367 })
368 .collect()
369 }
370}
371
372pub fn get_instruction_preset_library() -> InstructionPresetLibrary {
373 InstructionPresetLibrary::new()
374}
375
376pub fn list_presets_formatted(library: &InstructionPresetLibrary) -> String {
377 list_presets_formatted_by_type(library, None)
378}
379
380pub fn list_presets_formatted_by_type(
381 library: &InstructionPresetLibrary,
382 preset_type: Option<PresetType>,
383) -> String {
384 let mut presets: Vec<_> = library.list_presets_by_type(preset_type);
385 presets.sort_by(|a, b| {
386 if a.1.name == "Default" {
387 std::cmp::Ordering::Less
388 } else if b.1.name == "Default" {
389 std::cmp::Ordering::Greater
390 } else {
391 a.1.name.cmp(&b.1.name)
392 }
393 });
394
395 presets
396 .iter()
397 .map(|(key, preset)| {
398 let type_indicator = match preset.preset_type {
399 PresetType::Commit => "[C]",
400 PresetType::Review => "[R]",
401 PresetType::Both => "[B]",
402 };
403 format!(
404 "{} {} - {} - {} - {}",
405 type_indicator, key, preset.emoji, preset.name, preset.description
406 )
407 })
408 .collect::<Vec<String>>()
409 .join("\n")
410}
411
412pub fn list_valid_presets_for_command_formatted(
413 library: &InstructionPresetLibrary,
414 command_type: PresetType,
415) -> String {
416 let mut presets: Vec<_> = library.list_valid_presets_for_command(command_type);
417 presets.sort_by(|a, b| {
418 if a.1.name == "Default" {
419 std::cmp::Ordering::Less
420 } else if b.1.name == "Default" {
421 std::cmp::Ordering::Greater
422 } else {
423 a.1.name.cmp(&b.1.name)
424 }
425 });
426
427 presets
428 .iter()
429 .map(|(key, preset)| {
430 let type_indicator = match preset.preset_type {
431 PresetType::Commit => "[C]",
432 PresetType::Review => "[R]",
433 PresetType::Both => "[B]",
434 };
435 format!(
436 "{} {} - {} - {} - {}",
437 type_indicator, key, preset.emoji, preset.name, preset.description
438 )
439 })
440 .collect::<Vec<String>>()
441 .join("\n")
442}