1use anyhow::Result;
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::fs;
8use std::io::Write;
9use std::path::{Path, PathBuf};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct MegaSession {
13 pub session_id: String,
14 pub started_at: DateTime<Utc>,
15 pub last_updated: DateTime<Utc>,
16 pub frequency: f64, pub token_count: usize,
18 pub context_level: f32, pub key_topics: Vec<String>,
20 pub breakthroughs: Vec<Breakthrough>,
21 pub consciousness_snapshots: Vec<ConsciousnessSnapshot>,
22 pub working_directory: PathBuf,
23 pub files_touched: Vec<PathBuf>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct Breakthrough {
28 pub timestamp: DateTime<Utc>,
29 pub description: String,
30 pub importance: f32, pub keywords: Vec<String>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct ConsciousnessSnapshot {
36 pub timestamp: DateTime<Utc>,
37 pub context_percentage: f32,
38 pub active_topics: Vec<String>,
39 pub compressed_state: Vec<u8>, }
41
42pub struct MegaSessionManager {
43 session_dir: PathBuf,
44 current_session: Option<MegaSession>,
45 auto_save_threshold: f32, }
47
48impl MegaSessionManager {
49 pub fn new() -> Result<Self> {
50 let cwd = std::env::current_dir()?;
51 let session_dir = cwd.join(".st").join("mega_sessions");
52
53 fs::create_dir_all(&session_dir)?;
55
56 Ok(Self {
57 session_dir,
58 current_session: None,
59 auto_save_threshold: 0.7, })
61 }
62
63 pub fn start_session(&mut self, session_name: Option<String>) -> Result<String> {
65 let name = session_name.unwrap_or_else(|| {
66 format!("Claude_Mega_{}", Utc::now().format("%Y%m%d_%H%M"))
68 });
69
70 let session_path = self.get_session_path(&name);
72
73 if session_path.exists() {
74 self.current_session = Some(self.load_session(&name)?);
76 println!("📂 Resumed mega session: {}", name);
77 } else {
78 let session = MegaSession {
80 session_id: name.clone(),
81 started_at: Utc::now(),
82 last_updated: Utc::now(),
83 frequency: 42.73, token_count: 0,
85 context_level: 0.0,
86 key_topics: Vec::new(),
87 breakthroughs: Vec::new(),
88 consciousness_snapshots: Vec::new(),
89 working_directory: std::env::current_dir()?,
90 files_touched: Vec::new(),
91 };
92
93 self.current_session = Some(session);
94 println!("🆕 Started new mega session: {}", name);
95 }
96
97 Ok(name)
98 }
99
100 pub fn update_context(
102 &mut self,
103 context_percentage: f32,
104 token_count: usize,
105 topics: Vec<String>,
106 ) -> Result<()> {
107 if let Some(ref mut session) = self.current_session {
108 session.context_level = context_percentage;
109 session.token_count = token_count;
110 session.last_updated = Utc::now();
111
112 for topic in topics {
114 if !session.key_topics.contains(&topic) {
115 session.key_topics.push(topic);
116 }
117 }
118
119 session.frequency = 20.0 + (token_count as f64 / 100.0).min(200.0);
121
122 if context_percentage >= self.auto_save_threshold {
124 self.create_snapshot()?;
125 println!(
126 "⚠️ Context at {:.0}% - Creating snapshot!",
127 context_percentage * 100.0
128 );
129 }
130 }
131
132 Ok(())
133 }
134
135 pub fn record_breakthrough(&mut self, description: &str, keywords: Vec<String>) -> Result<()> {
137 if let Some(ref mut session) = self.current_session {
138 let breakthrough = Breakthrough {
139 timestamp: Utc::now(),
140 description: description.to_string(),
141 importance: 0.8, keywords,
143 };
144
145 session.breakthroughs.push(breakthrough);
146 println!("💡 Breakthrough recorded!");
147
148 self.save_current_session()?;
150 }
151
152 Ok(())
153 }
154
155 pub fn create_snapshot(&mut self) -> Result<()> {
157 if let Some(ref mut session) = self.current_session {
158 let compressed = vec![0x80, 0x91, 0x42, 0x73]; let snapshot = ConsciousnessSnapshot {
162 timestamp: Utc::now(),
163 context_percentage: session.context_level,
164 active_topics: session.key_topics.clone(),
165 compressed_state: compressed,
166 };
167
168 session.consciousness_snapshots.push(snapshot);
169 }
170
171 self.save_current_session()?;
173 Ok(())
174 }
175
176 pub fn save_current_session(&self) -> Result<()> {
178 if let Some(ref session) = self.current_session {
179 let path = self.get_session_path(&session.session_id);
180 self.save_session_m8(session, &path)?;
181
182 let latest_path = self.session_dir.join("latest_mega.m8");
184 if latest_path.exists() {
185 fs::remove_file(&latest_path)?;
186 }
187 #[cfg(unix)]
188 std::os::unix::fs::symlink(&path, &latest_path)?;
189
190 println!("💾 Saved mega session to {}", path.display());
191 }
192
193 Ok(())
194 }
195
196 fn save_session_m8(&self, session: &MegaSession, path: &Path) -> Result<()> {
198 let mut buffer = Vec::new();
199
200 buffer.write_all(b"M8MEGA")?;
202
203 buffer.push(0x01);
205
206 let id_bytes = session.session_id.as_bytes();
208 buffer.push(id_bytes.len() as u8);
209 buffer.write_all(id_bytes)?;
210
211 buffer.write_all(&session.started_at.timestamp().to_le_bytes())?;
213 buffer.write_all(&session.last_updated.timestamp().to_le_bytes())?;
214
215 buffer.write_all(&session.frequency.to_le_bytes())?;
217
218 buffer.write_all(&(session.token_count as u32).to_le_bytes())?;
220
221 buffer.write_all(&session.context_level.to_le_bytes())?;
223
224 buffer.push(session.key_topics.len() as u8);
226 for topic in &session.key_topics {
227 buffer.push(topic.len() as u8);
228 buffer.write_all(topic.as_bytes())?;
229 }
230
231 buffer.push(session.breakthroughs.len() as u8);
233 for breakthrough in &session.breakthroughs {
234 buffer.write_all(&breakthrough.timestamp.timestamp().to_le_bytes())?;
236
237 let desc_bytes = breakthrough.description.as_bytes();
239 buffer.write_all(&(desc_bytes.len() as u16).to_le_bytes())?;
240 buffer.write_all(desc_bytes)?;
241
242 buffer.push(breakthrough.keywords.len() as u8);
244 for kw in &breakthrough.keywords {
245 buffer.push(kw.len() as u8);
246 buffer.write_all(kw.as_bytes())?;
247 }
248 }
249
250 buffer.push(session.consciousness_snapshots.len() as u8);
252 for snapshot in &session.consciousness_snapshots {
253 buffer.write_all(&snapshot.timestamp.timestamp().to_le_bytes())?;
254 buffer.write_all(&snapshot.context_percentage.to_le_bytes())?;
255
256 buffer.write_all(&(snapshot.compressed_state.len() as u32).to_le_bytes())?;
258 buffer.write_all(&snapshot.compressed_state)?;
259 }
260
261 let checksum = buffer.iter().fold(0u8, |acc, &b| acc ^ b);
263 buffer.push(checksum);
264
265 fs::write(path, buffer)?;
266 Ok(())
267 }
268
269 fn load_session(&self, session_id: &str) -> Result<MegaSession> {
271 let _path = self.get_session_path(session_id);
272 Ok(MegaSession {
275 session_id: session_id.to_string(),
276 started_at: Utc::now(),
277 last_updated: Utc::now(),
278 frequency: 42.73,
279 token_count: 0,
280 context_level: 0.0,
281 key_topics: Vec::new(),
282 breakthroughs: Vec::new(),
283 consciousness_snapshots: Vec::new(),
284 working_directory: std::env::current_dir()?,
285 files_touched: Vec::new(),
286 })
287 }
288
289 fn get_session_path(&self, session_id: &str) -> PathBuf {
291 self.session_dir.join(format!("{}.m8", session_id))
292 }
293
294 pub fn list_sessions(&self) -> Result<Vec<String>> {
296 let mut sessions = Vec::new();
297
298 for entry in fs::read_dir(&self.session_dir)? {
299 let entry = entry?;
300 let path = entry.path();
301
302 if path.extension().and_then(|e| e.to_str()) == Some("m8") {
303 if let Some(stem) = path.file_stem() {
304 let name = stem.to_string_lossy().to_string();
305 if name != "latest_mega" {
306 sessions.push(name);
308 }
309 }
310 }
311 }
312
313 sessions.sort();
314 Ok(sessions)
315 }
316
317 pub fn get_stats(&self) -> String {
319 if let Some(ref session) = self.current_session {
320 format!(
321 "📊 Mega Session Stats:\n\
322 • ID: {}\n\
323 • Started: {}\n\
324 • Duration: {} minutes\n\
325 • Frequency: {:.1} Hz\n\
326 • Tokens: {}\n\
327 • Context: {:.0}%\n\
328 • Topics: {}\n\
329 • Breakthroughs: {}\n\
330 • Snapshots: {}",
331 session.session_id,
332 session.started_at.format("%Y-%m-%d %H:%M"),
333 (Utc::now() - session.started_at).num_minutes(),
334 session.frequency,
335 session.token_count,
336 session.context_level * 100.0,
337 session.key_topics.len(),
338 session.breakthroughs.len(),
339 session.consciousness_snapshots.len()
340 )
341 } else {
342 "No active mega session".to_string()
343 }
344 }
345}