Skip to main content
Glama
by 8b-is
context.rs6.91 kB
//! Context Mode - Provides intelligent context for AI conversations //! Integrates with MEM|8 memories, git status, and recent changes //! //! "Context is consciousness" - Omni use super::Formatter; use crate::mem8::ConversationMemory; use crate::scanner::{FileNode, TreeStats}; use anyhow::Result; use std::io::Write; use std::path::Path; use std::time::{SystemTime, UNIX_EPOCH}; pub struct ContextFormatter { show_git: bool, show_memories: bool, } impl Default for ContextFormatter { fn default() -> Self { Self { show_git: true, show_memories: true, } } } impl ContextFormatter { pub fn new() -> Self { Self::default() } /// Get git context for the path fn get_git_context(&self, path: &Path) -> Option<String> { if !self.show_git { return None; } // Try to get git info using gix if let Ok(repo) = gix::discover(path) { let mut git_info = Vec::new(); // Get branch if let Ok(head) = repo.head_ref() { if let Some(reference) = head { let branch = reference.name().as_bstr().to_string(); git_info.push(format!( "Branch: {}", branch.strip_prefix("refs/heads/").unwrap_or(&branch) )); } } // Get last commit if let Ok(commit) = repo.head_commit() { let id = commit.id().to_string(); let msg = commit .message_raw_sloppy() .to_string() .lines() .next() .unwrap_or("No message") .to_string(); git_info.push(format!("Last: {} - {}", &id[..8], msg)); } if !git_info.is_empty() { return Some(git_info.join("\n")); } } None } /// Search for related memories in MEM|8 fn get_memory_context(&self, path: &Path) -> Option<String> { if !self.show_memories { return None; } // Get project name from path let project_name = path.file_name()?.to_str()?; // Initialize conversation memory let memory = ConversationMemory::new().ok()?; // List conversations and find related ones let conversations = memory.list_conversations().ok()?; let related: Vec<_> = conversations .iter() .filter(|c| c.file_name.contains(project_name)) .take(3) .collect(); if !related.is_empty() { let mut output = vec!["🧠 Related memories:".to_string()]; for conv in related { output.push(format!( " • {} ({} messages)", conv.file_name, conv.message_count )); } return Some(output.join("\n")); } None } } impl Formatter for ContextFormatter { fn format( &self, writer: &mut dyn Write, nodes: &[FileNode], stats: &TreeStats, root_path: &Path, ) -> Result<()> { writeln!(writer, "=== Smart Tree Context ===")?; writeln!(writer)?; // Project identification writeln!(writer, "📁 Project: {}", root_path.display())?; // Git context if let Some(git_info) = self.get_git_context(root_path) { writeln!(writer, "\n📍 Git Status:")?; writeln!(writer, "{}", git_info)?; } // Directory structure (compressed) writeln!(writer, "\n🌳 Structure:")?; writeln!(writer, "SUMMARY_AI_V1:")?; writeln!(writer, "PATH:{}", root_path.display())?; writeln!( writer, "STATS:F{:x}D{:x}S{:x}", stats.total_files, stats.total_dirs, stats.total_size )?; // Count files by extension let mut ext_counts = std::collections::HashMap::new(); for node in nodes { if !node.is_dir { if let Some(ext) = node.path.extension() { let ext_str = ext.to_string_lossy().to_string(); *ext_counts.entry(ext_str).or_insert(0) += 1; } } } let mut exts: Vec<_> = ext_counts.iter().collect(); exts.sort_by(|a, b| b.1.cmp(a.1)); let ext_str: Vec<_> = exts .iter() .take(10) .map(|(ext, count)| format!("{}:{}", ext, count)) .collect(); if !ext_str.is_empty() { writeln!(writer, "EXT:{}", ext_str.join(","))?; } // Find and show key files let key_files = find_key_files(nodes); if !key_files.is_empty() { writeln!(writer, "KEY:{}", key_files.join(","))?; } // Recent changes let recent = find_recent_files(nodes, 86400); // Last 24 hours if !recent.is_empty() { writeln!(writer, "\n⏰ Recent changes:")?; for file in recent.iter().take(5) { writeln!(writer, " • {}", file)?; } } // Memory context if let Some(memories) = self.get_memory_context(root_path) { writeln!(writer, "\n{}", memories)?; } writeln!(writer, "\n=== End Context ===")?; Ok(()) } } // Helper functions fn find_key_files(nodes: &[FileNode]) -> Vec<String> { let important = [ "Cargo.toml", "package.json", "README.md", "CLAUDE.md", "pyproject.toml", "go.mod", "Makefile", ".env", ]; let mut found = Vec::new(); for node in nodes { if let Some(file_name) = node.path.file_name() { let name = file_name.to_string_lossy(); if important.contains(&name.as_ref()) && !found.contains(&name.to_string()) { found.push(name.to_string()); if found.len() >= 10 { break; } } } } found } fn find_recent_files(nodes: &[FileNode], seconds: u64) -> Vec<String> { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_secs(); let mut recent = Vec::new(); for node in nodes { if !node.is_dir { if let Ok(duration) = node.modified.duration_since(UNIX_EPOCH) { let file_time = duration.as_secs(); let age = now.saturating_sub(file_time); if age < seconds { recent.push(node.path.display().to_string()); if recent.len() >= 10 { break; } } } } } recent }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server