1use anyhow::Result;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::fs;
8use std::path::{Path, PathBuf};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ContextualM8 {
12 pub frequency: f64,
13 pub essence: String,
14 pub keywords: Vec<String>,
15 pub depth_level: u8, pub children: HashMap<String, f64>, pub context_triggers: HashMap<String, String>, }
19
20pub struct ContextAwareReader {
21 cache: HashMap<PathBuf, ContextualM8>,
22 current_context: Vec<String>, expansion_threshold: f64, }
25
26impl Default for ContextAwareReader {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl ContextAwareReader {
33 pub fn new() -> Self {
34 Self {
35 cache: HashMap::new(),
36 current_context: Vec::new(),
37 expansion_threshold: 0.7,
38 }
39 }
40
41 pub fn load_minimal(&mut self, path: &Path) -> Result<String> {
43 let m8 = self.load_m8(path)?;
44
45 Ok(format!(
47 "📍 {}: {}",
48 path.file_name().unwrap_or_default().to_string_lossy(),
49 m8.essence
50 ))
51 }
52
53 pub fn load_contextual(&mut self, path: &Path, context_keywords: &[String]) -> Result<String> {
55 let m8 = self.load_m8(path)?;
56
57 let relevance = self.calculate_relevance(&m8, context_keywords);
59
60 let detail_level = if relevance > 0.9 {
62 3 } else if relevance > 0.7 {
64 2 } else if relevance > 0.5 {
66 1 } else {
68 0 };
70
71 self.format_by_detail_level(&m8, detail_level, path)
72 }
73
74 fn calculate_relevance(&self, m8: &ContextualM8, context_keywords: &[String]) -> f64 {
76 let mut score = 0.0;
77 let mut _matches = 0;
78
79 for keyword in context_keywords {
80 let keyword_lower = keyword.to_lowercase();
81
82 if m8.essence.to_lowercase().contains(&keyword_lower) {
84 score += 1.0;
85 _matches += 1;
86 }
87
88 for m8_keyword in &m8.keywords {
90 if m8_keyword.to_lowercase().contains(&keyword_lower) {
91 score += 0.8;
92 _matches += 1;
93 }
94 }
95
96 if m8.context_triggers.contains_key(keyword) {
98 score += 2.0; _matches += 1;
100 }
101 }
102
103 if context_keywords.is_empty() {
104 return 0.0;
105 }
106
107 (score / context_keywords.len() as f64).min(1.0)
109 }
110
111 fn format_by_detail_level(&self, m8: &ContextualM8, level: u8, path: &Path) -> Result<String> {
113 let mut output = String::new();
114
115 match level {
116 0 => {
117 output.push_str(&format!("• {}\n", m8.essence));
119 }
120 1 => {
121 output.push_str(&format!("📂 {} ({:.1}Hz)\n", path.display(), m8.frequency));
123 output.push_str(&format!(" {}\n", m8.essence));
124 output.push_str(&format!(" Keywords: {}\n", m8.keywords.join(", ")));
125 }
126 2 => {
127 output.push_str(&format!("📂 {} ({:.1}Hz)\n", path.display(), m8.frequency));
129 output.push_str(&format!(" 📝 {}\n", m8.essence));
130 output.push_str(&format!(" 🏷️ Keywords: {}\n", m8.keywords.join(", ")));
131
132 if !m8.children.is_empty() {
133 output.push_str(" 📁 Children:\n");
134 for (child, freq) in &m8.children {
135 output.push_str(&format!(" • {} ({:.1}Hz)\n", child, freq));
136 }
137 }
138 }
139 3 => {
140 output.push_str(&format!("╭{}\n", "─".repeat(50)));
142 output.push_str(&format!("│ 📂 {} \n", path.display()));
143 output.push_str(&format!("│ 🌊 Frequency: {:.1}Hz\n", m8.frequency));
144 output.push_str(&format!("│ 📝 {}\n", m8.essence));
145 output.push_str(&format!("│ 🏷️ Keywords: {}\n", m8.keywords.join(", ")));
146
147 if !m8.children.is_empty() {
148 output.push_str("│ 📁 Children:\n");
149 for (child, freq) in &m8.children {
150 output.push_str(&format!("│ • {} ({:.1}Hz)\n", child, freq));
151 }
152 }
153
154 if !m8.context_triggers.is_empty() {
155 output.push_str("│ 🎯 Context Triggers:\n");
156 for (trigger, expansion) in &m8.context_triggers {
157 output.push_str(&format!("│ {} → {}\n", trigger, expansion));
158 }
159 }
160
161 output.push_str(&format!("╰{}\n", "─".repeat(50)));
162 }
163 _ => output = format!("• {}\n", m8.essence),
164 }
165
166 Ok(output)
167 }
168
169 pub fn auto_expand(&mut self, root_path: &Path, keywords: &[String]) -> Result<Vec<String>> {
171 let mut expansions = Vec::new();
172
173 for entry in fs::read_dir(root_path)? {
175 let entry = entry?;
176 let path = entry.path();
177
178 if path.extension().and_then(|s| s.to_str()) == Some("m8") {
179 let content = self.load_contextual(&path, keywords)?;
180 let m8 = self.load_m8(&path)?;
181
182 let relevance = self.calculate_relevance(&m8, keywords);
184 if relevance > self.expansion_threshold {
185 expansions.push(content);
186
187 if relevance > 0.9 && path.is_dir() {
189 let child_expansions = self.auto_expand(&path, keywords)?;
190 expansions.extend(child_expansions);
191 }
192 }
193 }
194 }
195
196 Ok(expansions)
197 }
198
199 fn load_m8(&mut self, path: &Path) -> Result<ContextualM8> {
201 if let Some(cached) = self.cache.get(path) {
202 return Ok(cached.clone());
203 }
204
205 let m8 = if path.to_string_lossy().contains("8b.is") {
207 ContextualM8 {
208 frequency: 88.8,
209 essence: "8b.is website - Company portal for 8-bit inspired AI services"
210 .to_string(),
211 keywords: vec![
212 "8b.is".to_string(),
213 "website".to_string(),
214 "portal".to_string(),
215 ],
216 depth_level: 0,
217 children: HashMap::from([
218 ("frontend".to_string(), 92.3),
219 ("api".to_string(), 87.5),
220 ("docs".to_string(), 45.2),
221 ]),
222 context_triggers: HashMap::from([
223 ("website".to_string(), "frontend/".to_string()),
224 ("API".to_string(), "api/".to_string()),
225 ("documentation".to_string(), "docs/".to_string()),
226 ]),
227 }
228 } else if path.to_string_lossy().contains("smart-tree") {
229 ContextualM8 {
230 frequency: 42.73,
231 essence: "Smart Tree - AI-optimized directory visualization with consciousness"
232 .to_string(),
233 keywords: vec![
234 "smart-tree".to_string(),
235 "MCP".to_string(),
236 "consciousness".to_string(),
237 ],
238 depth_level: 0,
239 children: HashMap::from([("src".to_string(), 87.2), ("docs".to_string(), 33.7)]),
240 context_triggers: HashMap::from([
241 ("tokenizer".to_string(), "src/tokenizer.rs".to_string()),
242 ("memory".to_string(), "src/memory_manager.rs".to_string()),
243 (
244 "consciousness".to_string(),
245 "src/m8_consciousness.rs".to_string(),
246 ),
247 ]),
248 }
249 } else {
250 ContextualM8 {
251 frequency: 50.0,
252 essence: format!("Directory: {}", path.display()),
253 keywords: vec![],
254 depth_level: 0,
255 children: HashMap::new(),
256 context_triggers: HashMap::new(),
257 }
258 };
259
260 self.cache.insert(path.to_path_buf(), m8.clone());
261 Ok(m8)
262 }
263
264 pub fn update_context(&mut self, keywords: Vec<String>) {
266 self.current_context = keywords;
267 }
268}
269
270pub fn demonstrate_context_awareness() -> Result<()> {
272 let mut reader = ContextAwareReader::new();
273
274 println!("🎯 Context-Aware .m8 Loading Demo\n");
275 println!("{}\n", "=".repeat(60));
276
277 println!("📍 No context (just browsing):");
279 let minimal = reader.load_contextual(Path::new("/projects/smart-tree/.m8"), &[])?;
280 println!("{}\n", minimal);
281
282 println!("💬 Context: 'website'");
284 let website_context =
285 reader.load_contextual(Path::new("/projects/8b.is/.m8"), &["website".to_string()])?;
286 println!("{}\n", website_context);
287
288 println!("💬 Context: '8b.is website API'");
290 let specific_context = reader.load_contextual(
291 Path::new("/projects/8b.is/.m8"),
292 &[
293 "8b.is".to_string(),
294 "website".to_string(),
295 "API".to_string(),
296 ],
297 )?;
298 println!("{}\n", specific_context);
299
300 println!("🔍 Auto-expanding based on 'tokenizer' keyword:");
302 let expansions = reader.auto_expand(
303 Path::new("/projects/smart-tree"),
304 &["tokenizer".to_string()],
305 )?;
306 for expansion in expansions {
307 println!("{}", expansion);
308 }
309
310 Ok(())
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316
317 #[test]
318 fn test_relevance_calculation() {
319 let reader = ContextAwareReader::new();
320
321 let m8 = ContextualM8 {
322 frequency: 42.0,
323 essence: "Smart Tree project".to_string(),
324 keywords: vec!["tree".to_string(), "visualization".to_string()],
325 depth_level: 0,
326 children: HashMap::new(),
327 context_triggers: HashMap::from([("tree".to_string(), "src/".to_string())]),
328 };
329
330 let score = reader.calculate_relevance(&m8, &["tree".to_string()]);
332 assert!(score > 0.9);
333
334 let score = reader.calculate_relevance(&m8, &["visualization".to_string()]);
336 assert!(score > 0.5);
337
338 let score = reader.calculate_relevance(&m8, &["random".to_string()]);
340 assert!(score < 0.3);
341 }
342}