use clap::{Parser, Subcommand};
use std::process;
mod analyzer;
mod api;
mod commands;
mod config;
mod error;
mod parser;
mod search;
mod server;
mod storage;
mod tui;
mod watcher;
use error::Result;
#[derive(Parser)]
#[command(name = "claude-hindsight")]
#[command(version, about, long_about = None)]
#[command(author = "Codestz <est.estrada@outlook.com>")]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand)]
enum Commands {
Init {
#[arg(long)]
enable_otel: bool,
},
List {
#[arg(short, long)]
project: Option<String>,
#[arg(long)]
errors: bool,
#[arg(short, long)]
last: Option<usize>,
#[arg(long)]
today: bool,
#[arg(long)]
with_subagents: bool,
},
Watch {
#[arg(short, long)]
dashboard: bool,
session_id: Option<String>,
},
Show {
session_id: String,
#[arg(short, long)]
dashboard: bool,
#[arg(short, long, default_value = "3939")]
port: u16,
},
Search {
query: String,
#[arg(long)]
tool: Vec<String>,
#[arg(long)]
errors: bool,
},
Export {
session_id: String,
#[arg(short, long, default_value = "report.html")]
output: String,
},
Config {
#[command(subcommand)]
action: ConfigAction,
},
Paths {
#[command(subcommand)]
action: PathsAction,
},
Reindex {
#[arg(short, long)]
verbose: bool,
},
Serve {
#[arg(short, long, default_value = "7227")]
port: u16,
#[arg(long)]
open: bool,
},
}
#[derive(Subcommand)]
enum PathsAction {
List,
Add {
path: String,
#[arg(long)]
name: Option<String>,
},
Remove {
path: String,
},
}
#[derive(Subcommand)]
enum ConfigAction {
Show,
Edit,
Reset,
Validate,
}
fn main() {
if let Err(e) = run() {
eprintln!("Error: {}", e);
process::exit(1);
}
}
fn run() -> Result<()> {
let cli = Cli::parse();
let command = match cli.command {
Some(cmd) => cmd,
None => {
let config = config::Config::load()?;
match config.ui.default_view.as_str() {
"last_session" => {
return run_last_session();
}
_ => {
return run_hub();
}
}
}
};
match command {
Commands::Init { enable_otel } => {
commands::init::run(enable_otel)?;
}
Commands::List {
project,
errors,
last,
today,
with_subagents,
} => {
commands::list::run(project, errors, last, today, with_subagents)?;
}
Commands::Watch {
dashboard,
session_id,
} => {
commands::watch::run(session_id, dashboard)?;
}
Commands::Show {
session_id,
dashboard,
port,
} => {
commands::show::run(session_id, dashboard, port)?;
}
Commands::Search {
query,
tool,
errors,
} => {
commands::search::run(query, tool, errors)?;
}
Commands::Export { session_id, output } => {
commands::export::run(session_id, output)?;
}
Commands::Paths { action } => match action {
PathsAction::List => commands::paths::list()?,
PathsAction::Add { path, name } => commands::paths::add(path, name)?,
PathsAction::Remove { path } => commands::paths::remove(path)?,
},
Commands::Config { action } => match action {
ConfigAction::Show => commands::config::show_config()?,
ConfigAction::Edit => commands::config::edit_config()?,
ConfigAction::Reset => commands::config::reset_config()?,
ConfigAction::Validate => commands::config::validate_config()?,
},
Commands::Reindex { verbose } => {
commands::reindex::run(verbose)?;
}
Commands::Serve { port, open } => {
commands::serve::run(port, open)?;
}
}
Ok(())
}
fn run_hub() -> Result<()> {
use tui::router::Router;
use tui::EventHandler;
let mut router = Router::new()?;
let mut terminal = tui::init()?;
let mut event_handler = EventHandler::new(250);
loop {
terminal.draw(|f| router.render(f))?;
if let tui::Event::Key(key) = event_handler.poll()? {
router.handle_key(key)?;
}
router.tick();
if router.should_quit {
break;
}
}
tui::restore()?;
Ok(())
}
fn run_last_session() -> Result<()> {
use storage::SessionIndex;
use tui::router::Router;
use tui::EventHandler;
let index = SessionIndex::new()?;
let latest = index.get_latest()?;
match latest {
Some(session_file) => {
let mut router = Router::new_with_session(session_file.session_id)?;
let mut terminal = tui::init()?;
let mut event_handler = EventHandler::new(250);
loop {
terminal.draw(|f| router.render(f))?;
if let tui::Event::Key(key) = event_handler.poll()? {
router.handle_key(key)?;
}
router.tick();
if router.should_quit {
break;
}
}
tui::restore()?;
Ok(())
}
None => {
eprintln!("No sessions found. Run 'hindsight init' to discover sessions.");
eprintln!("Falling back to projects view...");
run_hub()
}
}
}