use super::{AppError, AppResult, CliArgs, CliCommand, SessionsCommand};
use std::io::{self, IsTerminal};
fn usage_error(message: impl Into<String>) -> AppError {
AppError::usage(anyhow::anyhow!(message.into()))
}
pub(super) fn validate_update_launch(args: &CliArgs) -> AppResult<()> {
if args.command.is_some()
|| args.initial_prompt.is_some()
|| args.provider.is_some()
|| args.model.is_some()
|| args.api_key.is_some()
|| args.theme.is_some()
|| args.no_session
|| args.continue_session
|| args.resume.is_some()
|| args.update_restart
{
return Err(usage_error("--update must be used alone"));
}
Ok(())
}
pub(super) fn validate_subcommand_launch(args: &CliArgs) -> AppResult<()> {
if args.update_restart {
return Err(usage_error(
"subcommands cannot be combined with --update-restart",
));
}
if args.initial_prompt.is_some() {
return Err(usage_error(
"subcommands cannot be combined with --prompt; use one mode per invocation",
));
}
if args.theme.is_some() {
return Err(usage_error(
"subcommands cannot be combined with --theme; appearance is only used by normal startup",
));
}
if args.continue_session {
return Err(usage_error(
"subcommands cannot be combined with --continue; diagnostics do not attach to sessions",
));
}
if args.resume.is_some() {
return Err(usage_error(
"subcommands cannot be combined with --resume; diagnostics do not attach to sessions",
));
}
if args.no_session {
return Err(usage_error(
"subcommands cannot be combined with --no-session; diagnostics never create sessions",
));
}
if args.provider.is_some() {
return Err(usage_error(
"subcommands cannot be combined with --provider; diagnostics do not use provider auth",
));
}
if args.model.is_some() {
return Err(usage_error(
"subcommands cannot be combined with --model; diagnostics do not use provider models",
));
}
if args.api_key.is_some() {
return Err(usage_error(
"subcommands cannot be combined with --api-key; diagnostics do not authenticate",
));
}
if let Some(CliCommand::Sessions {
command:
SessionsCommand::MeasureCompression {
model,
max_files,
max_bytes,
},
}) = args.command.as_ref()
{
if !crate::tool_output_measurement::is_valid_measurement_model(model) {
return Err(usage_error(
"measure-compression --model must name a supported openai-codex text model",
));
}
if !crate::tool_output_measurement::MeasurementLimits::is_valid_file_count(*max_files) {
return Err(usage_error(
"measure-compression --max-files must be between 1 and 10000",
));
}
if !crate::tool_output_measurement::MeasurementLimits::is_valid_byte_limit(*max_bytes) {
return Err(usage_error(
"measure-compression --max-bytes must be between 1048576 and 1073741824",
));
}
}
Ok(())
}
pub(super) fn validate_session_launch(args: &CliArgs) -> AppResult<()> {
if args.no_session && (args.continue_session || args.resume.is_some()) {
return Err(usage_error(
"--no-session cannot be combined with --continue or --resume",
));
}
if args.continue_session && args.resume.is_some() {
return Err(usage_error(
"--continue cannot be combined with --resume; choose one session target",
));
}
Ok(())
}
pub(super) fn validate_initial_prompt_launch(args: &CliArgs) -> AppResult<()> {
if args
.initial_prompt
.as_deref()
.is_some_and(|prompt| prompt.trim().is_empty())
{
return Err(usage_error("--prompt requires non-whitespace text"));
}
Ok(())
}
pub(super) fn validate_tui_launch() -> AppResult<()> {
let stdin_is_tty = io::stdin().is_terminal();
let stdout_is_tty = io::stdout().is_terminal();
if !stdin_is_tty || !stdout_is_tty {
return Err(usage_error(
"Mission Control requires both stdin and stdout to be TTYs",
));
}
Ok(())
}