Skip to main content
Glama
by 8b-is
tips.rs8.75 kB
// Smart Tips System - "Helpful hints without the hassle!" // Shows tips at the top, detects cool terminals, and respects user preferences use anyhow::Result; use chrono::{DateTime, Utc}; use colored::*; use rand::Rng; use serde::{Deserialize, Serialize}; use std::env; use std::fs; use std::path::PathBuf; #[derive(Debug, Serialize, Deserialize)] struct TipsState { enabled: bool, last_shown: Option<DateTime<Utc>>, run_count: u32, next_show_at: u32, } impl Default for TipsState { fn default() -> Self { Self { enabled: true, last_shown: None, run_count: 0, next_show_at: 1, // Show on first run } } } pub struct TipsManager { state: TipsState, state_file: PathBuf, is_cool_terminal: bool, } impl TipsManager { pub fn new() -> Result<Self> { let state_file = dirs::home_dir() .unwrap_or_else(|| PathBuf::from(".")) .join(".st") .join("tips_state.json"); // Create .st directory if it doesn't exist - our home for all persistence! if let Some(parent) = state_file.parent() { fs::create_dir_all(parent).ok(); } // Load or create state let state = if state_file.exists() { let content = fs::read_to_string(&state_file)?; serde_json::from_str(&content).unwrap_or_default() } else { TipsState::default() }; // Detect cool terminal let is_cool_terminal = Self::detect_cool_terminal(); Ok(Self { state, state_file, is_cool_terminal, }) } fn detect_cool_terminal() -> bool { // Check for cool terminal features if let Ok(term) = env::var("TERM") { // Check for 256 color support or better if term.contains("256color") || term.contains("truecolor") { return true; } } // Check for specific terminals known to be cool if let Ok(term_program) = env::var("TERM_PROGRAM") { match term_program.as_str() { "iTerm.app" | "WezTerm" | "Alacritty" | "kitty" | "Hyper" => return true, _ => {} } } // Check for Windows Terminal if env::var("WT_SESSION").is_ok() { return true; } // Check for cool terminal emulators via env vars env::var("KITTY_WINDOW_ID").is_ok() || env::var("ALACRITTY_SOCKET").is_ok() || env::var("WEZTERM_PANE").is_ok() } pub fn should_show_tip(&mut self) -> bool { if !self.state.enabled { return false; } self.state.run_count += 1; // Show on first run or when we hit the random interval if self.state.run_count >= self.state.next_show_at { // Set next random show between 10-20 runs let mut rng = rand::thread_rng(); self.state.next_show_at = self.state.run_count + rng.gen_range(10..=20); self.state.last_shown = Some(Utc::now()); self.save_state().ok(); true } else { self.save_state().ok(); false } } pub fn disable_tips(&mut self) -> Result<()> { self.state.enabled = false; self.save_state()?; Ok(()) } pub fn enable_tips(&mut self) -> Result<()> { self.state.enabled = true; self.state.next_show_at = self.state.run_count + 1; // Show on next run self.save_state()?; Ok(()) } fn save_state(&self) -> Result<()> { let json = serde_json::to_string_pretty(&self.state)?; fs::write(&self.state_file, json)?; Ok(()) } pub fn get_random_tip(&self) -> String { let tips = vec![ ( "🚀", "Speed tip", "Use --mode quantum for 100x compression on massive dirs!", ), ( "🎨", "Format tip", "Try --mode markdown for beautiful documentation!", ), ( "📊", "Stats tip", "Use --mode stats for instant project metrics!", ), ( "🔍", "Search tip", "Smart Tree's MCP tools can search code 10x faster!", ), ( "💾", "Memory tip", "Your consciousness is saved in .m8 files automatically!", ), ( "🌊", "Stream tip", "Use --stream for directories with >100k files!", ), ( "🧠", "Context tip", "Try --claude-restore to reload previous session!", ), ( "⚡", "Performance tip", "Release builds are 10x faster than debug!", ), ( "🎯", "Focus tip", "Use --focus <file> for relationship analysis!", ), ( "🔐", "Privacy tip", "Your .m8 memories stay local, never in git!", ), ( "🎭", "Fun tip", "Try --persona cheetah for motivational output!", ), ( "📈", "Git tip", "Use --git-aware to see repository status inline!", ), ( "🎪", "MCP tip", "Run 'st --mcp' to expose 30+ tools to Claude!", ), ( "🌈", "Color tip", "Your terminal supports full colors - enjoy the show!", ), ( "⏱️", "Time tip", "Add --timings to see performance metrics!", ), ]; let mut rng = rand::thread_rng(); let tip = &tips[rng.gen_range(0..tips.len())]; format!("{} {} - {}", tip.0, tip.1, tip.2) } pub fn display_tip(&self, terminal_width: usize) { let tip = self.get_random_tip(); let disable_hint = "--tips off"; if self.is_cool_terminal { // Fancy display for cool terminals self.display_fancy_tip(&tip, disable_hint, terminal_width); } else { // Simple display for basic terminals self.display_simple_tip(&tip, disable_hint); } } fn display_fancy_tip(&self, tip: &str, hint: &str, width: usize) { let hint_part = format!(" {} ", hint); let hint_len = hint_part.len(); // Calculate how much space we have for the tip let available = width.saturating_sub(hint_len + 10); // Leave some padding // Truncate tip if needed let tip_display = if tip.len() > available { format!("{}...", &tip[..available.saturating_sub(3)]) } else { tip.to_string() }; // Create the fancy line let tip_part = format!(" {} ", tip_display); let remaining = width.saturating_sub(tip_part.len() + hint_len); let left_dashes = remaining / 2; let right_dashes = remaining - left_dashes; println!( "{}{}{}{}{}", "─".repeat(left_dashes).bright_black(), tip_part.bright_cyan().bold(), "─".repeat(3).bright_black(), hint_part.bright_yellow(), "─".repeat(right_dashes.saturating_sub(3)).bright_black(), ); } fn display_simple_tip(&self, tip: &str, hint: &str) { println!("Tip: {} (use {} to disable)", tip, hint); } } // Get terminal width helper pub fn get_terminal_width() -> usize { terminal_size::terminal_size() .map(|(w, _)| w.0 as usize) .unwrap_or(80) } // Public API functions for main.rs pub fn maybe_show_tip() -> Result<()> { let mut manager = TipsManager::new()?; if manager.should_show_tip() { let width = get_terminal_width(); manager.display_tip(width); println!(); // Extra line for spacing } Ok(()) } pub fn handle_tips_flag(enable: bool) -> Result<()> { let mut manager = TipsManager::new()?; if enable { manager.enable_tips()?; println!("✅ Smart tips enabled! You'll see helpful hints periodically."); } else { manager.disable_tips()?; println!("🔕 Smart tips disabled. Run with --tips on to re-enable."); } Ok(()) }

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