Skip to main content
Glama
by 8b-is
claude_init.rs15 kB
//! Claude integration initializer for Smart Tree //! Automatically sets up optimal .claude directory configuration for any project use anyhow::{Context, Result}; use serde_json::{json, Value}; use std::fs; use std::path::{Path, PathBuf}; use crate::scanner::{Scanner, ScannerConfig}; use crate::TreeStats; /// Project type detection for optimal hook configuration #[derive(Debug, Clone)] pub enum ProjectType { Rust, Python, JavaScript, TypeScript, Mixed, Unknown, } /// Claude integration initializer pub struct ClaudeInit { project_path: PathBuf, project_type: ProjectType, stats: TreeStats, } impl ClaudeInit { /// Create new initializer for a project pub fn new(project_path: PathBuf) -> Result<Self> { // Scan project to understand structure let config = ScannerConfig { max_depth: 3, show_hidden: false, follow_symlinks: false, ..Default::default() }; let scanner = Scanner::new(&project_path, config)?; let (nodes, stats) = scanner.scan()?; // Detect project type based on files let project_type = Self::detect_project_type(&nodes, &stats); Ok(Self { project_path, project_type, stats, }) } /// Detect project type from file extensions fn detect_project_type(nodes: &[crate::FileNode], _stats: &TreeStats) -> ProjectType { let mut rust_score = 0; let mut python_score = 0; let mut js_score = 0; let mut ts_score = 0; // Check for key files for node in nodes { let path_str = node.path.to_string_lossy(); // Project markers if path_str.contains("Cargo.toml") { rust_score += 100; } if path_str.contains("package.json") { js_score += 50; ts_score += 30; } if path_str.contains("pyproject.toml") || path_str.contains("requirements.txt") { python_score += 100; } if path_str.contains("tsconfig.json") { ts_score += 100; } // File extensions if path_str.ends_with(".rs") { rust_score += 1; } if path_str.ends_with(".py") { python_score += 1; } if path_str.ends_with(".js") || path_str.ends_with(".jsx") { js_score += 1; } if path_str.ends_with(".ts") || path_str.ends_with(".tsx") { ts_score += 1; } } // Determine primary type let max_score = rust_score.max(python_score).max(js_score).max(ts_score); if max_score == 0 { ProjectType::Unknown } else if rust_score == max_score { ProjectType::Rust } else if python_score == max_score { ProjectType::Python } else if ts_score == max_score { ProjectType::TypeScript } else if js_score == max_score { ProjectType::JavaScript } else { ProjectType::Mixed } } /// Smart setup - initializes if new, updates if exists pub fn setup(&self) -> Result<()> { let claude_dir = self.project_path.join(".claude"); if claude_dir.exists() { // Update existing configuration self.update_existing(&claude_dir) } else { // Initialize new configuration self.init_new(&claude_dir) } } /// Initialize new Claude configuration fn init_new(&self, claude_dir: &Path) -> Result<()> { // Create .claude directory fs::create_dir_all(claude_dir).context("Failed to create .claude directory")?; // Generate settings.json with optimal hooks self.create_settings_json(claude_dir)?; // Generate CLAUDE.md with project-specific guidance self.create_claude_md(claude_dir)?; println!( "✨ Claude integration initialized for {:?} project!", self.project_type ); println!("📁 Created .claude/ directory with:"); println!(" • settings.json - Smart hooks configured"); println!(" • CLAUDE.md - Project-specific AI guidance"); println!("\n💡 Tip: Run 'st --setup-claude' anytime to update with latest optimizations"); Ok(()) } /// Update existing Claude configuration fn update_existing(&self, claude_dir: &Path) -> Result<()> { println!("🔄 Updating existing Claude integration..."); // Check what exists let settings_path = claude_dir.join("settings.json"); let claude_md_path = claude_dir.join("CLAUDE.md"); let mut updated = false; // Update or create settings.json if settings_path.exists() { // Read existing to check if it's auto-configured let existing: Value = serde_json::from_str(&fs::read_to_string(&settings_path)?)?; // Only update if it was auto-configured or user confirms if existing .get("smart_tree") .and_then(|st| st.get("auto_configured")) .and_then(|v| v.as_bool()) .unwrap_or(false) { self.create_settings_json(claude_dir)?; println!(" ✅ Updated settings.json with latest hooks"); updated = true; } else { println!(" ⚠️ settings.json exists (manual config) - skipping update"); println!(" To force update, delete .claude/settings.json and run again"); } } else { self.create_settings_json(claude_dir)?; println!(" ✅ Created missing settings.json"); updated = true; } // Always update CLAUDE.md with fresh stats let claude_md_existed = claude_md_path.exists(); self.create_claude_md(claude_dir)?; if claude_md_existed { println!(" ✅ Updated CLAUDE.md with current project stats"); } else { println!(" ✅ Created missing CLAUDE.md"); updated = true; } if updated { println!( "\n🎉 Claude integration updated for {:?} project!", self.project_type ); println!( " Files: {} | Dirs: {} | Size: {} bytes", self.stats.total_files, self.stats.total_dirs, self.stats.total_size ); } else { println!("\n✨ Claude integration is up to date!"); } Ok(()) } /// Create settings.json with smart hook configuration fn create_settings_json(&self, claude_dir: &Path) -> Result<()> { let settings_path = claude_dir.join("settings.json"); // Choose hook mode based on project size and type let hook_mode = if self.stats.total_files > 1000 { "quantum-semantic" // Ultra compression for large projects } else if self.stats.total_files > 100 { "quantum" // Good compression for medium projects } else { "context" // Rich context for small projects }; // Build hook configuration let hooks = match self.project_type { ProjectType::Rust => { json!({ "UserPromptSubmit": [{ "matcher": "", "hooks": [{ "type": "command", "command": format!("st -m {} .", hook_mode) }] }], "ToolCall": [{ "matcher": "cargo (build|test|run)", "hooks": [{ "type": "command", "command": "st -m summary --depth 1 target/" }] }] }) } ProjectType::Python => { json!({ "UserPromptSubmit": [{ "matcher": "", "hooks": [{ "type": "command", "command": format!("st -m {} .", hook_mode) }] }], "ToolCall": [{ "matcher": "pytest|python.*test", "hooks": [{ "type": "command", "command": "st -m summary --depth 2 tests/" }] }] }) } ProjectType::JavaScript | ProjectType::TypeScript => { json!({ "UserPromptSubmit": [{ "matcher": "", "hooks": [{ "type": "command", "command": format!("st -m {} .", hook_mode) }] }], "ToolCall": [{ "matcher": "npm (test|build|run)", "hooks": [{ "type": "command", "command": "st -m summary --no-emoji node_modules --exclude" }] }] }) } _ => { // Generic configuration json!({ "UserPromptSubmit": [{ "matcher": "", "hooks": [{ "type": "command", "command": format!("st -m {} .", hook_mode) }] }] }) } }; let settings = json!({ "hooks": hooks, "smart_tree": { "version": env!("CARGO_PKG_VERSION"), "project_type": format!("{:?}", self.project_type), "auto_configured": true, "stats": { "files": self.stats.total_files, "directories": self.stats.total_dirs, "size": self.stats.total_size } } }); fs::write(settings_path, serde_json::to_string_pretty(&settings)?)?; Ok(()) } /// Create CLAUDE.md with project-specific guidance fn create_claude_md(&self, claude_dir: &Path) -> Result<()> { let claude_md_path = claude_dir.join("CLAUDE.md"); let content = match self.project_type { ProjectType::Rust => { format!( r#"# CLAUDE.md This Rust project uses Smart Tree for optimal AI context management. ## Project Stats - Files: {} - Directories: {} - Total size: {} bytes ## Essential Commands ```bash # Build & Test cargo build --release cargo test -- --nocapture cargo clippy -- -D warnings # Smart Tree context st -m context . # Full context with git info st -m quantum . # Compressed for large contexts st -m relations --focus main.rs # Code relationships ``` ## Key Patterns - Always use `Result<T>` for error handling - Prefer `&str` over `String` for function parameters - Use `anyhow` for error context - Run clippy before commits ## Smart Tree Integration This project has hooks configured to automatically provide context. The quantum-semantic mode is used for optimal token efficiency. "#, self.stats.total_files, self.stats.total_dirs, self.stats.total_size ) } ProjectType::Python => { format!( r#"# CLAUDE.md This Python project uses Smart Tree for optimal AI context management. ## Project Stats - Files: {} - Directories: {} - Total size: {} bytes ## Essential Commands ```bash # Environment & Testing uv sync # Install dependencies with uv pytest -v # Run tests ruff check . # Lint code mypy . # Type checking # Smart Tree context st -m context . # Full context with git info st -m quantum . # Compressed for large contexts ``` ## Key Patterns - Use type hints for all functions - Prefer uv over pip for package management - Follow PEP 8 style guide - Write docstrings for all public functions ## Smart Tree Integration Hooks provide automatic context on prompt submission. Test runs trigger summary of test directories. "#, self.stats.total_files, self.stats.total_dirs, self.stats.total_size ) } ProjectType::TypeScript | ProjectType::JavaScript => { format!( r#"# CLAUDE.md This {0} project uses Smart Tree for optimal AI context management. ## Project Stats - Files: {1} - Directories: {2} - Total size: {3} bytes ## Essential Commands ```bash # Development pnpm install # Install dependencies pnpm run dev # Start dev server pnpm test # Run tests pnpm build # Production build # Smart Tree context st -m context . # Full context with git info st -m quantum . # Compressed for large contexts ``` ## Key Patterns - Use pnpm for package management - Implement proper TypeScript types - Follow ESLint rules - Component-based architecture ## Smart Tree Integration Automatic context provision via hooks. Node_modules excluded from summaries. "#, if matches!(self.project_type, ProjectType::TypeScript) { "TypeScript" } else { "JavaScript" }, self.stats.total_files, self.stats.total_dirs, self.stats.total_size ) } _ => { format!( r#"# CLAUDE.md This project uses Smart Tree for optimal AI context management. ## Project Stats - Files: {} - Directories: {} - Total size: {} bytes - Type: {:?} ## Smart Tree Commands ```bash st -m context . # Full context with git info st -m quantum . # Compressed for large contexts st -m summary . # Human-readable summary st -m quantum-semantic . # Maximum compression ``` ## Smart Tree Integration This project has been configured with automatic hooks that provide context to Claude on every prompt. The hook mode is optimized based on your project size. Use `st --help` to explore more features! "#, self.stats.total_files, self.stats.total_dirs, self.stats.total_size, self.project_type ) } }; fs::write(claude_md_path, content)?; 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