Skip to main content

fuelcheck_cli/
args.rs

1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4use fuelcheck_core::model::OutputFormat;
5use fuelcheck_core::providers::{ProviderSelector, SourcePreference};
6use fuelcheck_core::reports::CostReportKind;
7
8use crate::logger::LogLevel;
9
10#[derive(Parser, Debug)]
11#[command(author, version, about = "Fuelcheck CLI (CodexBar-compatible)")]
12pub struct Cli {
13    #[command(flatten)]
14    pub global: GlobalArgs,
15    #[command(subcommand)]
16    pub command: Command,
17}
18
19#[derive(Parser, Debug, Clone)]
20pub struct GlobalArgs {
21    #[arg(long, global = true)]
22    pub no_color: bool,
23    #[arg(long, global = true)]
24    pub log_level: Option<LogLevel>,
25    #[arg(long, global = true)]
26    pub json_output: bool,
27    #[arg(long, global = true)]
28    pub json_only: bool,
29    #[arg(short = 'v', long, global = true)]
30    pub verbose: bool,
31}
32
33#[derive(Subcommand, Debug)]
34pub enum Command {
35    Usage(UsageArgs),
36    Cost(CostArgs),
37    Config(ConfigCommandArgs),
38    Setup(SetupArgs),
39}
40
41#[derive(Parser, Debug, Clone)]
42pub struct UsageArgs {
43    #[arg(short, long = "provider")]
44    pub providers: Vec<ProviderSelectorArg>,
45    #[arg(long, default_value = "auto")]
46    pub source: SourcePreferenceArg,
47    #[arg(long, default_value = "text")]
48    pub format: OutputFormatArg,
49    #[arg(long)]
50    pub json: bool,
51    #[arg(long)]
52    pub pretty: bool,
53    #[arg(long)]
54    pub status: bool,
55    #[arg(long)]
56    pub no_credits: bool,
57    #[arg(long)]
58    pub refresh: bool,
59    #[arg(long)]
60    pub web_debug_dump_html: bool,
61    #[arg(long, default_value = "20")]
62    pub web_timeout: u64,
63    #[arg(long)]
64    pub config: Option<PathBuf>,
65    #[arg(long)]
66    pub account: Option<String>,
67    #[arg(long)]
68    pub account_index: Option<usize>,
69    #[arg(long)]
70    pub all_accounts: bool,
71    #[arg(long)]
72    pub antigravity_plan_debug: bool,
73    #[arg(long)]
74    pub watch: bool,
75    #[arg(long, default_value = "10")]
76    pub interval: u64,
77}
78
79#[derive(Parser, Debug, Clone)]
80pub struct CostArgs {
81    #[arg(short, long = "provider")]
82    pub providers: Vec<ProviderSelectorArg>,
83    #[arg(long, default_value = "text")]
84    pub format: OutputFormatArg,
85    #[arg(long)]
86    pub json: bool,
87    #[arg(long)]
88    pub pretty: bool,
89    #[arg(long)]
90    pub report: Option<CostReportKindArg>,
91    #[arg(long)]
92    pub since: Option<String>,
93    #[arg(long)]
94    pub until: Option<String>,
95    #[arg(long)]
96    pub timezone: Option<String>,
97    #[arg(long)]
98    pub compact: bool,
99    #[arg(long)]
100    pub config: Option<PathBuf>,
101}
102
103#[derive(Parser, Debug, Clone)]
104pub struct SetupArgs {
105    #[arg(long)]
106    pub force: bool,
107    #[arg(long)]
108    pub enable_all: bool,
109    #[arg(long)]
110    pub claude_cookie: Option<String>,
111    #[arg(long)]
112    pub cursor_cookie: Option<String>,
113    #[arg(long, alias = "droid-cookie")]
114    pub factory_cookie: Option<String>,
115    #[arg(long)]
116    pub config: Option<PathBuf>,
117}
118
119#[derive(Parser, Debug)]
120pub struct ConfigCommandArgs {
121    #[command(subcommand)]
122    pub command: ConfigCommand,
123}
124
125#[derive(Subcommand, Debug)]
126pub enum ConfigCommand {
127    Validate(ConfigArgs),
128    Dump(ConfigArgs),
129}
130
131#[derive(Parser, Debug, Clone)]
132pub struct ConfigArgs {
133    #[arg(long)]
134    pub format: Option<OutputFormatArg>,
135    #[arg(long)]
136    pub pretty: bool,
137    #[arg(long)]
138    pub config: Option<PathBuf>,
139}
140
141impl ConfigCommand {
142    pub fn format(&self) -> OutputFormat {
143        match self {
144            Self::Validate(args) => args.format.map(Into::into).unwrap_or(OutputFormat::Text),
145            Self::Dump(args) => args.format.map(Into::into).unwrap_or(OutputFormat::Json),
146        }
147    }
148
149    pub fn pretty(&self) -> bool {
150        match self {
151            Self::Validate(args) | Self::Dump(args) => args.pretty,
152        }
153    }
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
157pub enum OutputFormatArg {
158    Text,
159    Json,
160}
161
162impl From<OutputFormatArg> for OutputFormat {
163    fn from(value: OutputFormatArg) -> Self {
164        match value {
165            OutputFormatArg::Text => OutputFormat::Text,
166            OutputFormatArg::Json => OutputFormat::Json,
167        }
168    }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
172pub enum SourcePreferenceArg {
173    Auto,
174    Oauth,
175    Web,
176    Cli,
177    Api,
178    Local,
179}
180
181impl From<SourcePreferenceArg> for SourcePreference {
182    fn from(value: SourcePreferenceArg) -> Self {
183        match value {
184            SourcePreferenceArg::Auto => SourcePreference::Auto,
185            SourcePreferenceArg::Oauth => SourcePreference::Oauth,
186            SourcePreferenceArg::Web => SourcePreference::Web,
187            SourcePreferenceArg::Cli => SourcePreference::Cli,
188            SourcePreferenceArg::Api => SourcePreference::Api,
189            SourcePreferenceArg::Local => SourcePreference::Local,
190        }
191    }
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
195pub enum ProviderSelectorArg {
196    Codex,
197    Claude,
198    Gemini,
199    Cursor,
200    #[value(alias = "droid")]
201    Factory,
202    Zai,
203    MiniMax,
204    Kimi,
205    #[value(alias = "kimik2")]
206    KimiK2,
207    Copilot,
208    Kiro,
209    VertexAI,
210    JetBrains,
211    Amp,
212    Warp,
213    OpenCode,
214    All,
215    Both,
216}
217
218impl From<ProviderSelectorArg> for ProviderSelector {
219    fn from(value: ProviderSelectorArg) -> Self {
220        match value {
221            ProviderSelectorArg::Codex => ProviderSelector::Codex,
222            ProviderSelectorArg::Claude => ProviderSelector::Claude,
223            ProviderSelectorArg::Gemini => ProviderSelector::Gemini,
224            ProviderSelectorArg::Cursor => ProviderSelector::Cursor,
225            ProviderSelectorArg::Factory => ProviderSelector::Factory,
226            ProviderSelectorArg::Zai => ProviderSelector::Zai,
227            ProviderSelectorArg::MiniMax => ProviderSelector::MiniMax,
228            ProviderSelectorArg::Kimi => ProviderSelector::Kimi,
229            ProviderSelectorArg::KimiK2 => ProviderSelector::KimiK2,
230            ProviderSelectorArg::Copilot => ProviderSelector::Copilot,
231            ProviderSelectorArg::Kiro => ProviderSelector::Kiro,
232            ProviderSelectorArg::VertexAI => ProviderSelector::VertexAI,
233            ProviderSelectorArg::JetBrains => ProviderSelector::JetBrains,
234            ProviderSelectorArg::Amp => ProviderSelector::Amp,
235            ProviderSelectorArg::Warp => ProviderSelector::Warp,
236            ProviderSelectorArg::OpenCode => ProviderSelector::OpenCode,
237            ProviderSelectorArg::All => ProviderSelector::All,
238            ProviderSelectorArg::Both => ProviderSelector::Both,
239        }
240    }
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
244pub enum CostReportKindArg {
245    Daily,
246    Monthly,
247    Session,
248}
249
250impl From<CostReportKindArg> for CostReportKind {
251    fn from(value: CostReportKindArg) -> Self {
252        match value {
253            CostReportKindArg::Daily => CostReportKind::Daily,
254            CostReportKindArg::Monthly => CostReportKind::Monthly,
255            CostReportKindArg::Session => CostReportKind::Session,
256        }
257    }
258}