#![ allow( missing_docs ) ]
use std::{ env, io::{ self, Write }, process };
use crate::cli;
use unilang::prelude::*;
use unilang::phf;
include!( concat!( env!( "OUT_DIR" ), "/static_commands.rs" ) );
fn build_command_registry() -> CommandRegistry
{
type RoutineFn = fn( VerifiedCommand, ExecutionContext ) -> Result< OutputData, ErrorData >;
let routines : phf::Map< &'static str, RoutineFn > = phf::phf_map!
{
".status" => cli::status_routine,
".list" => cli::list_routine,
".show" => cli::show_routine,
".count" => cli::count_routine,
".search" => cli::search_routine,
".export" => cli::export_routine,
".projects" => cli::projects_routine,
".path" => cli::path_routine,
".exists" => cli::exists_routine,
".session.dir" => cli::session_dir_routine,
".session.ensure" => cli::session_ensure_routine,
};
#[ allow( deprecated ) ]
let mut registry = CommandRegistry::new();
for ( name, static_cmd ) in AGGREGATED_COMMANDS.entries()
{
if let Some( &routine ) = routines.get( *name )
{
let cmd : CommandDefinition = ( *static_cmd ).into();
#[ allow( deprecated ) ]
if let Err( e ) = registry.command_add_runtime( &cmd, Box::new( routine ) )
{
eprintln!( "WARNING: Failed to register routine for {name}: {e}" );
}
}
}
registry
}
fn run_repl( registry : CommandRegistry )
{
println!( "Claude Code Storage CLI" );
println!( "Type 'help' for available commands, 'exit' to quit.\n" );
let pipeline = Pipeline::new( registry );
let mut command_buffer = String::new();
loop
{
print!( "> " );
io::stdout().flush().unwrap();
command_buffer.clear();
if let Err( e ) = io::stdin().read_line( &mut command_buffer )
{
eprintln!( "Error reading input: {e}" );
continue;
}
let input = command_buffer.trim();
if input.is_empty() { continue; }
if input == "exit" || input == "quit" || input == "q"
{
println!( "Goodbye!" );
break;
}
let result = pipeline.process_command_simple( input );
if result.success
{
if let Some( output ) = result.outputs.first()
{
println!( "{}", output.content );
}
}
else if let Some( error ) = result.error
{
eprintln!( "Error: {error}" );
}
}
}
fn extract_user_message( error : &str ) -> String
{
let trimmed = error.trim_end();
for prefix in &[
"Execution error: Execution Error: ",
"Semantic analysis error: Execution Error: ",
]
{
if let Some( rest ) = trimmed.strip_prefix( prefix )
{
return rest.trim().to_string();
}
}
trimmed.to_string()
}
#[ allow( clippy::needless_pass_by_value ) ]
fn execute_oneshot( registry : CommandRegistry, args : Vec< String > ) -> !
{
let pipeline = Pipeline::new( registry );
let command_line = args[ 1.. ].join( " " );
let result = pipeline.process_command_simple( &command_line );
if result.success
{
if let Some( output ) = result.outputs.first()
{
println!( "{}", output.content );
}
process::exit( 0 );
}
else
{
if let Some( error ) = result.error
{
eprintln!( "{}", extract_user_message( &error ) );
}
process::exit( 1 );
}
}
#[ inline ]
pub fn run()
{
let registry = build_command_registry();
let args : Vec< String > = env::args().collect();
if args.len() == 1
{
run_repl( registry );
}
else
{
execute_oneshot( registry, args );
}
}