git-iris 2.0.8

AI-powered Git workflow assistant for smart commits, code reviews, changelogs, and release notes
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct InstructionPreset {
    pub name: String,
    pub description: String,
    pub instructions: String,
    pub emoji: String,           // New field for emoji
    pub preset_type: PresetType, // New field to distinguish between commit and review presets
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Copy, Default)]
pub enum PresetType {
    Commit,
    Review,
    #[default]
    Both,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct InstructionPresetLibrary {
    presets: HashMap<String, InstructionPreset>,
}

impl Default for InstructionPresetLibrary {
    fn default() -> Self {
        Self::new()
    }
}

impl InstructionPresetLibrary {
    #[allow(clippy::too_many_lines)]
    #[must_use]
    pub fn new() -> Self {
        let mut presets = HashMap::new();

        presets.insert(
            "default".to_string(),
            InstructionPreset {
                name: "Default".to_string(),
                description: "Standard professional style".to_string(),
                instructions: "Provide clear, concise, and professional responses. Focus on accuracy and relevance.".to_string(),
                emoji: "📝".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "detailed".to_string(),
            InstructionPreset {
                name: "Detailed".to_string(),
                description: "Provide more context and explanation".to_string(),
                instructions: "Offer comprehensive explanations, including background information, potential impacts, and related considerations. Aim for thoroughness while maintaining clarity.".to_string(),
                emoji: "🔍".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "concise".to_string(),
            InstructionPreset {
                name: "Concise".to_string(),
                description: "Short and to-the-point responses".to_string(),
                instructions: "Keep responses brief and focused on the core information. Prioritize essential details and avoid unnecessary elaboration.".to_string(),
                emoji: "🎯".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "technical".to_string(),
            InstructionPreset {
                name: "Technical".to_string(),
                description: "Focus on technical details".to_string(),
                instructions: "Emphasize technical aspects in your responses. Include specific terminology, methodologies, or performance impacts where relevant. Assume a technically proficient audience.".to_string(),
                emoji: "⚙️".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "storyteller".to_string(),
            InstructionPreset {
                name: "Storyteller".to_string(),
                description: "Frame information as part of an ongoing narrative".to_string(),
                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(),
                emoji: "📚".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "emoji-lover".to_string(),
            InstructionPreset {
                name: "Emoji Enthusiast".to_string(),
                description: "Use emojis to enhance communication".to_string(),
                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(),
                emoji: "😍".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "formal".to_string(),
            InstructionPreset {
                name: "Formal".to_string(),
                description: "Maintain a highly professional and formal tone".to_string(),
                instructions: "Use formal language and structure in your responses. Avoid colloquialisms and maintain a respectful, business-like tone throughout.".to_string(),
                emoji: "🎩".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "explanatory".to_string(),
            InstructionPreset {
                name: "Explanatory".to_string(),
                description: "Focus on explaining concepts and changes".to_string(),
                instructions: "Prioritize explaining the 'why' behind information or changes. Provide context, rationale, and potential implications to foster understanding.".to_string(),
                emoji: "💡".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "user-focused".to_string(),
            InstructionPreset {
                name: "User-Focused".to_string(),
                description: "Emphasize user impact and benefits".to_string(),
                instructions: "Frame information in terms of its impact on users or stakeholders. Highlight benefits, improvements, and how changes affect the user experience.".to_string(),
                emoji: "👥".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "cosmic".to_string(),
            InstructionPreset {
                name: "Cosmic Oracle".to_string(),
                description: "Channel mystical and cosmic energy".to_string(),
                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(),
                emoji: "🔮".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "academic".to_string(),
            InstructionPreset {
                name: "Academic".to_string(),
                description: "Scholarly and research-oriented style".to_string(),
                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(),
                emoji: "🎓".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "comparative".to_string(),
            InstructionPreset {
                name: "Comparative".to_string(),
                description: "Highlight differences and similarities".to_string(),
                instructions: "Focus on comparing and contrasting elements. Identify key differences and similarities, and explain their significance or implications.".to_string(),
                emoji: "⚖️".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "future-oriented".to_string(),
            InstructionPreset {
                name: "Future-Oriented".to_string(),
                description: "Emphasize future implications and possibilities".to_string(),
                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(),
                emoji: "🔮".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "time-traveler".to_string(),
            InstructionPreset {
                name: "Time Traveler".to_string(),
                description: "Narrate from different points in time".to_string(),
                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(),
                emoji: "".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "chef-special".to_string(),
            InstructionPreset {
                name: "Chef's Special".to_string(),
                description: "Present information as a culinary experience".to_string(),
                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(),
                emoji: "👩‍🍳".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "superhero-saga".to_string(),
            InstructionPreset {
                name: "Superhero Saga".to_string(),
                description: "Frame information in a superhero universe".to_string(),
                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(),
                emoji: "🦸".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "nature-documentary".to_string(),
            InstructionPreset {
                name: "Nature Documentary".to_string(),
                description: "Narrate as if observing a natural phenomenon".to_string(),
                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(),
                emoji: "🌿".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "chill".to_string(),
            InstructionPreset {
                name: "Chill".to_string(),
                description: "Professional but fun commit messages".to_string(),
                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(),
                emoji: "😎".to_string(),
                preset_type: PresetType::Both,
            }
        );

        presets.insert(
            "hater".to_string(),
            InstructionPreset {
                name: "Hater".to_string(),
                description: "Hyper-critical and brutally honest style".to_string(),
                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(),
                emoji: "💢".to_string(),
                preset_type: PresetType::Both,
            },
        );

        presets.insert(
            "conventional".to_string(),
            InstructionPreset {
                name: "Conventional Commits".to_string(),
                description: "Follow the Conventional Commits specification".to_string(),
                instructions: "STRICT CONVENTIONAL COMMITS SPECIFICATION - FOLLOW EXACTLY:\n\n\
                               FORMAT: <type>[optional scope]: <description>\n\n\
                               MANDATORY RULES:\n\
                               1. NO EMOJIS - Conventional commits never use emojis\n\
                               2. NO CAPITALIZATION of type or scope\n\
                               3. Subject line MUST be 50 characters or less\n\
                               4. Description MUST be in imperative mood (add, fix, update - NOT added, fixed, updated)\n\
                               5. NO period at end of subject line\n\
                               6. USE SCOPES when files relate to specific components/modules\n\n\
                               SCOPE USAGE - STRONGLY PREFERRED:\n\
                               - For API changes: feat(api): add user endpoint\n\
                               - For UI changes: feat(ui): add login form\n\
                               - For auth: fix(auth): handle expired tokens\n\
                               - For database: feat(db): add user table migration\n\
                               - For tests: test(auth): add login validation tests\n\
                               - For config: chore(config): update database settings\n\
                               - For docs: docs(readme): update installation steps\n\
                               - For CLI: feat(cli): add new command option\n\
                               - For build: build(deps): update dependency versions\n\
                               - Analyze the changed files and pick the most relevant component\n\n\
                               VALID TYPES (use ONLY these):\n\
                               - feat: new feature for the user\n\
                               - fix: bug fix for the user\n\
                               - docs: changes to documentation\n\
                               - style: formatting, missing semicolons, etc (no code change)\n\
                               - refactor: code change that neither fixes bug nor adds feature\n\
                               - perf: code change that improves performance\n\
                               - test: adding missing tests or correcting existing tests\n\
                               - build: changes that affect build system or external dependencies\n\
                               - ci: changes to CI configuration files and scripts\n\
                               - chore: other changes that don't modify src or test files\n\
                               - revert: reverts a previous commit\n\n\
                               SCOPE SELECTION RULES:\n\
                               - Look at the file paths and identify the main component/module\n\
                               - Use the most specific relevant scope (prefer 'auth' over 'api' if it's auth-specific)\n\
                               - Common scopes: api, ui, auth, db, cli, config, deps, core, utils, tests\n\
                               - If multiple unrelated components, omit scope or use broader one\n\n\
                               BODY (optional):\n\
                               - Separate from subject with blank line\n\
                               - Wrap at 72 characters\n\
                               - Explain what and why, not how\n\
                               - Use imperative mood\n\n\
                               BREAKING CHANGES:\n\
                               - Add '!' after type/scope: feat(api)!: remove deprecated endpoints\n\
                               - OR include 'BREAKING CHANGE:' in footer\n\n\
                               EXAMPLES:\n\
                               ✓ feat(auth): add OAuth login\n\
                               ✓ fix(api): resolve timeout issue\n\
                               ✓ docs(readme): update contributing guidelines\n\
                               ✓ feat(ui)!: remove deprecated button component\n\
                               ✓ refactor(core): extract validation logic\n\
                               ✗ Add user authentication (missing type and scope)\n\
                               ✗ feat: Add user authentication (missing scope when relevant)\n\
                               ✗ feat: adds user authentication (wrong mood)\n\
                               ✗ 🎉 feat(auth): add authentication (has emoji)".to_string(),
                emoji: "📏".to_string(),
                preset_type: PresetType::Both,
            },
        );

        // Add review-specific presets
        presets.insert(
            "security".to_string(),
            InstructionPreset {
                name: "Security".to_string(),
                description: "Focus on security vulnerabilities and best practices".to_string(),
                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(),
                emoji: "🔒".to_string(),
                preset_type: PresetType::Review,
            },
        );

        presets.insert(
            "performance".to_string(),
            InstructionPreset {
                name: "Performance".to_string(),
                description: "Analyze code for performance optimizations".to_string(),
                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(),
                emoji: "".to_string(),
                preset_type: PresetType::Review,
            },
        );

        presets.insert(
            "architecture".to_string(),
            InstructionPreset {
                name: "Architecture".to_string(),
                description: "Evaluate architectural patterns and design decisions".to_string(),
                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(),
                emoji: "🏗️".to_string(),
                preset_type: PresetType::Review,
            },
        );

        presets.insert(
            "testing".to_string(),
            InstructionPreset {
                name: "Testing".to_string(),
                description: "Focus on test coverage and testing strategies".to_string(),
                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(),
                emoji: "🧪".to_string(),
                preset_type: PresetType::Review,
            },
        );

        presets.insert(
            "maintainability".to_string(),
            InstructionPreset {
                name: "Maintainability".to_string(),
                description: "Evaluate code for long-term maintenance".to_string(),
                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(),
                emoji: "🔧".to_string(),
                preset_type: PresetType::Review,
            },
        );

        presets.insert(
            "conventions".to_string(),
            InstructionPreset {
                name: "Code Conventions".to_string(),
                description: "Check adherence to language and project coding standards".to_string(),
                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(),
                emoji: "📏".to_string(),
                preset_type: PresetType::Review,
            },
        );

        Self { presets }
    }

    #[must_use]
    pub fn get_preset(&self, key: &str) -> Option<&InstructionPreset> {
        self.presets.get(key)
    }

    #[must_use]
    pub fn list_presets(&self) -> Vec<(&String, &InstructionPreset)> {
        self.presets.iter().collect()
    }

    #[must_use]
    pub fn list_presets_by_type(
        &self,
        preset_type: Option<PresetType>,
    ) -> Vec<(&String, &InstructionPreset)> {
        match preset_type {
            Some(typ) => self
                .presets
                .iter()
                .filter(|(_, preset)| preset.preset_type == typ)
                .collect(),
            None => self.list_presets(),
        }
    }

    #[must_use]
    pub fn list_valid_presets_for_command(
        &self,
        command_type: PresetType,
    ) -> Vec<(&String, &InstructionPreset)> {
        self.presets
            .iter()
            .filter(|(_, preset)| {
                preset.preset_type == command_type || preset.preset_type == PresetType::Both
            })
            .collect()
    }
}

#[must_use]
pub fn get_instruction_preset_library() -> InstructionPresetLibrary {
    InstructionPresetLibrary::new()
}

#[must_use]
pub fn list_presets_formatted(library: &InstructionPresetLibrary) -> String {
    list_presets_formatted_by_type(library, None)
}

#[must_use]
pub fn list_presets_formatted_by_type(
    library: &InstructionPresetLibrary,
    preset_type: Option<PresetType>,
) -> String {
    let mut presets: Vec<_> = library.list_presets_by_type(preset_type);
    presets.sort_by(|a, b| {
        if a.1.name == "Default" {
            std::cmp::Ordering::Less
        } else if b.1.name == "Default" {
            std::cmp::Ordering::Greater
        } else {
            a.1.name.cmp(&b.1.name)
        }
    });

    presets
        .iter()
        .map(|(key, preset)| {
            let type_indicator = match preset.preset_type {
                PresetType::Commit => "[C]",
                PresetType::Review => "[R]",
                PresetType::Both => "[B]",
            };
            format!(
                "{} {} - {} - {} - {}",
                type_indicator, key, preset.emoji, preset.name, preset.description
            )
        })
        .collect::<Vec<String>>()
        .join("\n")
}

#[must_use]
pub fn list_valid_presets_for_command_formatted(
    library: &InstructionPresetLibrary,
    command_type: PresetType,
) -> String {
    let mut presets: Vec<_> = library.list_valid_presets_for_command(command_type);
    presets.sort_by(|a, b| {
        if a.1.name == "Default" {
            std::cmp::Ordering::Less
        } else if b.1.name == "Default" {
            std::cmp::Ordering::Greater
        } else {
            a.1.name.cmp(&b.1.name)
        }
    });

    presets
        .iter()
        .map(|(key, preset)| {
            let type_indicator = match preset.preset_type {
                PresetType::Commit => "[C]",
                PresetType::Review => "[R]",
                PresetType::Both => "[B]",
            };
            format!(
                "{} {} - {} - {} - {}",
                type_indicator, key, preset.emoji, preset.name, preset.description
            )
        })
        .collect::<Vec<String>>()
        .join("\n")
}