Codex Handbook
app-server/src/main.rs 139 lines
use clap::Parser;use codex_app_server::AppServerRuntimeOptions;use codex_app_server::AppServerTransport;use codex_app_server::AppServerWebsocketAuthArgs;use codex_app_server::PluginStartupTasks;use codex_app_server::run_main_with_transport_options;use codex_arg0::Arg0DispatchPaths;use codex_arg0::arg0_dispatch_or_else;use codex_config::LoaderOverrides;use codex_protocol::protocol::SessionSource;use codex_utils_cli::CliConfigOverrides;use std::path::PathBuf;// Debug-only test hook: lets integration tests point the server at a temporary// managed config file without writing to /etc.const MANAGED_CONFIG_PATH_ENV_VAR: &str = "CODEX_APP_SERVER_MANAGED_CONFIG_PATH";const DISABLE_MANAGED_CONFIG_ENV_VAR: &str = "CODEX_APP_SERVER_DISABLE_MANAGED_CONFIG";#[derive(Debug, Parser)]#[command(version)]struct AppServerArgs {    #[command(flatten)]    config_overrides: CliConfigOverrides,    /// Transport endpoint URL. Supported values: `stdio://` (default),    /// `unix://`, `unix://PATH`, `ws://IP:PORT`, `off`.    #[arg(        long = "listen",        value_name = "URL",        default_value = AppServerTransport::DEFAULT_LISTEN_URL    )]    listen: AppServerTransport,    /// Session source used to derive product restrictions and metadata.    #[arg(        long = "session-source",        value_name = "SOURCE",        default_value = "vscode",        value_parser = SessionSource::from_startup_arg    )]    session_source: SessionSource,    #[command(flatten)]    auth: AppServerWebsocketAuthArgs,    /// Fail if config.toml contains unknown configuration fields.    #[arg(long = "strict-config", default_value_t = false)]    strict_config: bool,    /// Hidden debug-only test hook used by integration tests that spawn the    /// production app-server binary.    #[cfg(debug_assertions)]    #[arg(long = "disable-plugin-startup-tasks-for-tests", hide = true)]    disable_plugin_startup_tasks_for_tests: bool,    /// Enable remote control for this app-server process without changing persistence.    #[arg(long = "remote-control", hide = true)]    remote_control: bool,}fn main() -> anyhow::Result<()> {    let remote_control_disabled = codex_app_server::take_remote_control_disabled_env();    arg0_dispatch_or_else(move |arg0_paths: Arg0DispatchPaths| async move {        let AppServerArgs {            config_overrides,            listen,            session_source,            auth,            strict_config,            #[cfg(debug_assertions)]            disable_plugin_startup_tasks_for_tests,            remote_control,        } = AppServerArgs::parse();        let loader_overrides = if disable_managed_config_from_debug_env() {            LoaderOverrides::without_managed_config_for_tests()        } else {            managed_config_path_from_debug_env()                .map(LoaderOverrides::with_managed_config_path_for_tests)                .unwrap_or_default()        };        let transport = listen;        let auth = auth.try_into_settings()?;        let mut runtime_options = AppServerRuntimeOptions::default();        #[cfg(debug_assertions)]        if disable_plugin_startup_tasks_for_tests {            runtime_options.plugin_startup_tasks = PluginStartupTasks::Skip;        }        runtime_options.remote_control_startup_mode =            match (remote_control, remote_control_disabled) {                (true, _) => codex_app_server::RemoteControlStartupMode::EnabledEphemeral,                (false, true) => codex_app_server::RemoteControlStartupMode::DisabledEphemeral,                (false, false) => codex_app_server::RemoteControlStartupMode::ResolvePersisted,            };        run_main_with_transport_options(            arg0_paths,            config_overrides,            loader_overrides,            strict_config,            /*default_analytics_enabled*/ false,            transport,            session_source,            auth,            runtime_options,        )        .await?;        Ok(())    })}fn disable_managed_config_from_debug_env() -> bool {    #[cfg(debug_assertions)]    {        if let Ok(value) = std::env::var(DISABLE_MANAGED_CONFIG_ENV_VAR) {            return matches!(value.as_str(), "1" | "true" | "TRUE" | "yes" | "YES");        }    }    false}fn managed_config_path_from_debug_env() -> Option<PathBuf> {    #[cfg(debug_assertions)]    {        if let Ok(value) = std::env::var(MANAGED_CONFIG_PATH_ENV_VAR) {            return if value.is_empty() {                None            } else {                Some(PathBuf::from(value))            };        }    }    None}#[cfg(test)]#[path = "main_tests.rs"]mod tests;