mirror of
https://github.com/openai/codex.git
synced 2026-05-02 10:26:45 +00:00
Fix exec inheritance of root shared flags (#18630)
Addresses #18113 Problem: Shared flags provided before the exec subcommand were parsed by the root CLI but not inherited by the exec CLI, so exec sessions could run with stale or default sandbox and model configuration. Solution: Move shared TUI and exec flags into a common option block and merge root selections into exec before dispatch, while preserving exec's global subcommand flag behavior.
This commit is contained in:
@@ -2,8 +2,10 @@ mod approval_mode_cli_arg;
|
||||
mod config_override;
|
||||
pub(crate) mod format_env_display;
|
||||
mod sandbox_mode_cli_arg;
|
||||
mod shared_options;
|
||||
|
||||
pub use approval_mode_cli_arg::ApprovalModeCliArg;
|
||||
pub use config_override::CliConfigOverrides;
|
||||
pub use format_env_display::format_env_display;
|
||||
pub use sandbox_mode_cli_arg::SandboxModeCliArg;
|
||||
pub use shared_options::SharedCliOptions;
|
||||
|
||||
174
codex-rs/utils/cli/src/shared_options.rs
Normal file
174
codex-rs/utils/cli/src/shared_options.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
//! Shared command-line flags used by both interactive and non-interactive Codex entry points.
|
||||
|
||||
use crate::SandboxModeCliArg;
|
||||
use clap::Args;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Args, Debug, Default)]
|
||||
pub struct SharedCliOptions {
|
||||
/// Optional image(s) to attach to the initial prompt.
|
||||
#[arg(
|
||||
long = "image",
|
||||
short = 'i',
|
||||
value_name = "FILE",
|
||||
value_delimiter = ',',
|
||||
num_args = 1..
|
||||
)]
|
||||
pub images: Vec<PathBuf>,
|
||||
|
||||
/// Model the agent should use.
|
||||
#[arg(long, short = 'm')]
|
||||
pub model: Option<String>,
|
||||
|
||||
/// Use open-source provider.
|
||||
#[arg(long = "oss", default_value_t = false)]
|
||||
pub oss: bool,
|
||||
|
||||
/// Specify which local provider to use (lmstudio or ollama).
|
||||
/// If not specified with --oss, will use config default or show selection.
|
||||
#[arg(long = "local-provider")]
|
||||
pub oss_provider: Option<String>,
|
||||
|
||||
/// Configuration profile from config.toml to specify default options.
|
||||
#[arg(long = "profile", short = 'p')]
|
||||
pub config_profile: Option<String>,
|
||||
|
||||
/// Select the sandbox policy to use when executing model-generated shell
|
||||
/// commands.
|
||||
#[arg(long = "sandbox", short = 's')]
|
||||
pub sandbox_mode: Option<SandboxModeCliArg>,
|
||||
|
||||
/// Convenience alias for low-friction sandboxed automatic execution.
|
||||
#[arg(long = "full-auto", default_value_t = false)]
|
||||
pub full_auto: bool,
|
||||
|
||||
/// Skip all confirmation prompts and execute commands without sandboxing.
|
||||
/// EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed.
|
||||
#[arg(
|
||||
long = "dangerously-bypass-approvals-and-sandbox",
|
||||
alias = "yolo",
|
||||
default_value_t = false,
|
||||
conflicts_with = "full_auto"
|
||||
)]
|
||||
pub dangerously_bypass_approvals_and_sandbox: bool,
|
||||
|
||||
/// Tell the agent to use the specified directory as its working root.
|
||||
#[clap(long = "cd", short = 'C', value_name = "DIR")]
|
||||
pub cwd: Option<PathBuf>,
|
||||
|
||||
/// Additional directories that should be writable alongside the primary workspace.
|
||||
#[arg(long = "add-dir", value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
|
||||
pub add_dir: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl SharedCliOptions {
|
||||
pub fn inherit_exec_root_options(&mut self, root: &Self) {
|
||||
let self_selected_sandbox_mode = self.sandbox_mode.is_some()
|
||||
|| self.full_auto
|
||||
|| self.dangerously_bypass_approvals_and_sandbox;
|
||||
let Self {
|
||||
images,
|
||||
model,
|
||||
oss,
|
||||
oss_provider,
|
||||
config_profile,
|
||||
sandbox_mode,
|
||||
full_auto,
|
||||
dangerously_bypass_approvals_and_sandbox,
|
||||
cwd,
|
||||
add_dir,
|
||||
} = self;
|
||||
let Self {
|
||||
images: root_images,
|
||||
model: root_model,
|
||||
oss: root_oss,
|
||||
oss_provider: root_oss_provider,
|
||||
config_profile: root_config_profile,
|
||||
sandbox_mode: root_sandbox_mode,
|
||||
full_auto: root_full_auto,
|
||||
dangerously_bypass_approvals_and_sandbox: root_dangerously_bypass_approvals_and_sandbox,
|
||||
cwd: root_cwd,
|
||||
add_dir: root_add_dir,
|
||||
} = root;
|
||||
|
||||
if model.is_none() {
|
||||
model.clone_from(root_model);
|
||||
}
|
||||
if *root_oss {
|
||||
*oss = true;
|
||||
}
|
||||
if oss_provider.is_none() {
|
||||
oss_provider.clone_from(root_oss_provider);
|
||||
}
|
||||
if config_profile.is_none() {
|
||||
config_profile.clone_from(root_config_profile);
|
||||
}
|
||||
if sandbox_mode.is_none() {
|
||||
*sandbox_mode = *root_sandbox_mode;
|
||||
}
|
||||
if !self_selected_sandbox_mode {
|
||||
*full_auto = *root_full_auto;
|
||||
*dangerously_bypass_approvals_and_sandbox =
|
||||
*root_dangerously_bypass_approvals_and_sandbox;
|
||||
}
|
||||
if cwd.is_none() {
|
||||
cwd.clone_from(root_cwd);
|
||||
}
|
||||
if !root_images.is_empty() {
|
||||
let mut merged_images = root_images.clone();
|
||||
merged_images.append(images);
|
||||
*images = merged_images;
|
||||
}
|
||||
if !root_add_dir.is_empty() {
|
||||
let mut merged_add_dir = root_add_dir.clone();
|
||||
merged_add_dir.append(add_dir);
|
||||
*add_dir = merged_add_dir;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_subcommand_overrides(&mut self, subcommand: Self) {
|
||||
let subcommand_selected_sandbox_mode = subcommand.sandbox_mode.is_some()
|
||||
|| subcommand.full_auto
|
||||
|| subcommand.dangerously_bypass_approvals_and_sandbox;
|
||||
let Self {
|
||||
images,
|
||||
model,
|
||||
oss,
|
||||
oss_provider,
|
||||
config_profile,
|
||||
sandbox_mode,
|
||||
full_auto,
|
||||
dangerously_bypass_approvals_and_sandbox,
|
||||
cwd,
|
||||
add_dir,
|
||||
} = subcommand;
|
||||
|
||||
if let Some(model) = model {
|
||||
self.model = Some(model);
|
||||
}
|
||||
if oss {
|
||||
self.oss = true;
|
||||
}
|
||||
if let Some(oss_provider) = oss_provider {
|
||||
self.oss_provider = Some(oss_provider);
|
||||
}
|
||||
if let Some(config_profile) = config_profile {
|
||||
self.config_profile = Some(config_profile);
|
||||
}
|
||||
if subcommand_selected_sandbox_mode {
|
||||
self.sandbox_mode = sandbox_mode;
|
||||
self.full_auto = full_auto;
|
||||
self.dangerously_bypass_approvals_and_sandbox =
|
||||
dangerously_bypass_approvals_and_sandbox;
|
||||
}
|
||||
if let Some(cwd) = cwd {
|
||||
self.cwd = Some(cwd);
|
||||
}
|
||||
if !images.is_empty() {
|
||||
self.images = images;
|
||||
}
|
||||
if !add_dir.is_empty() {
|
||||
self.add_dir.extend(add_dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user