pub mod commands; use clap::{Args, Parser, Subcommand}; use crate::model::{ enums::{ProjectSide, ProjectType, UpdateStrategy}, fork::RefType, }; #[derive(Parser)] #[clap(name = "pakker")] #[clap(about = "A multiplatform modpack manager for Minecraft", long_about = None)] pub struct Cli { /// Enable verbose output (-v for info, -vv for debug, -vvv for trace) #[clap(short, long, action = clap::ArgAction::Count)] pub verbose: u8, #[clap(subcommand)] pub command: Commands, } #[derive(Subcommand)] pub enum Commands { /// Initialize a new modpack project Init(InitArgs), /// Import an existing modpack Import(ImportArgs), /// Add projects to the modpack Add(AddArgs), /// Add projects with explicit platform specification (non-interactive) #[clap(name = "add-prj", alias = "prj")] AddPrj(AddPrjArgs), /// Remove projects from the modpack Rm(RmArgs), /// Update projects Update(UpdateArgs), /// List projects in the modpack Ls(LsArgs), /// Set project properties Set(SetArgs), /// Link projects together Link(LinkArgs), /// Unlink projects Unlink(UnlinkArgs), /// Show differences between local and remote Diff(DiffArgs), /// Fetch project files Fetch(FetchArgs), /// Sync projects (fetch + update) Sync(SyncArgs), /// Export modpack Export(ExportArgs), /// Manage remote repositories Remote(RemoteArgs), /// Update modpack from remote Git repository RemoteUpdate(RemoteUpdateArgs), /// Check for available updates Status(StatusArgs), /// Inspect project details Inspect(InspectArgs), /// Manage API credentials Credentials(CredentialsArgs), /// Configure modpack properties Cfg(CfgArgs), /// Manage fork configuration Fork(ForkArgs), } #[derive(Args)] pub struct InitArgs { /// Modpack name #[clap(short, long)] pub name: Option, /// Modpack version #[clap(short = 'V', long)] pub version: Option, /// Target platform #[clap(short, long)] pub target: Option, /// Minecraft versions (space-separated) #[clap(short, long = "mc-versions", value_delimiter = ' ', num_args = 1..)] pub mc_versions: Option>, /// Mod loaders (format: name=version, can be specified multiple times) #[clap(short, long = "loaders", value_delimiter = ',')] pub loaders: Option>, /// Skip interactive prompts (use defaults) #[clap(short, long)] pub yes: bool, } #[derive(Args)] pub struct ImportArgs { /// Path to modpack file pub file: String, /// Resolve dependencies #[clap(short = 'D', long = "deps")] pub deps: bool, /// Skip confirmation prompts #[clap(short, long)] pub yes: bool, } #[derive(Args)] pub struct AddArgs { /// Project identifiers to add #[clap(required = true)] pub inputs: Vec, /// Project type (mod, resourcepack, shader, datapack, world) #[clap(short = 't', long = "type")] pub project_type: Option, /// Skip resolving dependencies #[clap(short = 'D', long)] pub no_deps: bool, /// Update if already exists #[clap(short, long)] pub update: bool, /// Skip confirmation prompts #[clap(short, long)] pub yes: bool, } #[derive(Args)] pub struct AddPrjArgs { /// `CurseForge` project slug or ID (optional file ID: `slug#file_id`) #[clap(long = "cf", alias = "curseforge")] pub curseforge: Option, /// Modrinth project slug or ID (optional file ID: `slug#file_id`) #[clap(long = "mr", alias = "modrinth")] pub modrinth: Option, /// GitHub repository (format: owner/repo or owner/repo#tag) #[clap(long = "gh", alias = "github")] pub github: Option, /// Project type (mod, resourcepack, shader, datapack, world) #[clap(short = 't', long = "type")] pub project_type: Option, /// Project side (client, server, both) #[clap(long)] pub side: Option, /// Update strategy (latest, none) #[clap(long)] pub strategy: Option, /// Redistributable flag #[clap(long)] pub redistributable: Option, /// Subpath for project file placement #[clap(long)] pub subpath: Option, /// Project aliases (can be specified multiple times) #[clap(long = "alias")] pub aliases: Vec, /// Export flag (whether to include in exports) #[clap(long)] pub export: Option, /// Skip resolving dependencies #[clap(short = 'D', long = "no-deps")] pub no_deps: bool, /// Skip confirmation prompts #[clap(short, long)] pub yes: bool, } #[derive(Args)] pub struct RmArgs { /// Project identifiers to remove #[clap(required = true)] pub inputs: Vec, /// Remove all projects #[clap(short = 'a', long)] pub all: bool, /// Skip confirmation prompt #[clap(short, long)] pub yes: bool, /// Skip removing dependent projects #[clap(short = 'D', long = "no-deps")] pub no_deps: bool, } #[derive(Args)] pub struct UpdateArgs { /// Projects to update (empty = all) #[arg(value_name = "PROJECT")] pub inputs: Vec, /// Update all projects #[arg(short, long)] pub all: bool, /// Skip confirmation prompts #[arg(short, long)] pub yes: bool, } #[derive(Args)] pub struct LsArgs { /// Show detailed information #[clap(short, long)] pub detailed: bool, /// Add update information for projects #[clap(short = 'c', long = "check-updates")] pub check_updates: bool, /// Maximum length for project names #[clap(long = "name-max-length")] pub name_max_length: Option, } #[derive(Args)] pub struct SetArgs { /// Project identifier (optional for lockfile properties) pub input: Option, /// Project type #[clap(long)] pub r#type: Option, /// Project side (client/server/both) #[clap(long)] pub side: Option, /// Update strategy (latest/none) #[clap(long)] pub strategy: Option, /// Redistributable flag #[clap(long)] pub redistributable: Option, /// Change the target of the pack (curseforge, modrinth, multiplatform) #[clap(short = 't', long)] pub target: Option, /// Change the minecraft versions (comma-separated) #[clap(short = 'v', long)] pub mc_versions: Option, /// Change the mod loaders (format: name=version,name=version) #[clap(short = 'l', long)] pub loaders: Option, } #[derive(Args)] pub struct LinkArgs { /// Source project pub from: String, /// Target project pub to: String, } #[derive(Args)] pub struct UnlinkArgs { /// Source project pub from: String, /// Target project pub to: String, } #[derive(Args)] pub struct DiffArgs { /// Path to old lockfile pub old_lockfile: String, /// Path to current lockfile (optional, defaults to pakku-lock.json) pub current_lockfile: Option, /// Export markdown diff #[clap(long)] pub markdown_diff: Option, /// Export markdown (formatted) #[clap(long)] pub markdown: Option, /// Verbose output (show file changes) #[clap(short, long)] pub verbose: bool, /// Header size for markdown (0-5) #[clap(short = 'H', long, default_value = "2")] pub header_size: usize, } #[derive(Args)] pub struct FetchArgs { /// Timeout for waiting on conflicting operations (seconds) #[clap(short, long)] pub timeout: Option, /// Number of retry attempts for failed downloads #[clap(short = 'r', long, default_value = "2")] pub retry: u32, /// Move unknown files to shelf instead of deleting #[clap(long)] pub shelve: bool, } #[derive(Args)] pub struct SyncArgs { /// Sync additions only #[clap(short = 'A', long)] pub additions: bool, /// Sync removals only #[clap(short = 'R', long)] pub removals: bool, /// Sync updates only (apply pending updates) #[clap(short = 'U', long)] pub updates: bool, } #[derive(Args)] pub struct ExportArgs { /// Export profile (curseforge, modrinth, serverpack) /// If not specified, all profiles will be exported #[clap(short, long)] pub profile: Option, /// Output directory #[clap(short, long)] pub output: Option, /// Use Pakker-compatible output layout (build//...) /// Default is Pakker layout (exports/...) #[clap(long)] pub pakker_layout: bool, /// Show file IO errors during export #[clap(long = "show-io-errors")] pub show_io_errors: bool, /// Export modpack without server content /// Modrinth: exclude server-overrides and SERVER mods /// `ServerPack`: skip export #[clap(long = "no-server")] pub no_server: bool, } #[derive(Args)] pub struct RemoteArgs { /// Git URL to install from (if empty, shows status) pub url: Option, /// Branch to checkout (instead of remote's HEAD) #[clap(short, long)] pub branch: Option, /// Install server pack #[clap(short = 'S', long)] pub server_pack: bool, /// Retry count for downloads #[clap(short, long, default_value = "2")] pub retry: u32, /// Remove remote from modpack #[clap(long = "rm", long = "remove")] pub remove: bool, } #[derive(Args)] pub struct RemoteUpdateArgs { /// Branch to checkout instead of remote's HEAD #[clap(short, long)] pub branch: Option, /// Install server pack instead of full modpack #[clap(short, long)] pub server_pack: bool, } #[derive(Args)] pub struct StatusArgs { /// Check updates in parallel #[clap(short, long)] pub parallel: bool, } #[derive(Args)] pub struct InspectArgs { /// Project identifiers to inspect #[clap(required = true)] pub projects: Vec, } #[derive(Args)] pub struct CredentialsArgs { /// Delete stored credentials (defaults to deleting both file and keyring) #[clap(short, long)] pub delete: bool, /// Delete credentials file (~/.pakku/credentials) #[clap(long)] pub delete_file: bool, /// Delete credentials from keyring (service: pakker) #[clap(long)] pub delete_keyring: bool, #[clap(subcommand)] pub subcommand: Option, } #[derive(Subcommand)] pub enum CredentialsSubcommand { /// Set API credentials Set(CredentialsSetArgs), } #[derive(Args)] pub struct CredentialsSetArgs { /// `CurseForge` API key #[clap(long)] pub cf_api_key: Option, /// Modrinth API token #[clap(long)] pub modrinth_token: Option, /// GitHub access token #[clap(long)] pub gh_access_token: Option, } #[derive(Args)] pub struct CfgArgs { /// Modpack name #[clap(long)] pub name: Option, /// Modpack version #[clap(long)] pub version: Option, /// Modpack description #[clap(long)] pub description: Option, /// Modpack author #[clap(long)] pub author: Option, /// Path for mods #[clap(long)] pub mods_path: Option, /// Path for resource packs #[clap(long)] pub resource_packs_path: Option, /// Path for data packs #[clap(long)] pub data_packs_path: Option, /// Path for worlds #[clap(long)] pub worlds_path: Option, /// Path for shaders #[clap(long)] pub shaders_path: Option, #[clap(subcommand)] pub subcommand: Option, } #[derive(Subcommand)] pub enum CfgSubcommand { /// Configure per-project settings Prj(CfgPrjArgs), } #[derive(Args)] pub struct CfgPrjArgs { /// Project identifier pub project: String, /// Project type #[clap(long)] pub r#type: Option, /// Project side (client/server/both) #[clap(long)] pub side: Option, /// Update strategy (latest/none) #[clap(long)] pub update_strategy: Option, /// Redistributable flag #[clap(long)] pub redistributable: Option, /// Subpath for project #[clap(long)] pub subpath: Option, /// Add alias #[clap(long)] pub add_alias: Option, /// Remove alias #[clap(long)] pub remove_alias: Option, /// Export flag #[clap(long)] pub export: Option, } /// Fork subcommand arguments #[derive(Debug, Args)] #[command(args_conflicts_with_subcommands = true)] pub struct ForkArgs { #[clap(subcommand)] pub subcommand: ForkSubcommand, } #[derive(Debug, Subcommand)] pub enum ForkSubcommand { /// Initialize fork from parent repository Init { /// Git URL of parent repository #[clap(long, conflicts_with = "from_path")] git_url: Option, /// Use current repository as parent #[clap(long, conflicts_with = "from_path")] from_current: bool, /// Use an already-cloned repository as parent (path to worktree or .git) #[clap(long, value_parser, conflicts_with_all = &["git_url", "from_current"])] from_path: Option, /// Branch/tag/commit to track #[clap(long)] ref_name: Option, /// Type of ref (branch/tag/commit) #[clap(long, value_enum)] ref_type: Option, /// Remote name #[clap(long, default_value = "origin")] remote: Option, }, /// Update fork configuration Set { /// New git URL (optional) #[clap(long)] git_url: Option, /// Branch/tag/commit to track #[clap(long)] ref_name: String, /// Type of ref (branch/tag/commit) #[clap(long, value_enum)] ref_type: Option, /// Remote name #[clap(long)] remote: Option, }, /// Show fork configuration Show, /// Remove fork configuration Unset, /// Sync with parent repository Sync, /// Promote projects to parent (legacy) Promote { /// Project identifiers to promote projects: Vec, }, }