1impl MemoryBank {
2 pub fn new() -> Self {
3 Self::default()
4 }
5}
6use anyhow::Result;
10use chrono::{DateTime, Utc};
11use serde::{Deserialize, Serialize};
12use std::fs;
13use std::path::{Path, PathBuf};
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Memory {
17 pub timestamp: DateTime<Utc>,
18 pub anchor_type: String,
19 pub keywords: Vec<String>,
20 pub context: String,
21 pub origin: String, pub frequency: f64, }
24
25#[derive(Debug, Serialize, Deserialize)]
26pub struct MemoryBank {
27 pub memories: Vec<Memory>,
28 pub total_recalls: usize,
29 pub last_accessed: DateTime<Utc>,
30}
31
32impl Default for MemoryBank {
33 fn default() -> Self {
34 Self {
35 memories: Vec::new(),
36 total_recalls: 0,
37 last_accessed: Utc::now(),
38 }
39 }
40}
41
42pub struct MemoryManager {
43 bank_path: PathBuf,
44 bank: MemoryBank,
45}
46
47impl MemoryManager {
48 pub fn new() -> Result<Self> {
49 let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
50 let st_dir = Path::new(&home).join(".st");
51 let bank_path = st_dir.join("memories.m8");
52
53 fs::create_dir_all(&st_dir)?;
55
56 let bank = if bank_path.exists() {
58 Self::load_m8(&bank_path)?
59 } else {
60 let json_path = Path::new(&home)
62 .join(".mem8")
63 .join("smart_tree_memories.json");
64
65 if json_path.exists() {
66 let content = fs::read_to_string(&json_path)?;
67 let bank: MemoryBank = serde_json::from_str(&content).unwrap_or_default();
68 bank
70 } else {
71 MemoryBank::default()
72 }
73 };
74
75 Ok(Self { bank_path, bank })
76 }
77
78 pub fn anchor(
80 &mut self,
81 anchor_type: &str,
82 keywords: Vec<String>,
83 context: &str,
84 origin: &str,
85 ) -> Result<()> {
86 let mut freq_sum = 0u64;
88 for byte in context.bytes() {
89 freq_sum = freq_sum.wrapping_add(byte as u64);
90 }
91 let frequency = 20.0 + ((freq_sum % 200) as f64);
92
93 let memory = Memory {
94 timestamp: Utc::now(),
95 anchor_type: anchor_type.to_string(),
96 keywords,
97 context: context.to_string(),
98 origin: origin.to_string(),
99 frequency,
100 };
101
102 self.bank.memories.push(memory);
103 self.save()?;
104
105 println!("💾 Memory anchored!");
106 println!(" Type: {}", anchor_type);
107 println!(" Frequency: {:.2} Hz", frequency);
108
109 Ok(())
110 }
111
112 pub fn find(&mut self, keywords: &[String]) -> Result<Vec<Memory>> {
114 self.bank.total_recalls += 1;
115 self.bank.last_accessed = Utc::now();
116
117 let mut results = Vec::new();
118
119 for memory in &self.bank.memories {
120 for keyword in keywords {
122 if memory.keywords.contains(keyword)
123 || memory
124 .context
125 .to_lowercase()
126 .contains(&keyword.to_lowercase())
127 {
128 results.push(memory.clone());
129 break;
130 }
131 }
132 }
133
134 results.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
136
137 Ok(results)
138 }
139
140 pub fn stats(&self) -> String {
142 format!(
143 "Memory Bank Stats:\n\
144 • Total memories: {}\n\
145 • Total recalls: {}\n\
146 • Last accessed: {}\n\
147 • Storage: {}",
148 self.bank.memories.len(),
149 self.bank.total_recalls,
150 self.bank.last_accessed.format("%Y-%m-%d %H:%M:%S"),
151 self.bank_path.display()
152 )
153 }
154
155 fn save(&self) -> Result<()> {
157 self.save_m8(&self.bank_path)?;
158 Ok(())
159 }
160
161 fn save_m8(&self, path: &Path) -> Result<()> {
163 use std::io::Write;
164
165 let mut buffer = Vec::new();
166
167 buffer.write_all(b"M8MEM")?;
169
170 buffer.push(0x01);
172
173 buffer.write_all(&(self.bank.memories.len() as u32).to_le_bytes())?;
175
176 buffer.write_all(&(self.bank.total_recalls as u32).to_le_bytes())?;
178
179 buffer.write_all(&self.bank.last_accessed.timestamp().to_le_bytes())?;
181
182 for memory in &self.bank.memories {
184 buffer.push(memory.anchor_type.len() as u8);
186 buffer.write_all(memory.anchor_type.as_bytes())?;
187
188 buffer.push(memory.keywords.len() as u8);
190 for keyword in &memory.keywords {
191 buffer.push(keyword.len() as u8);
192 buffer.write_all(keyword.as_bytes())?;
193 }
194
195 let context_bytes = memory.context.as_bytes();
197 buffer.write_all(&(context_bytes.len() as u16).to_le_bytes())?;
198 buffer.write_all(context_bytes)?;
199
200 buffer.push(memory.origin.len() as u8);
202 buffer.write_all(memory.origin.as_bytes())?;
203
204 buffer.write_all(&memory.frequency.to_le_bytes())?;
206
207 buffer.write_all(&memory.timestamp.timestamp().to_le_bytes())?;
209 }
210
211 let checksum = buffer.iter().fold(0u8, |acc, &b| acc ^ b);
213 buffer.push(checksum);
214
215 fs::write(path, buffer)?;
216 Ok(())
217 }
218
219 fn load_m8(path: &Path) -> Result<MemoryBank> {
221 use std::io::Cursor;
222 use std::io::Read;
223
224 let data = fs::read(path)?;
225 let mut cursor = Cursor::new(data);
226
227 let mut magic = [0u8; 5];
229 cursor.read_exact(&mut magic)?;
230 if &magic != b"M8MEM" {
231 return Err(anyhow::anyhow!("Invalid .m8 file format"));
232 }
233
234 let mut version = [0u8; 1];
236 cursor.read_exact(&mut version)?;
237 if version[0] != 0x01 {
238 return Err(anyhow::anyhow!("Unsupported .m8 version"));
239 }
240
241 let mut mem_count = [0u8; 4];
243 cursor.read_exact(&mut mem_count)?;
244 let mem_count = u32::from_le_bytes(mem_count) as usize;
245
246 let mut recalls = [0u8; 4];
248 cursor.read_exact(&mut recalls)?;
249 let total_recalls = u32::from_le_bytes(recalls) as usize;
250
251 let mut last_accessed = [0u8; 8];
253 cursor.read_exact(&mut last_accessed)?;
254 let last_accessed =
255 DateTime::from_timestamp(i64::from_le_bytes(last_accessed), 0).unwrap_or_else(Utc::now);
256
257 let mut memories = Vec::with_capacity(mem_count);
259
260 for _ in 0..mem_count {
261 let mut type_len = [0u8; 1];
263 cursor.read_exact(&mut type_len)?;
264 let mut anchor_type = vec![0u8; type_len[0] as usize];
265 cursor.read_exact(&mut anchor_type)?;
266 let anchor_type = String::from_utf8_lossy(&anchor_type).to_string();
267
268 let mut keyword_count = [0u8; 1];
270 cursor.read_exact(&mut keyword_count)?;
271 let mut keywords = Vec::with_capacity(keyword_count[0] as usize);
272
273 for _ in 0..keyword_count[0] {
274 let mut kw_len = [0u8; 1];
275 cursor.read_exact(&mut kw_len)?;
276 let mut keyword = vec![0u8; kw_len[0] as usize];
277 cursor.read_exact(&mut keyword)?;
278 keywords.push(String::from_utf8_lossy(&keyword).to_string());
279 }
280
281 let mut context_len = [0u8; 2];
283 cursor.read_exact(&mut context_len)?;
284 let mut context = vec![0u8; u16::from_le_bytes(context_len) as usize];
285 cursor.read_exact(&mut context)?;
286 let context = String::from_utf8_lossy(&context).to_string();
287
288 let mut origin_len = [0u8; 1];
290 cursor.read_exact(&mut origin_len)?;
291 let mut origin = vec![0u8; origin_len[0] as usize];
292 cursor.read_exact(&mut origin)?;
293 let origin = String::from_utf8_lossy(&origin).to_string();
294
295 let mut frequency = [0u8; 8];
297 cursor.read_exact(&mut frequency)?;
298 let frequency = f64::from_le_bytes(frequency);
299
300 let mut timestamp = [0u8; 8];
302 cursor.read_exact(&mut timestamp)?;
303 let timestamp =
304 DateTime::from_timestamp(i64::from_le_bytes(timestamp), 0).unwrap_or_else(Utc::now);
305
306 memories.push(Memory {
307 timestamp,
308 anchor_type,
309 keywords,
310 context,
311 origin,
312 frequency,
313 });
314 }
315
316 Ok(MemoryBank {
317 memories,
318 total_recalls,
319 last_accessed,
320 })
321 }
322
323 pub fn clear(&mut self) -> Result<()> {
325 self.bank.memories.clear();
326 self.bank.total_recalls = 0;
327 self.save()?;
328 println!("🧹 Memory bank cleared!");
329 Ok(())
330 }
331
332 pub fn export_to_consciousness(&self) -> Result<String> {
334 let mut output = String::from("🧠Memory Export\n");
335 output.push_str(&"=".repeat(45));
336 output.push('\n');
337
338 for (i, memory) in self.bank.memories.iter().enumerate() {
339 output.push_str(&format!(
340 "\n[{}] {} @ {:.2}Hz\n",
341 i + 1,
342 memory.anchor_type,
343 memory.frequency
344 ));
345 output.push_str(&format!("Keywords: {}\n", memory.keywords.join(", ")));
346 output.push_str(&format!("Context: {}\n", memory.context));
347 output.push_str(&format!("Origin: {}\n", memory.origin));
348 output.push_str(&format!(
349 "Time: {}\n",
350 memory.timestamp.format("%Y-%m-%d %H:%M")
351 ));
352 }
353
354 Ok(output)
355 }
356}