Appearance
CLI 调度器 — 代码走读
codex-rs/cli/src/main.rs — CLI 主入口(~3773 行)
程序入口与 argv[0] 多工具分发
Codex CLI 部署为单个二进制文件,但需要暴露多个工具入口(codex-linux-sandbox、apply_patch、codex-execve-wrapper)。arg0_dispatch 通过检查 argv[0](即程序被调用时的文件名)来实现多工具分发:
rust
fn main() -> anyhow::Result<()> {
arg0_dispatch_or_else(|arg0_paths: Arg0DispatchPaths| async move {
cli_main(arg0_paths).await?;
Ok(())
})
}arg0_dispatch() 内部分发逻辑:
- 提取
argv[0]的file_name()部分 - Unix 特殊路径:若
exe_name == "codex-execve-wrapper",在单线程 tokio 运行时上运行 shell 提权包装器 - 若
exe_name == "codex-linux-sandbox",调用codex_linux_sandbox::run_main()(不会返回) - 若
exe_name == "apply_patch"或"applypatch",调用codex_apply_patch::main() - 检查
argv[1]是否等于CODEX_FS_HELPER_ARG1或CODEX_CORE_APPLY_PATCH_ARG1,分发到对应的辅助入口
PATH 环境变量准备:prepare_path_env_var_with_aliases() 在 ~/.codex/tmp/arg0/ 下创建临时目录,其中包含指向当前可执行文件的符号链接(apply_patch、codex-linux-sandbox、codex-execve-wrapper),并将此目录添加到 PATH 前面。临时目录内的 .lock 文件防止清理器误删正在使用的目录。
arg0_dispatch_or_else 包装器会:
- 在名为
"codex-main"的线程上启动,栈大小为 16 MB - 构建同样使用 16 MB 栈大小的多线程 tokio 运行时
- 构造
Arg0DispatchPaths并保持临时目录存活直到异步 main 完成
rust
pub struct Arg0DispatchPaths {
pub codex_self_exe: Option<PathBuf>,
pub codex_linux_sandbox_exe: Option<PathBuf>,
pub main_execve_wrapper_exe: Option<PathBuf>,
}MultitoolCli — 顶层 CLI 定义
rust
#[derive(Debug, Parser)]
#[clap(
author, version,
subcommand_negates_reqs = true,
bin_name = "codex",
override_usage = "codex [OPTIONS] [PROMPT]\n codex [OPTIONS] <COMMAND> [ARGS]"
)]
struct MultitoolCli {
#[clap(flatten)] pub config_overrides: CliConfigOverrides,
#[clap(flatten)] pub feature_toggles: FeatureToggles,
#[clap(flatten)] remote: InteractiveRemoteOptions,
#[clap(flatten)] interactive: TuiCli,
#[clap(subcommand)] subcommand: Option<Subcommand>,
}cli_main() — 子命令路由器
核心分发逻辑:
rust
async fn cli_main(arg0_paths: Arg0DispatchPaths) -> Result<()> {
let cli = MultitoolCli::parse();
let config_overrides = cli.fold_config_overrides();
match cli.subcommand {
Some(Subcommand::Exec(args)) => exec::run_main(args, paths),
Some(Subcommand::AppServer(args)) => app_server::run_main(args, paths),
Some(Subcommand::Login) => login_flow(),
Some(Subcommand::Logout) => logout_flow(),
Some(Subcommand::Review(args)) => review_main(args),
Some(Subcommand::Mcp(args)) => mcp_main(args),
Some(Subcommand::McpServer(args)) => mcp_server_main(args),
Some(Subcommand::Resume(args)) => resume_main(args),
Some(Subcommand::Archive(args)) => archive_main(args),
Some(Subcommand::Doctor) => doctor_main(),
Some(Subcommand::Sandbox(args)) => sandbox_main(args),
Some(Subcommand::Apply(args)) => apply_main(args),
Some(Subcommand::Execpolicy(args)) => execpolicy_main(args),
// ... 更多子命令
None => run_interactive_tui(cli),
}
}关键子命令处理模式:
- 无子命令(交互 TUI):调用
run_interactive_tui()启动 TUI,支持可选的远程端点 Exec:继承根级共享选项,调用codex_exec::run_main()Review:内部重新解析为codex exec并设置Review命令变体——review是exec的薄包装Resume/Fork:合并根级和 resume/fork 范围的标志,然后运行交互 TUISandbox:使用条件编译(#[cfg(target_os = ...)])分发到平台特定沙箱
fold_config_overrides — 配置覆盖合并
FeatureToggles 将 --enable/--disable 标志转换为 features.<name>=true/false 格式,然后合并到 CliConfigOverrides.raw_overrides:
rust
#[derive(Debug, Default, Parser, Clone)]
struct FeatureToggles {
#[arg(long = "enable", action = clap::ArgAction::Append, global = true)]
enable: Vec<String>,
#[arg(long = "disable", action = clap::ArgAction::Append, global = true)]
disable: Vec<String>,
}
impl FeatureToggles {
fn to_overrides(&self) -> Vec<String> {
// 验证每个 feature 名称是否已知
// 生成如 "features.unified_exec=true" 的字符串
}
}CliConfigOverrides 的 -c key=value 机制:
rust
pub struct CliConfigOverrides {
#[arg(short = 'c', long = "config", action = ArgAction::Append, global = true)]
pub raw_overrides: Vec<String>,
}TOML 解析技巧:将值包装为 _x_ = {value} 再解析为 TOML 文档,提取 _x_ 键。这允许用户写 -c model=o3 而无需引号(裸字符串不是合法 TOML,解析失败后回退为原始字符串)。
优先级控制:prepend_root_overrides 将根级标志插入到子命令标志之前,确保子命令标志具有更高优先级。
Subcommand 枚举 — 全部 CLI 子命令
rust
enum Subcommand {
Exec(ExecCli), // 别名: "e"
Review(ReviewCommand),
Login(LoginCommand),
Logout(LogoutCommand),
Mcp(McpCli),
Plugin(PluginCli),
McpServer(McpServerCommand),
AppServer(AppServerCommand),
RemoteControl(RemoteControlCommand),
Completion(CompletionCommand),
Update,
Doctor(DoctorCommand),
Sandbox(HostSandboxArgs),
Debug(DebugCommand),
Execpolicy(ExecpolicyCommand), // 隐藏
Apply(ApplyCommand), // 别名: "a"
Resume(ResumeCommand),
Archive(SessionArchiveCommand),
Unarchive(SessionArchiveCommand),
Fork(ForkCommand),
Cloud(CloudTasksCli),
// ... 以及多个隐藏子命令
}codex-rs/cli/src/lib.rs — 平台特定沙箱命令
lib.rs 为三个平台定义了平行的沙箱命令结构体:
rust
#[cfg(target_os = "macos")] type HostSandboxArgs = codex_cli::SeatbeltCommand;
#[cfg(target_os = "linux")] type HostSandboxArgs = codex_cli::LandlockCommand;
#[cfg(target_os = "windows")] type HostSandboxArgs = codex_cli::WindowsCommand;每个结构体包含 permissions_profile、config_profile、cwd、include_managed_config 和 command: Vec<String>。macOS 变体额外支持 allow_unix_sockets 和 log_denials。
Feature 注册表(codex-rs/features/src/lib.rs)
Feature 枚举有 60+ 个变体,每个通过 FeatureSpec 注册:
rust
pub struct FeatureSpec {
pub id: Feature,
pub key: &'static str,
pub stage: Stage, // UnderDevelopment | Experimental | Stable | Deprecated | Removed
pub default_enabled: bool,
}特性标志的生命周期阶段:UnderDevelopment → Experimental → Stable → Deprecated → Removed。Removed 阶段的标志保留为空操作,确保配置向后兼容。
Features::from_sources() 按层级构建有效特性集:默认值 → 基础配置 → profile 配置 → CLI 覆盖 → 依赖归一化。
关键函数索引
| 函数/模块 | 文件路径 | 说明 |
|---|---|---|
main() | cli/src/main.rs | 程序入口,触发 arg0 分发 |
arg0_dispatch_or_else() | arg0/src/lib.rs | argv[0] 多工具分发 + tokio 运行时构建 |
cli_main() | cli/src/main.rs | CLI 主逻辑,子命令分发 |
run_interactive_tui() | cli/src/main.rs | 启动 TUI 模式,含 SQLite 状态修复循环 |
fold_config_overrides() | cli/src/main.rs | 合并特性开关到配置覆盖 |
FeatureToggles.to_overrides() | cli/src/main.rs | 将 --enable/--disable 转为配置字符串 |
CliConfigOverrides | utils/cli/src/config_override.rs | -c key=value 配置覆盖机制 |
parse_overrides() | utils/cli/src/config_override.rs | TOML 值解析 + 回退 |
prepend_root_overrides() | utils/cli/src/config_override.rs | 根级覆盖优先级控制 |
MultitoolCli | cli/src/main.rs | clap Parser 顶层定义 |
Subcommand | cli/src/main.rs | 25+ 子命令枚举 |
FeatureSpec | features/src/lib.rs | 特性标志规格定义 |
Features::from_sources() | features/src/lib.rs | 分层特性集构建 |
Arg0DispatchPaths | arg0/src/lib.rs | 二进制路径信息 |
SharedCliOptions | utils/cli/src/shared_options.rs | 共享 CLI 选项(model, sandbox, cwd 等) |