File size: 5,572 Bytes
afa0cbf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | #![recursion_limit = "256"]
use clap::Parser;
use codex_app_server::AppServerCodeModeHostArgs;
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;
#[cfg(all(
target_os = "linux",
target_env = "musl",
any(target_arch = "x86_64", target_arch = "aarch64")
))]
#[global_allocator]
static ALLOCATOR: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
// 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,
#[command(flatten)]
code_mode_host: AppServerCodeModeHostArgs,
/// 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,
/// Save loaded threads during managed daemon shutdown.
#[arg(long, hide = true)]
managed_daemon: 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,
code_mode_host,
listen,
session_source,
auth,
strict_config,
#[cfg(debug_assertions)]
disable_plugin_startup_tasks_for_tests,
remote_control,
managed_daemon,
} = 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 {
code_mode_host_transport: code_mode_host.into(),
managed_daemon,
..Default::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,
};
let exit = run_main_with_transport_options(
arg0_paths,
config_overrides,
loader_overrides,
strict_config,
/*default_analytics_enabled*/ false,
transport,
session_source,
auth,
runtime_options,
)
.await?;
if exit == codex_app_server::AppServerExit::Forced {
// Runtime teardown can wait forever for blocked rollout I/O.
std::process::exit(0);
}
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;
|