use super::*;
#[derive(Parser, Debug)]
#[command(
name = "prodex",
version,
about = "Manage multiple Codex profiles backed by isolated CODEX_HOME directories.",
after_help = CLI_TOP_LEVEL_AFTER_HELP
)]
pub(crate) struct Cli {
#[command(subcommand)]
pub(crate) command: Commands,
}
#[derive(Subcommand, Debug)]
pub(crate) enum Commands {
#[command(
subcommand,
about = "Add, inspect, remove, and activate managed profiles.",
after_help = CLI_PROFILE_AFTER_HELP
)]
Profile(ProfileCommands),
#[command(
name = "use",
about = "Set the active profile used by commands that omit --profile."
)]
UseProfile(ProfileSelector),
#[command(about = "Show the active profile and its CODEX_HOME details.")]
Current,
#[command(
name = "info",
about = "Summarize version status, running processes, quota pool, and runway."
)]
Info(InfoArgs),
#[command(
about = "Inspect local state, Codex resolution, quota readiness, and runtime logs.",
after_help = CLI_DOCTOR_AFTER_HELP
)]
Doctor(DoctorArgs),
#[command(
about = "Inspect structured enterprise audit events written to /tmp.",
after_help = CLI_AUDIT_AFTER_HELP
)]
Audit(AuditArgs),
#[command(
about = "Remove stale local runtime logs, temp homes, dead broker artifacts, and orphaned managed homes.",
after_help = CLI_CLEANUP_AFTER_HELP
)]
Cleanup,
#[command(
trailing_var_arg = true,
about = "Run codex login inside a selected or auto-created profile.",
after_help = CLI_LOGIN_AFTER_HELP
)]
Login(CodexPassthroughArgs),
#[command(about = "Run codex logout for the selected or active profile.")]
Logout(LogoutArgs),
#[command(
about = "Inspect live quota for one profile or the whole profile pool.",
after_help = CLI_QUOTA_AFTER_HELP
)]
Quota(QuotaArgs),
#[command(
trailing_var_arg = true,
about = "Run codex through prodex with quota preflight and safe auto-rotate.",
after_help = CLI_RUN_AFTER_HELP
)]
Run(RunArgs),
#[command(
trailing_var_arg = true,
about = "Run codex through prodex with the Caveman plugin active in a temporary overlay home.",
after_help = CLI_CAVEMAN_AFTER_HELP
)]
Caveman(CavemanArgs),
#[command(
trailing_var_arg = true,
about = "Run Claude Code through prodex via an Anthropic-compatible runtime proxy.",
after_help = CLI_CLAUDE_AFTER_HELP
)]
Claude(ClaudeArgs),
#[command(name = "__runtime-broker", hide = true)]
RuntimeBroker(RuntimeBrokerArgs),
}
#[derive(Subcommand, Debug)]
pub(crate) enum ProfileCommands {
Add(AddProfileArgs),
Export(ExportProfileArgs),
Import(ImportProfileArgs),
ImportCurrent(ImportCurrentArgs),
List,
Remove(RemoveProfileArgs),
Use(ProfileSelector),
}
#[derive(Args, Debug)]
pub(crate) struct AddProfileArgs {
pub(crate) name: String,
#[arg(long, value_name = "PATH")]
pub(crate) codex_home: Option<PathBuf>,
#[arg(long, value_name = "PATH")]
pub(crate) copy_from: Option<PathBuf>,
#[arg(long)]
pub(crate) copy_current: bool,
#[arg(long)]
pub(crate) activate: bool,
}
#[derive(Args, Debug)]
pub(crate) struct ExportProfileArgs {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Vec<String>,
#[arg(value_name = "PATH")]
pub(crate) output: Option<PathBuf>,
#[arg(long, conflicts_with = "no_password")]
pub(crate) password_protect: bool,
#[arg(long)]
pub(crate) no_password: bool,
}
#[derive(Args, Debug)]
pub(crate) struct ImportProfileArgs {
#[arg(value_name = "PATH")]
pub(crate) path: PathBuf,
}
#[derive(Args, Debug)]
pub(crate) struct ImportCurrentArgs {
#[arg(default_value = "default")]
pub(crate) name: String,
}
#[derive(Args, Debug)]
pub(crate) struct RemoveProfileArgs {
#[arg(
value_name = "NAME",
required_unless_present = "all",
conflicts_with = "all"
)]
pub(crate) name: Option<String>,
#[arg(long, conflicts_with = "name")]
pub(crate) all: bool,
#[arg(long)]
pub(crate) delete_home: bool,
}
#[derive(Args, Debug, Clone)]
pub(crate) struct ProfileSelector {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
}
#[derive(Args, Debug, Clone)]
pub(crate) struct LogoutArgs {
#[arg(value_name = "NAME", conflicts_with = "profile")]
pub(crate) profile_name: Option<String>,
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
}
impl LogoutArgs {
pub(crate) fn selected_profile(&self) -> Option<&str> {
self.profile.as_deref().or(self.profile_name.as_deref())
}
}
#[derive(Args, Debug)]
pub(crate) struct CodexPassthroughArgs {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
#[arg(value_name = "CODEX_ARG", allow_hyphen_values = true)]
pub(crate) codex_args: Vec<OsString>,
}
#[derive(Args, Debug)]
pub(crate) struct QuotaArgs {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
#[arg(long)]
pub(crate) all: bool,
#[arg(long)]
pub(crate) detail: bool,
#[arg(long)]
pub(crate) raw: bool,
#[arg(long, hide = true)]
pub(crate) watch: bool,
#[arg(long, conflicts_with = "watch")]
pub(crate) once: bool,
#[arg(long, value_name = "URL")]
pub(crate) base_url: Option<String>,
}
#[derive(Args, Debug, Default)]
pub(crate) struct InfoArgs {}
#[derive(Args, Debug)]
pub(crate) struct DoctorArgs {
#[arg(long)]
pub(crate) quota: bool,
#[arg(long)]
pub(crate) runtime: bool,
#[arg(long)]
pub(crate) json: bool,
}
#[derive(Args, Debug)]
pub(crate) struct AuditArgs {
#[arg(long, default_value_t = 50, value_name = "COUNT")]
pub(crate) tail: usize,
#[arg(long)]
pub(crate) json: bool,
#[arg(long, value_name = "NAME")]
pub(crate) component: Option<String>,
#[arg(long, value_name = "NAME")]
pub(crate) action: Option<String>,
#[arg(long, value_name = "NAME")]
pub(crate) outcome: Option<String>,
}
#[derive(Args, Debug)]
pub(crate) struct RunArgs {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
#[arg(long, conflicts_with = "no_auto_rotate")]
pub(crate) auto_rotate: bool,
#[arg(long)]
pub(crate) no_auto_rotate: bool,
#[arg(long)]
pub(crate) skip_quota_check: bool,
#[arg(long, value_name = "URL")]
pub(crate) base_url: Option<String>,
#[arg(value_name = "CODEX_ARG", allow_hyphen_values = true)]
pub(crate) codex_args: Vec<OsString>,
}
#[derive(Args, Debug)]
pub(crate) struct ClaudeArgs {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
#[arg(long, conflicts_with = "no_auto_rotate")]
pub(crate) auto_rotate: bool,
#[arg(long)]
pub(crate) no_auto_rotate: bool,
#[arg(long)]
pub(crate) skip_quota_check: bool,
#[arg(long, value_name = "URL")]
pub(crate) base_url: Option<String>,
#[arg(value_name = "CLAUDE_ARG", allow_hyphen_values = true)]
pub(crate) claude_args: Vec<OsString>,
}
#[derive(Args, Debug)]
pub(crate) struct CavemanArgs {
#[arg(short, long, value_name = "NAME")]
pub(crate) profile: Option<String>,
#[arg(long, conflicts_with = "no_auto_rotate")]
pub(crate) auto_rotate: bool,
#[arg(long)]
pub(crate) no_auto_rotate: bool,
#[arg(long)]
pub(crate) skip_quota_check: bool,
#[arg(long, value_name = "URL")]
pub(crate) base_url: Option<String>,
#[arg(value_name = "CODEX_ARG", allow_hyphen_values = true)]
pub(crate) codex_args: Vec<OsString>,
}
#[derive(Args, Debug)]
pub(crate) struct RuntimeBrokerArgs {
#[arg(long)]
pub(crate) current_profile: String,
#[arg(long)]
pub(crate) upstream_base_url: String,
#[arg(long, default_value_t = false)]
pub(crate) include_code_review: bool,
#[arg(long)]
pub(crate) broker_key: String,
#[arg(long)]
pub(crate) instance_token: String,
#[arg(long)]
pub(crate) admin_token: String,
#[arg(long)]
pub(crate) listen_addr: Option<String>,
}