use clap::Parser;
mod cmd;
mod descmd;
use cliban::migrate;
mod audit;
mod errors;
mod output;
mod search;
mod since;
mod store_open;
#[derive(clap::Args)]
struct MigrateLegacyArgs {
#[arg(long)]
from: String,
#[arg(long)]
to: String,
}
#[derive(Parser)]
#[command(
name = "cliban",
version,
about = "AI-agent-first kanban board for the terminal"
)]
struct Cli {
#[arg(long, global = true)]
db: Option<String>,
#[command(subcommand)]
cmd: Option<Command>,
}
#[derive(clap::Subcommand)]
enum Command {
Tui,
Project(cmd::project::ProjectArgs),
Label(cmd::label::LabelArgs),
Issue(cmd::issue::IssueArgs),
Activity(cmd::activity::ActivityArgs),
Milestone(cmd::milestone::MilestoneArgs),
Fff(cmd::fff::FffArgs),
#[cfg(feature = "linear")]
Import(cmd::sync::ImportArgs),
#[cfg(feature = "linear")]
Push(cmd::sync::PushArgs),
MigrateLegacy(MigrateLegacyArgs),
}
fn main() {
let cli = Cli::parse();
if matches!(cli.cmd, None | Some(Command::Tui)) {
let path = store_open::db_path(&cli.db);
if let Err(e) = cliban_tui::run(path) {
eprintln!("error: {e}");
std::process::exit(1);
}
return;
}
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("build tokio runtime");
if let Err(e) = rt.block_on(run(cli)) {
eprintln!("error: {}", e.message());
std::process::exit(e.code());
}
}
async fn run(cli: Cli) -> errors::CliResult<()> {
match cli.cmd {
None | Some(Command::Tui) => unreachable!("TUI handled in main before runtime"),
Some(Command::Project(args)) => cmd::project::run(&cli.db, args).await,
Some(Command::Label(args)) => cmd::label::run(&cli.db, args).await,
Some(Command::Issue(args)) => cmd::issue::run(&cli.db, args).await,
Some(Command::Activity(args)) => cmd::activity::run(&cli.db, args).await,
Some(Command::Milestone(args)) => cmd::milestone::run(&cli.db, args).await,
Some(Command::Fff(args)) => cmd::fff::run(&cli.db, args).await,
#[cfg(feature = "linear")]
Some(Command::Import(args)) => cmd::sync::run_import(&cli.db, args).await,
#[cfg(feature = "linear")]
Some(Command::Push(args)) => cmd::sync::run_push(&cli.db, args).await,
Some(Command::MigrateLegacy(args)) => {
let report = migrate::migrate(
std::path::Path::new(&args.from),
std::path::Path::new(&args.to),
)
.map_err(errors::CliError::other)?;
println!(
"migrated: {} projects, {} milestones, {} issues, {} labels, {} issue_labels, {} relations",
report.projects, report.milestones, report.issues, report.labels,
report.issues_labels, report.relations,
);
Ok(())
}
}
}