//! CLI module with clap command definitions. pub mod commands; use clap::{Parser, Subcommand}; use std::io::IsTerminal; /// Gitlore - Local GitLab data management with semantic search #[derive(Parser)] #[command(name = "lore")] #[command(version, about, long_about = None)] pub struct Cli { /// Path to config file #[arg(short = 'c', long, global = true)] pub config: Option, /// Machine-readable JSON output (auto-enabled when piped) #[arg(long, global = true, env = "LORE_ROBOT")] pub robot: bool, /// JSON output (global shorthand) #[arg(short = 'J', long = "json", global = true)] pub json: bool, #[command(subcommand)] pub command: Commands, } impl Cli { /// Check if robot mode is active (explicit flag, env var, or non-TTY stdout) pub fn is_robot_mode(&self) -> bool { self.robot || self.json || !std::io::stdout().is_terminal() } } #[derive(Subcommand)] #[allow(clippy::large_enum_variant)] pub enum Commands { /// List or show issues Issues(IssuesArgs), /// List or show merge requests Mrs(MrsArgs), /// Ingest data from GitLab Ingest(IngestArgs), /// Count entities in local database Count(CountArgs), /// Show sync state Status, /// Verify GitLab authentication Auth, /// Check environment health Doctor, /// Show version information Version, /// Initialize configuration and database Init { /// Skip overwrite confirmation #[arg(short = 'f', long)] force: bool, /// Fail if prompts would be shown #[arg(long)] non_interactive: bool, }, /// Create timestamped database backup Backup, /// Delete database and reset all state Reset { /// Skip confirmation prompt #[arg(short = 'y', long)] yes: bool, }, /// Run pending database migrations Migrate, // --- Hidden backward-compat aliases --- /// List issues or MRs (deprecated: use 'lore issues' or 'lore mrs') #[command(hide = true)] List { /// Entity type to list #[arg(value_parser = ["issues", "mrs"])] entity: String, #[arg(long, default_value = "50")] limit: usize, #[arg(long)] project: Option, #[arg(long)] state: Option, #[arg(long)] author: Option, #[arg(long)] assignee: Option, #[arg(long)] label: Option>, #[arg(long)] milestone: Option, #[arg(long)] since: Option, #[arg(long)] due_before: Option, #[arg(long)] has_due_date: bool, #[arg(long, value_parser = ["updated", "created", "iid"], default_value = "updated")] sort: String, #[arg(long, value_parser = ["desc", "asc"], default_value = "desc")] order: String, #[arg(long)] open: bool, #[arg(long, conflicts_with = "no_draft")] draft: bool, #[arg(long, conflicts_with = "draft")] no_draft: bool, #[arg(long)] reviewer: Option, #[arg(long)] target_branch: Option, #[arg(long)] source_branch: Option, }, /// Show detailed entity information (deprecated: use 'lore issues ' or 'lore mrs ') #[command(hide = true)] Show { /// Entity type to show #[arg(value_parser = ["issue", "mr"])] entity: String, /// Entity IID iid: i64, #[arg(long)] project: Option, }, /// Verify GitLab authentication (deprecated: use 'lore auth') #[command(hide = true, name = "auth-test")] AuthTest, /// Show sync state (deprecated: use 'lore status') #[command(hide = true, name = "sync-status")] SyncStatus, } /// Arguments for `lore issues [IID]` #[derive(Parser)] pub struct IssuesArgs { /// Issue IID (omit to list, provide to show details) pub iid: Option, /// Maximum results #[arg(short = 'n', long = "limit", default_value = "50")] pub limit: usize, /// Filter by state (opened, closed, all) #[arg(short = 's', long)] pub state: Option, /// Filter by project path #[arg(short = 'p', long)] pub project: Option, /// Filter by author username #[arg(short = 'a', long)] pub author: Option, /// Filter by assignee username #[arg(short = 'A', long)] pub assignee: Option, /// Filter by label (repeatable, AND logic) #[arg(short = 'l', long)] pub label: Option>, /// Filter by milestone title #[arg(short = 'm', long)] pub milestone: Option, /// Filter by time (7d, 2w, 1m, or YYYY-MM-DD) #[arg(long)] pub since: Option, /// Filter by due date (before this date, YYYY-MM-DD) #[arg(long = "due-before")] pub due_before: Option, /// Show only issues with a due date #[arg(long = "has-due")] pub has_due: bool, /// Sort field (updated, created, iid) #[arg(long, value_parser = ["updated", "created", "iid"], default_value = "updated")] pub sort: String, /// Sort ascending (default: descending) #[arg(long)] pub asc: bool, /// Open first matching item in browser #[arg(short = 'o', long)] pub open: bool, } /// Arguments for `lore mrs [IID]` #[derive(Parser)] pub struct MrsArgs { /// MR IID (omit to list, provide to show details) pub iid: Option, /// Maximum results #[arg(short = 'n', long = "limit", default_value = "50")] pub limit: usize, /// Filter by state (opened, merged, closed, locked, all) #[arg(short = 's', long)] pub state: Option, /// Filter by project path #[arg(short = 'p', long)] pub project: Option, /// Filter by author username #[arg(short = 'a', long)] pub author: Option, /// Filter by assignee username #[arg(short = 'A', long)] pub assignee: Option, /// Filter by reviewer username #[arg(short = 'r', long)] pub reviewer: Option, /// Filter by label (repeatable, AND logic) #[arg(short = 'l', long)] pub label: Option>, /// Filter by time (7d, 2w, 1m, or YYYY-MM-DD) #[arg(long)] pub since: Option, /// Show only draft MRs #[arg(short = 'd', long, conflicts_with = "no_draft")] pub draft: bool, /// Exclude draft MRs #[arg(short = 'D', long = "no-draft", conflicts_with = "draft")] pub no_draft: bool, /// Filter by target branch #[arg(long)] pub target: Option, /// Filter by source branch #[arg(long)] pub source: Option, /// Sort field (updated, created, iid) #[arg(long, value_parser = ["updated", "created", "iid"], default_value = "updated")] pub sort: String, /// Sort ascending (default: descending) #[arg(long)] pub asc: bool, /// Open first matching item in browser #[arg(short = 'o', long)] pub open: bool, } /// Arguments for `lore ingest [ENTITY]` #[derive(Parser)] pub struct IngestArgs { /// Entity to ingest (issues, mrs). Omit to ingest everything. #[arg(value_parser = ["issues", "mrs"])] pub entity: Option, /// Filter to single project #[arg(short = 'p', long)] pub project: Option, /// Override stale sync lock #[arg(short = 'f', long)] pub force: bool, /// Full re-sync: reset cursors and fetch all data from scratch #[arg(long)] pub full: bool, } /// Arguments for `lore count ` #[derive(Parser)] pub struct CountArgs { /// Entity type to count (issues, mrs, discussions, notes) #[arg(value_parser = ["issues", "mrs", "discussions", "notes"])] pub entity: String, /// Parent type filter: issue or mr (for discussions/notes) #[arg(short = 'f', long = "for", value_parser = ["issue", "mr"])] pub for_entity: Option, }