git_iris/
instruction_presets.rs

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,           // New field for emoji
10    pub preset_type: PresetType, // New field to distinguish between commit and review presets
11}
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        // Add review-specific presets
268        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}