use unilang::{ VerifiedCommand, ExecutionContext, OutputData, ErrorData, ErrorCode };
use claude_storage_core::Storage;
use super::storage::{ create_storage, resolve_path_parameter };
#[ allow( clippy::needless_pass_by_value ) ]
#[ allow( clippy::too_many_lines ) ]
#[ inline ]
pub fn status_routine( cmd : VerifiedCommand, _ctx : ExecutionContext )
-> core::result::Result< OutputData, ErrorData >
{
let show_tokens = cmd.get_boolean( "show_tokens" ).unwrap_or( false );
let custom_path = cmd.get_string( "path" );
let verbosity = cmd.get_integer( "verbosity" ).unwrap_or( 1 );
if !( 0..=5 ).contains( &verbosity )
{
return Err( ErrorData::new(
ErrorCode::InternalError,
format!( "Invalid verbosity: {verbosity}. Valid range: 0-5" ),
) );
}
let resolved_path = custom_path
.map( | path | resolve_path_parameter( path )
.map_err( | e | ErrorData::new( ErrorCode::InternalError, format!( "Failed to resolve path '{path}': {e}" ) ) )
)
.transpose()?;
if let Some( ref path ) = resolved_path
{
if !std::path::Path::new( path ).exists()
{
eprintln!( "Storage root does not exist: {path}" );
std::process::exit( 2 );
}
}
let storage = if let Some( path ) = resolved_path
{
Storage::with_root( &path )
}
else
{
create_storage()?
};
if verbosity == 0
{
let stats = storage.global_stats_fast()
.map_err( | e | ErrorData::new( ErrorCode::InternalError, format!( "Failed to get statistics: {e}" ) ) )?;
let output = format!( "projects: {}\nsessions: {}\n", stats.total_projects, stats.total_sessions );
return Ok( OutputData::new( output, "text" ) );
}
let output = if show_tokens
{
let stats = storage.global_stats()
.map_err( | e | ErrorData::new( ErrorCode::InternalError, format!( "Failed to get statistics: {e}" ) ) )?;
format!
(
"Storage: {}\n\
Projects: {} (UUID: {}, Path: {})\n\
Sessions: {} (Main: {}, Agent: {})\n\
Entries: {} (User: {}, Assistant: {})\n\
Tokens:\n\
- Input: {}\n\
- Output: {}\n\
- Cache Read: {}\n\
- Cache Creation: {}",
storage.root().display(),
stats.total_projects,
stats.uuid_projects,
stats.path_projects,
stats.total_sessions,
stats.main_sessions,
stats.agent_sessions,
stats.total_entries,
stats.total_user_entries,
stats.total_assistant_entries,
stats.total_input_tokens,
stats.total_output_tokens,
stats.total_cache_read_tokens,
stats.total_cache_creation_tokens
)
}
else
{
let stats = storage.global_stats_fast()
.map_err( | e | ErrorData::new( ErrorCode::InternalError, format!( "Failed to get statistics: {e}" ) ) )?;
format!
(
"Storage: {}\nProjects: {} (UUID: {}, Path: {})\nSessions: {} (Main: {}, Agent: {})",
storage.root().display(),
stats.total_projects,
stats.uuid_projects,
stats.path_projects,
stats.total_sessions,
stats.main_sessions,
stats.agent_sessions,
)
};
if verbosity >= 2
{
use core::fmt::Write as FmtWrite;
let mut detail = output;
detail.push_str( "\n\nPer-project sessions:\n" );
let projects = storage.list_projects()
.map_err( | e | ErrorData::new( ErrorCode::InternalError, format!( "Failed to list projects: {e}" ) ) )?;
for project in projects
{
if let Ok( stats ) = project.project_stats()
{
writeln!(
detail,
" {:?}: {} sessions, User: {}, Assistant: {}",
project.id(),
stats.session_count,
stats.total_user_entries,
stats.total_assistant_entries,
).ok();
}
else
{
let count = project.count_sessions().unwrap_or( 0 );
writeln!( detail, " {:?}: {count} sessions", project.id() ).ok();
}
}
return Ok( OutputData::new( detail, "text" ) );
}
Ok( OutputData::new( output, "text" ) )
}