kinda wanna structure my plan out
This commit is contained in:
6 files changed
+241
-18
No files matched your search
@@ -6,11 +6,17 @@ csa show <acc> -> verbose account <acc>
|
||||
csa swap -- codex resume -> csa swap auth to the best account, then execvpe
|
||||
csa swap <acc> -- codex logout -> csa swap to that acount, then execvpe
|
||||
|
||||
optional features
|
||||
// important feature
|
||||
csa refresh (--all --expired OR <acc name>)
|
||||
|
||||
csa login
|
||||
csa logout
|
||||
csa refresh
|
||||
// account:
|
||||
csa account show (--all, --expired, <name>) default current
|
||||
csa account rename
|
||||
csa accound add
|
||||
csa account refresh
|
||||
|
||||
csa login <account>
|
||||
csa logout <account> --DO NOT Support --all, DO support --expired ONLY with confirmation
|
||||
|
||||
logout and refresh have official bindings in codex-login (logout with revoke, refresh_token)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
//! this deals with authentication. validate, refresh, and quota check.
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
#[derive(clap::Parser, Debug)]
|
||||
#[clap(
|
||||
name = "csa",
|
||||
version,
|
||||
about = "A CLI tool to manage multiple Codex accounts"
|
||||
)]
|
||||
pub struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand, Debug)]
|
||||
pub enum Commands {
|
||||
Show(ShowCommand),
|
||||
Add(AddCommand),
|
||||
Swap(SwapCommand),
|
||||
Account(AccountCommand),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, clap::Parser)]
|
||||
pub struct ShowCommand {
|
||||
/// specify to show the account.
|
||||
pub acc: Option<String>,
|
||||
}
|
||||
|
||||
/// `csa add --use --name myacc` or `csa add myacc --use` would add an account with nickname "myacc" and switch to it right away.
|
||||
#[derive(Clone, Debug, clap::Parser)]
|
||||
pub struct AddCommand {
|
||||
/// use the account right away after adding, instead of just adding to the store.
|
||||
#[clap(long = "use", short = 'u')]
|
||||
use_rn: bool,
|
||||
/// use to specify a nickname for the account. If not specified, will be the email or something else identifiable.
|
||||
/// highly recommend.
|
||||
pub name: Option<String>,
|
||||
}
|
||||
/// `csa swap acc1` would swap to acc1 if it exists. Else error out. `csa swap` would swap to the most capable account, which is determined by the internal logic of csa, and is usually the best valid account with the best availability.
|
||||
///
|
||||
/// to use something right after add/swap, use your favourite shell feature, the semicolon `;`.
|
||||
// that looks like an emoji yo (`;`) wth
|
||||
#[derive(Clone, Debug, clap::Parser)]
|
||||
pub struct SwapCommand {
|
||||
/// specify to swap to the account, instead of best effort swap to the most capable account.
|
||||
pub acc: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, clap::Parser)]
|
||||
pub struct AccountCommand {
|
||||
#[clap(subcommand)]
|
||||
subcommand: AccountSubCommand,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, clap::Subcommand)]
|
||||
pub enum AccountSubCommand {
|
||||
Refresh {
|
||||
/// specify to refresh the account. Else refresh all accounts.
|
||||
// this and AccountCommand.account at the same time is an error.
|
||||
// chat how do i enforce above rule?
|
||||
acc: Option<String>,
|
||||
/// specify to only refresh the account if it's expired. Else refresh anyway.
|
||||
expired: bool,
|
||||
},
|
||||
// also logout
|
||||
Remove {
|
||||
/// specify to remove the account
|
||||
// do NOT support remove all accounts.
|
||||
acc: String,
|
||||
},
|
||||
Rename {
|
||||
/// specify to rename the account
|
||||
acc: String,
|
||||
/// the new name for the account
|
||||
new_name: String,
|
||||
},
|
||||
// same thing as Show above
|
||||
Show {
|
||||
/// specify to show the account. Else show all accounts.
|
||||
acc: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use clap::Parser;
|
||||
#[test]
|
||||
fn show() {
|
||||
let cli = Cli::try_parse_from(["test", "show"]).expect("csa show");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
#[test]
|
||||
fn show_me() {
|
||||
let cli = Cli::try_parse_from(["test", "show", "me"]).expect("csa show me");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Show(ShowCommand { acc: Some(acc) }) if acc == "me")
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn add() {
|
||||
let cli = Cli::try_parse_from(["test", "add"]).expect("csa add");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
#[test]
|
||||
fn add_use() {
|
||||
let cli = Cli::try_parse_from(["test", "add", "--use"]).expect("csa add --use");
|
||||
println!("{cli:#?}");
|
||||
assert!(matches!(
|
||||
cli.command,
|
||||
Commands::Add(AddCommand {
|
||||
use_rn: true,
|
||||
name: None,
|
||||
})
|
||||
));
|
||||
}
|
||||
#[test]
|
||||
fn add_use_name() {
|
||||
let cli = Cli::try_parse_from(["test", "add", "--use", "--name", "myacc"])
|
||||
.expect("csa add --use --name myacc");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Add(AddCommand { use_rn: true, name: Some(name) }) if name == "myacc")
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn add_name() {
|
||||
let cli =
|
||||
Cli::try_parse_from(["test", "add", "--name", "myacc"]).expect("csa add --name myacc");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Add(AddCommand { use_rn: false, name: Some(name) }) if name == "myacc")
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn swap() {
|
||||
let cli = Cli::try_parse_from(["test", "swap"]).expect("csa swap");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_acc() {
|
||||
let cli = Cli::try_parse_from(["test", "swap", "acc1"]).expect("csa swap acc1");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Swap(SwapCommand { acc: Some(acc) }) if acc == "acc1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refresh() {
|
||||
let cli = Cli::try_parse_from(["test", "refresh"]).expect("csa refresh");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refresh_acc() {
|
||||
let cli = Cli::try_parse_from(["test", "refresh", "--acc", "acc1"])
|
||||
.expect("csa refresh --acc acc1");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Account(AccountCommand { subcommand: AccountSubCommand::Refresh { acc: Some(acc), expired }, .. }) if acc == "acc1" && !expired)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn refresh_acc_expired() {
|
||||
let cli = Cli::try_parse_from(["test", "refresh", "--acc", "acc1", "--expired"])
|
||||
.expect("csa refresh --acc acc1 --expired");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Account(AccountCommand { subcommand: AccountSubCommand::Refresh { acc: Some(acc), expired }, .. }) if acc == "acc1" && expired)
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn refresh_expired() {
|
||||
let cli =
|
||||
Cli::try_parse_from(["test", "refresh", "--expired"]).expect("csa refresh --expired");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Account(AccountCommand { subcommand: AccountSubCommand::Refresh { acc: None, expired }, .. }) if expired)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove() {
|
||||
let cli = Cli::try_parse_from(["test", "remove", "--acc", "acc1"])
|
||||
.expect("csa remove --acc acc1");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Account(AccountCommand { subcommand: AccountSubCommand::Remove { acc }, .. }) if acc == "acc1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn remove_no_acc() {
|
||||
let cli = Cli::try_parse_from(["test", "remove"]).expect("csa remove");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename() {
|
||||
let cli = Cli::try_parse_from(["test", "rename", "acc1", "acc_new"])
|
||||
.expect("csa rename acc1 acc_new");
|
||||
println!("{cli:#?}");
|
||||
assert!(
|
||||
matches!(cli.command, Commands::Account(AccountCommand { subcommand: AccountSubCommand::Rename { acc, new_name }, .. }) if acc == "acc1" && new_name == "acc_new")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn rename_no_args() {
|
||||
let cli = Cli::try_parse_from(["test", "rename"]).expect("csa rename");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn rename_no_new_name() {
|
||||
let cli = Cli::try_parse_from(["test", "rename", "acc1"]).expect("csa rename acc1");
|
||||
println!("{cli:#?}");
|
||||
}
|
||||
}
|
||||
+4
-14
@@ -1,14 +1,4 @@
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
pub mod cli;
|
||||
pub mod store;
|
||||
pub mod util;
|
||||
pub mod auth;
|
||||
@@ -0,0 +1,3 @@
|
||||
//! deals with storage of accounts.
|
||||
//! updates, pull out, standard crud... all here.
|
||||
//! 0 logic to do with the actual accounts, just storage and retrieval.
|
||||
@@ -0,0 +1 @@
|
||||
//! whatever looks like an general utility goes here.
|
||||
Reference in new issue
Block a user