omni_dev/data/context.rs
1//! Context data structures for enhanced commit message analysis.
2
3use std::collections::HashMap;
4use std::path::PathBuf;
5
6use anyhow::Result;
7use serde::{Deserialize, Serialize};
8
9/// Complete context information for intelligent commit message improvement.
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct CommitContext {
12 /// Project-level context and conventions.
13 pub project: ProjectContext,
14 /// Branch analysis and work pattern detection.
15 pub branch: BranchContext,
16 /// Multi-commit analysis and work patterns.
17 pub range: CommitRangeContext,
18 /// File-specific context and architectural understanding.
19 pub files: Vec<FileContext>,
20 /// User-provided context information.
21 pub user_provided: Option<String>,
22}
23
24/// Project-level context discovered from configuration files.
25#[derive(Debug, Clone, Serialize, Deserialize, Default)]
26pub struct ProjectContext {
27 /// Project-specific commit guidelines from .omni-dev/commit-guidelines.md.
28 pub commit_guidelines: Option<String>,
29 /// Project-specific PR guidelines from .omni-dev/pr-guidelines.md.
30 pub pr_guidelines: Option<String>,
31 /// Valid scopes and their descriptions from .omni-dev/scopes.yaml.
32 pub valid_scopes: Vec<ScopeDefinition>,
33 /// Feature-specific context from .omni-dev/context/.
34 pub feature_contexts: HashMap<String, FeatureContext>,
35 /// Parsed conventions from CONTRIBUTING.md.
36 pub project_conventions: ProjectConventions,
37 /// Detected ecosystem (rust, node, python, etc.).
38 pub ecosystem: Ecosystem,
39}
40
41/// Definition of a valid scope in the project.
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ScopeDefinition {
44 /// Name of the scope.
45 pub name: String,
46 /// Human-readable description of the scope.
47 pub description: String,
48 /// Example commit messages using this scope.
49 pub examples: Vec<String>,
50 /// File patterns that match this scope.
51 pub file_patterns: Vec<String>,
52}
53
54/// Context for a specific feature or work area.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct FeatureContext {
57 /// Name of the feature context.
58 pub name: String,
59 /// Description of the feature or work area.
60 pub description: String,
61 /// Associated scope for this feature.
62 pub scope: String,
63 /// Specific conventions for this feature.
64 pub conventions: Vec<String>,
65}
66
67/// Project conventions parsed from documentation.
68#[derive(Debug, Clone, Serialize, Deserialize, Default)]
69pub struct ProjectConventions {
70 /// Expected commit message format.
71 pub commit_format: Option<String>,
72 /// Required trailers like Signed-off-by.
73 pub required_trailers: Vec<String>,
74 /// Preferred commit types for this project.
75 pub preferred_types: Vec<String>,
76 /// Scope usage requirements and definitions.
77 pub scope_requirements: ScopeRequirements,
78}
79
80/// Requirements and validation rules for commit scopes.
81#[derive(Debug, Clone, Serialize, Deserialize, Default)]
82pub struct ScopeRequirements {
83 /// Whether a scope is required in commit messages.
84 pub required: bool,
85 /// List of valid scope names.
86 pub valid_scopes: Vec<String>,
87 /// Mapping from file patterns to suggested scopes.
88 pub scope_mapping: HashMap<String, Vec<String>>, // file patterns -> scope
89}
90
91/// Detected project ecosystem.
92#[derive(Debug, Clone, Serialize, Deserialize, Default)]
93pub enum Ecosystem {
94 #[default]
95 /// Unknown or undetected ecosystem.
96 Unknown,
97 /// Rust ecosystem with Cargo.
98 Rust,
99 /// Node.js ecosystem with npm/yarn.
100 Node,
101 /// Python ecosystem with pip/poetry.
102 Python,
103 /// Go ecosystem with go modules.
104 Go,
105 /// Java ecosystem with Maven/Gradle.
106 Java,
107 /// Generic project without specific ecosystem.
108 Generic,
109}
110
111/// Branch analysis and work pattern detection.
112#[derive(Debug, Clone, Serialize, Deserialize, Default)]
113pub struct BranchContext {
114 /// Type of work being performed on this branch.
115 pub work_type: WorkType,
116 /// Extracted scope from branch name.
117 pub scope: Option<String>,
118 /// Associated ticket or issue ID.
119 pub ticket_id: Option<String>,
120 /// Human-readable description of the branch purpose.
121 pub description: String,
122 /// Whether this is a feature branch (vs main/master).
123 pub is_feature_branch: bool,
124 /// Base branch this was created from.
125 pub base_branch: Option<String>,
126}
127
128/// Type of work being performed.
129#[derive(Debug, Clone, Serialize, Deserialize, Default)]
130pub enum WorkType {
131 #[default]
132 /// Unknown or unspecified work type.
133 Unknown,
134 /// New feature development.
135 Feature,
136 /// Bug fix.
137 Fix,
138 /// Documentation changes.
139 Docs,
140 /// Code refactoring.
141 Refactor,
142 /// Maintenance tasks.
143 Chore,
144 /// Test-related changes.
145 Test,
146 /// CI/CD pipeline changes.
147 Ci,
148 /// Build system changes.
149 Build,
150 /// Performance improvements.
151 Perf,
152}
153
154impl std::str::FromStr for WorkType {
155 type Err = anyhow::Error;
156
157 fn from_str(s: &str) -> Result<Self> {
158 match s.to_lowercase().as_str() {
159 "feature" | "feat" => Ok(WorkType::Feature),
160 "fix" | "bugfix" => Ok(WorkType::Fix),
161 "docs" | "doc" => Ok(WorkType::Docs),
162 "refactor" | "refact" => Ok(WorkType::Refactor),
163 "chore" => Ok(WorkType::Chore),
164 "test" | "tests" => Ok(WorkType::Test),
165 "ci" => Ok(WorkType::Ci),
166 "build" => Ok(WorkType::Build),
167 "perf" | "performance" => Ok(WorkType::Perf),
168 _ => Ok(WorkType::Unknown),
169 }
170 }
171}
172
173impl std::fmt::Display for WorkType {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 match self {
176 WorkType::Unknown => write!(f, "unknown work"),
177 WorkType::Feature => write!(f, "feature development"),
178 WorkType::Fix => write!(f, "bug fix"),
179 WorkType::Docs => write!(f, "documentation update"),
180 WorkType::Refactor => write!(f, "refactoring"),
181 WorkType::Chore => write!(f, "maintenance"),
182 WorkType::Test => write!(f, "testing"),
183 WorkType::Ci => write!(f, "CI/CD"),
184 WorkType::Build => write!(f, "build system"),
185 WorkType::Perf => write!(f, "performance improvement"),
186 }
187 }
188}
189
190/// Multi-commit analysis and work patterns.
191#[derive(Debug, Clone, Serialize, Deserialize, Default)]
192pub struct CommitRangeContext {
193 /// Related commit hashes in this analysis.
194 pub related_commits: Vec<String>, // commit hashes
195 /// Files that appear in multiple commits.
196 pub common_files: Vec<PathBuf>,
197 /// Detected work pattern across commits.
198 pub work_pattern: WorkPattern,
199 /// Analysis of scope consistency.
200 pub scope_consistency: ScopeAnalysis,
201 /// Overall architectural impact assessment.
202 pub architectural_impact: ArchitecturalImpact,
203 /// Significance of changes for commit message detail.
204 pub change_significance: ChangeSignificance,
205}
206
207/// Detected work pattern across commits.
208#[derive(Debug, Clone, Serialize, Deserialize, Default)]
209pub enum WorkPattern {
210 #[default]
211 /// Unknown or undetected pattern.
212 Unknown,
213 /// Building feature step by step.
214 Sequential,
215 /// Multiple small cleanup commits.
216 Refactoring,
217 /// Investigation and fixes.
218 BugHunt,
219 /// Documentation updates.
220 Documentation,
221 /// Config and setup changes.
222 Configuration,
223}
224
225/// Analysis of scope consistency across commits.
226#[derive(Debug, Clone, Serialize, Deserialize, Default)]
227pub struct ScopeAnalysis {
228 /// Most consistent scope across commits if any.
229 pub consistent_scope: Option<String>,
230 /// All scope changes detected.
231 pub scope_changes: Vec<String>,
232 /// Confidence level in scope consistency (0.0-1.0).
233 pub confidence: f32,
234}
235
236/// Impact on system architecture.
237#[derive(Debug, Clone, Serialize, Deserialize, Default)]
238pub enum ArchitecturalImpact {
239 #[default]
240 /// Small changes, no architecture impact.
241 Minimal,
242 /// Some architectural changes.
243 Moderate,
244 /// Major architectural changes.
245 Significant,
246 /// Breaking changes.
247 Breaking,
248}
249
250/// Significance of changes for commit message detail level.
251#[derive(Debug, Clone, Serialize, Deserialize, Default)]
252pub enum ChangeSignificance {
253 #[default]
254 /// Simple fix or small addition.
255 Minor,
256 /// Notable feature or improvement.
257 Moderate,
258 /// Significant enhancement or new capability.
259 Major,
260 /// Major system changes or breaking changes.
261 Critical,
262}
263
264/// File-based context and architectural understanding.
265#[derive(Debug, Clone, Serialize, Deserialize)]
266pub struct FileContext {
267 /// Path to the file.
268 pub path: PathBuf,
269 /// Purpose of this file in the project.
270 pub file_purpose: FilePurpose,
271 /// Architectural layer this file belongs to.
272 pub architectural_layer: ArchitecturalLayer,
273 /// Impact of changes to this file.
274 pub change_impact: ChangeImpact,
275 /// Significance of this file in the project.
276 pub project_significance: ProjectSignificance,
277}
278
279/// Purpose of the file in the project.
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub enum FilePurpose {
282 /// Configuration files.
283 Config,
284 /// Test files.
285 Test,
286 /// Docs and README files.
287 Documentation,
288 /// Main application logic.
289 CoreLogic,
290 /// API definitions, public interfaces.
291 Interface,
292 /// Build and deployment files.
293 Build,
294 /// Development tools and scripts.
295 Tooling,
296}
297
298/// Architectural layer of the file.
299#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
300pub enum ArchitecturalLayer {
301 /// UI, CLI, web interfaces.
302 Presentation,
303 /// Core business logic.
304 Business,
305 /// Data access, models, storage.
306 Data,
307 /// System, network, deployment.
308 Infrastructure,
309 /// Cross-cutting concerns (logging, auth, etc.).
310 Cross,
311}
312
313/// Impact of changes to this file.
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub enum ChangeImpact {
316 /// Formatting, comments, style changes.
317 Style,
318 /// New functionality, non-breaking.
319 Additive,
320 /// Changing existing functionality.
321 Modification,
322 /// Breaking existing functionality.
323 Breaking,
324 /// Security, safety, or critical fixes.
325 Critical,
326}
327
328/// Significance of file in project.
329#[derive(Debug, Clone, Serialize, Deserialize)]
330pub enum ProjectSignificance {
331 /// Common, everyday files.
332 Routine,
333 /// Key files but not critical.
334 Important,
335 /// Core files that define the project.
336 Critical,
337}
338
339impl CommitContext {
340 /// Creates a new empty context.
341 pub fn new() -> Self {
342 Self::default()
343 }
344
345 /// Checks if this context suggests a significant change needing detailed commit message.
346 #[must_use]
347 pub fn is_significant_change(&self) -> bool {
348 matches!(
349 self.range.change_significance,
350 ChangeSignificance::Major | ChangeSignificance::Critical
351 ) || matches!(
352 self.range.architectural_impact,
353 ArchitecturalImpact::Significant | ArchitecturalImpact::Breaking
354 ) || self.files.iter().any(|f| {
355 matches!(f.project_significance, ProjectSignificance::Critical)
356 || matches!(
357 f.change_impact,
358 ChangeImpact::Breaking | ChangeImpact::Critical
359 )
360 })
361 }
362
363 /// Returns the suggested commit message verbosity level.
364 pub fn suggested_verbosity(&self) -> VerbosityLevel {
365 if self.is_significant_change() {
366 VerbosityLevel::Comprehensive
367 } else if matches!(self.range.change_significance, ChangeSignificance::Moderate)
368 || self.files.len() > 1
369 || self.files.iter().any(|f| {
370 matches!(
371 f.architectural_layer,
372 ArchitecturalLayer::Presentation | ArchitecturalLayer::Business
373 )
374 })
375 {
376 // Be more generous with Detailed level for twiddle system:
377 // - Moderate changes
378 // - Multiple files
379 // - UI/CLI or business logic changes
380 VerbosityLevel::Detailed
381 } else {
382 VerbosityLevel::Concise
383 }
384 }
385}
386
387/// Suggested level of detail for commit messages.
388#[derive(Debug, Clone, Copy)]
389pub enum VerbosityLevel {
390 /// Single line, basic conventional commit.
391 Concise,
392 /// Subject + brief body paragraph.
393 Detailed,
394 /// Subject + detailed multi-paragraph body + lists.
395 Comprehensive,
396}