git_iris/companion/
branch_memory.rs

1//! Branch memory for Iris Companion
2//!
3//! Remembers context per branch across sessions.
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::path::PathBuf;
8
9/// Focus state - where the user was last working
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct FileFocus {
12    /// Path to the focused file
13    pub path: PathBuf,
14    /// Line number in the file
15    pub line: usize,
16    /// When this focus was recorded
17    pub timestamp: DateTime<Utc>,
18}
19
20impl FileFocus {
21    /// Create a new file focus
22    pub fn new(path: PathBuf, line: usize) -> Self {
23        Self {
24            path,
25            line,
26            timestamp: Utc::now(),
27        }
28    }
29}
30
31/// Per-branch persistent memory
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct BranchMemory {
34    /// Branch name
35    pub branch_name: String,
36    /// When this branch was first visited
37    pub created_at: DateTime<Utc>,
38    /// When this branch was last visited
39    pub last_visited: DateTime<Utc>,
40    /// Last focused file and line
41    pub last_focus: Option<FileFocus>,
42    /// User notes for this branch
43    pub notes: Vec<String>,
44    /// Number of sessions on this branch
45    pub session_count: u32,
46    /// Number of commits made on this branch (across sessions)
47    pub total_commits: u32,
48}
49
50impl BranchMemory {
51    /// Create new branch memory
52    pub fn new(branch_name: String) -> Self {
53        let now = Utc::now();
54        Self {
55            branch_name,
56            created_at: now,
57            last_visited: now,
58            last_focus: None,
59            notes: Vec::new(),
60            session_count: 1,
61            total_commits: 0,
62        }
63    }
64
65    /// Record a new session visit
66    pub fn record_visit(&mut self) {
67        self.last_visited = Utc::now();
68        self.session_count += 1;
69    }
70
71    /// Update last focus
72    pub fn set_focus(&mut self, path: PathBuf, line: usize) {
73        self.last_focus = Some(FileFocus::new(path, line));
74    }
75
76    /// Clear focus
77    pub fn clear_focus(&mut self) {
78        self.last_focus = None;
79    }
80
81    /// Add a note
82    pub fn add_note(&mut self, note: String) {
83        self.notes.push(note);
84    }
85
86    /// Record a commit
87    pub fn record_commit(&mut self) {
88        self.total_commits += 1;
89    }
90
91    /// Time since last visit
92    pub fn time_since_last_visit(&self) -> chrono::Duration {
93        Utc::now() - self.last_visited
94    }
95
96    /// Check if this is a returning visit (visited before more than 5 minutes ago)
97    pub fn is_returning_visit(&self) -> bool {
98        self.session_count > 1 && self.time_since_last_visit() > chrono::Duration::minutes(5)
99    }
100
101    /// Generate a welcome message if returning
102    pub fn welcome_message(&self) -> Option<String> {
103        if !self.is_returning_visit() {
104            return None;
105        }
106
107        let duration = self.time_since_last_visit();
108        let time_str = if duration.num_days() > 0 {
109            format!("{} days ago", duration.num_days())
110        } else if duration.num_hours() > 0 {
111            format!("{} hours ago", duration.num_hours())
112        } else {
113            format!("{} minutes ago", duration.num_minutes())
114        };
115
116        Some(format!(
117            "Welcome back to {}! Last here {}",
118            self.branch_name, time_str
119        ))
120    }
121}