use std::io;
use std::time::Duration;
use claude_dashboard::app::App;
use crossterm::{
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::Terminal;
use ratatui::backend::CrosstermBackend;
fn main() -> Result<(), String> {
let cli = claude_dashboard::utils::parse_cli_args();
let claude_dir = claude_dashboard::utils::find_claude_dir(cli.data_dir.as_deref())
.ok_or_else(|| {
eprintln!("Claude data directory not found.");
eprintln!("Expected at: %USERPROFILE%\\.claude or ~/.claude");
eprintln!("Use --data-dir <PATH> to specify a custom location");
"Claude data directory not found".to_string()
})?;
let stats = claude_dashboard::data::stats::parse_stats_cache(&claude_dir.join("stats-cache.json"))
.unwrap_or_else(|e| {
eprintln!("Warning: Could not parse stats-cache.json: {}", e);
Default::default()
});
let history = claude_dashboard::data::history::parse_history(&claude_dir.join("history.jsonl"))
.unwrap_or_else(|e| {
eprintln!("Warning: Could not parse history.jsonl: {}", e);
Vec::new()
});
let project_dirs = claude_dashboard::data::projects::discover_projects(&claude_dir.join("projects"), &history)
.unwrap_or_else(|e| {
eprintln!("Warning: Could not discover projects: {}", e);
Vec::new()
});
if project_dirs.is_empty() {
eprintln!("Warning: No projects found in {}/projects", claude_dir.display());
}
enable_raw_mode().map_err(|e| format!("Failed to enable raw mode: {}", e))?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)
.map_err(|e| format!("Failed to enter alternate screen: {}", e))?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)
.map_err(|e| format!("Failed to create terminal: {}", e))?;
claude_dashboard::i18n::init();
let mut app = App::new(stats, history, project_dirs, cli.start_tab, claude_dir);
let tick_rate = Duration::from_millis(250);
let result = run_event_loop(&mut terminal, &mut app, tick_rate);
let _ = disable_raw_mode();
let _ = execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
);
result
}
fn run_event_loop(
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
app: &mut App,
tick_rate: Duration,
) -> Result<(), String> {
loop {
terminal
.draw(|f| claude_dashboard::ui::render(f, app))
.map_err(|e| format!("Failed to draw frame: {}", e))?;
if event::poll(tick_rate).map_err(|e| format!("Event poll error: {}", e))? {
if let Event::Key(key) = event::read().map_err(|e| format!("Event read error: {}", e))? {
if key.kind == KeyEventKind::Release {
continue;
}
if key.code == KeyCode::Char('q') || key.code == KeyCode::Esc {
return Ok(());
}
app.handle_event(key);
}
}
app.tick();
}
}