Skip to content

Commit 91f29fd

Browse files
authored
Merge pull request #19 from Jakedismo/feat/tui-improvements
feat(cli): Enhance `codegraph index` with a sophisticated TUI
2 parents ef0f873 + 71d1089 commit 91f29fd

File tree

3 files changed

+132
-167
lines changed

3 files changed

+132
-167
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ url = "2.5"
151151

152152
# Tracing and logging
153153
tracing = "0.1"
154-
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
154+
tracing-subscriber = { version = "0.3", features = ["env-filter", "registry"] }
155+
tracing-indicatif = "0.3.1"
155156
tracing-appender = "0.2"
156157
once_cell = "1.19"
157158
hashbrown = "0.16.0"
@@ -174,6 +175,7 @@ base64 = "0.22"
174175
clap = { version = "4.5", features = ["derive", "cargo", "env", "wrap_help"] }
175176
colored = "3.0.0"
176177
indicatif = "0.18.0"
178+
atty = "0.2.14"
177179

178180
# Security
179181
jsonwebtoken = "9.3"

crates/codegraph-mcp/src/bin/codegraph.rs

Lines changed: 73 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
use anyhow::Result;
2+
use atty::Stream;
23
use clap::{Parser, Subcommand};
34
use codegraph_core::GraphStore;
45
use codegraph_mcp::{IndexerConfig, ProcessManager, ProjectIndexer};
56
use colored::*;
7+
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
68
use rmcp::{transport::stdio, ServiceExt};
79
use std::path::PathBuf;
810
use tracing::info;
9-
use tracing_subscriber;
11+
use tracing_indicatif::IndicatifLayer;
12+
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Registry};
1013

1114
#[derive(Parser)]
1215
#[command(
@@ -432,15 +435,10 @@ enum StatsFormat {
432435
async fn main() -> Result<()> {
433436
let cli = Cli::parse();
434437

435-
// Initialize logging
436438
let log_level = if cli.verbose { "debug" } else { "info" };
437-
tracing_subscriber::fmt()
438-
.with_env_filter(std::env::var("RUST_LOG").unwrap_or_else(|_| log_level.to_string()))
439-
.init();
440439

441440
// Load configuration if provided
442441
if let Some(config_path) = &cli.config {
443-
info!("Loading configuration from: {:?}", config_path);
444442
// TODO: Load and merge configuration
445443
}
446444

@@ -705,33 +703,34 @@ async fn handle_start(
705703

706704
match transport {
707705
TransportType::Stdio { buffer_size: _ } => {
708-
// For STDIO transport, reconfigure tracing to use stderr only
709-
tracing_subscriber::fmt()
710-
.with_writer(std::io::stderr)
711-
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
712-
.try_init()
713-
.ok(); // Ignore if already initialized
714-
715-
eprintln!(
716-
"{}",
717-
"Starting CodeGraph MCP Server with 100% Official SDK..."
718-
.green()
719-
.bold()
720-
);
706+
if atty::is(Stream::Stderr) {
707+
eprintln!(
708+
"{}",
709+
"Starting CodeGraph MCP Server with 100% Official SDK..."
710+
.green()
711+
.bold()
712+
);
713+
}
721714

722715
// Create and initialize the revolutionary CodeGraph server with official SDK
723716
let mut server = codegraph_mcp::official_server::CodeGraphMCPServer::new();
724717
server.initialize_qwen().await;
725718

726-
eprintln!("✅ Revolutionary CodeGraph MCP server ready with 100% protocol compliance");
719+
if atty::is(Stream::Stderr) {
720+
eprintln!("✅ Revolutionary CodeGraph MCP server ready with 100% protocol compliance");
721+
}
727722

728723
// Use official rmcp STDIO transport for perfect compliance
729724
let service = server.serve(rmcp::transport::stdio()).await.map_err(|e| {
730-
eprintln!("❌ Failed to start official MCP server: {}", e);
725+
if atty::is(Stream::Stderr) {
726+
eprintln!("❌ Failed to start official MCP server: {}", e);
727+
}
731728
anyhow::anyhow!("MCP server startup failed: {}", e)
732729
})?;
733730

734-
eprintln!("🚀 Official MCP server started with revolutionary capabilities");
731+
if atty::is(Stream::Stderr) {
732+
eprintln!("🚀 Official MCP server started with revolutionary capabilities");
733+
}
735734

736735
// Wait for the server to complete
737736
service
@@ -790,16 +789,23 @@ async fn handle_start(
790789
}
791790

792791
async fn handle_stop(pid_file: Option<PathBuf>, force: bool) -> Result<()> {
793-
println!("{}", "Stopping CodeGraph MCP Server...".yellow().bold());
792+
if atty::is(Stream::Stdout) {
793+
println!("{}", "Stopping CodeGraph MCP Server...".yellow().bold());
794+
}
794795

795796
let manager = ProcessManager::new();
796797

797798
if force {
798-
println!("Force stopping server");
799+
if atty::is(Stream::Stdout) {
800+
println!("Force stopping server");
801+
}
799802
}
800803

801804
manager.stop_server(pid_file, force).await?;
802-
println!("✓ Server stopped");
805+
806+
if atty::is(Stream::Stdout) {
807+
println!("✓ Server stopped");
808+
}
803809

804810
Ok(())
805811
}
@@ -856,45 +862,33 @@ async fn handle_index(
856862
device: Option<String>,
857863
max_seq_len: usize,
858864
) -> Result<()> {
859-
println!("{}", format!("Indexing project: {:?}", path).cyan().bold());
865+
let indicatif_layer = IndicatifLayer::new();
866+
let multi_progress = indicatif_layer.get_progress_bar();
860867

861-
if let Some(langs) = &languages {
862-
println!("Languages: {}", langs.join(", "));
863-
}
868+
let subscriber = Registry::default()
869+
.with(tracing_subscriber::filter::EnvFilter::from_default_env())
870+
.with(indicatif_layer);
864871

865-
if recursive {
866-
println!("Recursive indexing enabled");
867-
}
872+
tracing::subscriber::set_global_default(subscriber).ok();
873+
874+
let h_style = ProgressStyle::with_template("{spinner:.blue} {msg}")
875+
.unwrap()
876+
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ");
877+
878+
let header_pb = multi_progress.add(ProgressBar::new(1));
879+
header_pb.set_style(h_style);
880+
header_pb.set_message(format!("Indexing project: {}", path.to_string_lossy()));
868881

869882
// Memory-aware optimization for high-memory systems
870883
let available_memory_gb = estimate_available_memory_gb();
871884
let (optimized_batch_size, optimized_workers) =
872885
optimize_for_memory(available_memory_gb, batch_size, workers);
873886

874-
println!("Workers: {} → {} (optimized)", workers, optimized_workers);
875-
println!(
876-
"Batch size: {} → {} (optimized)",
877-
batch_size, optimized_batch_size
878-
);
879-
880887
if available_memory_gb >= 64 {
881-
println!(
882-
"{}",
883-
format!(
884-
"🚀 High-memory system detected ({}GB) - performance optimized!",
885-
available_memory_gb
886-
)
887-
.green()
888-
.bold()
889-
);
890-
println!(
891-
"{}",
892-
format!(
893-
"💾 Memory capacity: ~{} embeddings per batch",
894-
optimized_batch_size
895-
)
896-
.cyan()
897-
);
888+
multi_progress.println(format!(
889+
"🚀 High-memory system detected ({}GB) - performance optimized!",
890+
available_memory_gb
891+
))?;
898892
}
899893

900894
// Configure indexer
@@ -914,10 +908,15 @@ async fn handle_index(
914908
};
915909

916910
// Create indexer
917-
let mut indexer = ProjectIndexer::new(config).await?;
911+
let mut indexer = ProjectIndexer::new(config, multi_progress.clone()).await?;
912+
913+
let start_time = std::time::Instant::now();
918914

919915
// Perform indexing
920916
let stats = indexer.index_project(&path).await?;
917+
let elapsed = start_time.elapsed();
918+
919+
header_pb.finish_with_message("✔ Indexing complete".to_string());
921920

922921
println!();
923922
println!("{}", "🎉 INDEXING COMPLETE!".green().bold());
@@ -927,37 +926,35 @@ async fn handle_index(
927926
println!("{}", "📊 Performance Summary".cyan().bold());
928927
println!("┌─────────────────────────────────────────────────┐");
929928
println!(
930-
"│ 📄 Files: {} indexed │",
931-
format!("{:>6}", stats.files).yellow()
932-
);
933-
println!(
934-
"│ 📝 Lines: {} processed │",
935-
format!("{:>6}", stats.lines).yellow()
936-
);
937-
println!(
938-
"│ 🔧 Functions: {} extracted │",
939-
format!("{:>6}", stats.functions).green()
929+
"│ ⏱️ Total time: {:<33} │",
930+
format!("{:.2?}", elapsed).green()
940931
);
941932
println!(
942-
"│ 🏗️ Classes: {} extracted │",
943-
format!("{:>6}", stats.classes).green()
933+
"│ ⚡ Throughput: {:<33} │",
934+
format!("{:.2} files/sec", stats.files as f64 / elapsed.as_secs_f64()).yellow()
944935
);
936+
println!("├─────────────────────────────────────────────────┤");
945937
println!(
946-
"│ 📦 Structs: {} extracted │",
947-
format!("{:>6}", stats.structs).green()
938+
"│ 📄 Files: {} indexed, {} skipped {:<13} │",
939+
format!("{:>6}", stats.files).yellow(),
940+
format!("{:>4}", stats.skipped).yellow(),
941+
""
948942
);
949943
println!(
950-
"│ 🎯 Traits: {} extracted │",
951-
format!("{:>6}", stats.traits).green()
944+
"│ 📝 Lines: {} processed {:<24} │",
945+
format!("{:>6}", stats.lines).yellow(),
946+
""
952947
);
953948
println!(
954-
"│ 💾 Embeddings: {} generated │",
955-
format!("{:>6}", stats.embeddings).cyan()
949+
"│ 💾 Embeddings: {} generated {:<20} │",
950+
format!("{:>6}", stats.embeddings).cyan(),
951+
""
956952
);
957953
if stats.errors > 0 {
958954
println!(
959-
"│ ❌ Errors: {} encountered │",
960-
format!("{:>6}", stats.errors).red()
955+
"│ ❌ Errors: {} encountered {:<24} │",
956+
format!("{:>6}", stats.errors).red(),
957+
""
961958
);
962959
}
963960
println!("└─────────────────────────────────────────────────┘");

0 commit comments

Comments
 (0)