enable/disable remote control at runtime, not via features (#22578)

## Why
reapplies https://github.com/openai/codex/pull/22386 which was
previously reverted

Also, introduce `remoteControl/enable` and `remoteControl/disable`
app-server APIs to toggle on/off remote control at runtime for a given
running app-server instance.

## What Changed

- Adds experimental v2 RPCs:
  - `remoteControl/enable`
  - `remoteControl/disable`
- Adds `RemoteControlRequestProcessor` and routes the new RPCs through
it instead of `ConfigRequestProcessor`.
- Adds named `RemoteControlHandle::enable`, `disable`, and `status`
methods.
- Makes `remoteControl/enable` return an error when sqlite state DB is
unavailable, while keeping enrollment/websocket failures as async status
updates.
- Adds `AppServerRuntimeOptions.remote_control_enabled` and hidden
`--remote-control` flags for `codex app-server` and `codex-app-server`.
- Updates managed daemon startup to use `codex app-server
--remote-control --listen unix://`.
- Marks `Feature::RemoteControl` as removed and ignores
`[features].remote_control`.
- Updates app-server README entries for the new remote-control methods.
This commit is contained in:
Owen Lin
2026-05-13 18:07:46 -07:00
committed by GitHub
parent 512f8f8012
commit 4e368aa2e9
22 changed files with 346 additions and 52 deletions

View File

@@ -454,6 +454,10 @@ struct AppServerCommand {
)]
listen: codex_app_server::AppServerTransport,
/// Enable remote control for this app-server process.
#[arg(long = "remote-control", hide = true)]
remote_control: bool,
/// Controls whether analytics are enabled by default.
///
/// Analytics are disabled by default for app-server. Users have to explicitly opt in
@@ -532,10 +536,10 @@ enum AppServerDaemonSubcommand {
/// Restart the local app server daemon.
Restart,
/// Enable remote_control for future starts and a currently running managed daemon.
/// Enable remote control for future starts and a currently running managed daemon.
EnableRemoteControl,
/// Disable remote_control for future starts and a currently running managed daemon.
/// Disable remote control for future starts and a currently running managed daemon.
DisableRemoteControl,
/// Stop the local app server daemon.
@@ -558,7 +562,7 @@ struct AppServerProxyCommand {
#[derive(Debug, Args)]
struct AppServerBootstrapCommand {
/// Launch the managed app-server with remote_control enabled.
/// Launch the managed app-server with remote control enabled.
#[arg(long = "remote-control")]
remote_control: bool,
}
@@ -945,6 +949,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
subcommand,
strict_config: app_server_strict_config,
listen,
remote_control,
analytics_default_enabled,
auth,
} = app_server_cli;
@@ -959,6 +964,10 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
None => {
let transport = listen;
let auth = auth.try_into_settings()?;
let runtime_options = codex_app_server::AppServerRuntimeOptions {
remote_control_enabled: remote_control,
..Default::default()
};
codex_app_server::run_main_with_transport_options(
arg0_paths.clone(),
root_config_overrides,
@@ -968,7 +977,7 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
transport,
codex_protocol::protocol::SessionSource::VSCode,
auth,
codex_app_server::AppServerRuntimeOptions::default(),
runtime_options,
)
.await?;
}
@@ -2607,6 +2616,7 @@ mod tests {
fn app_server_analytics_default_disabled_without_flag() {
let app_server = app_server_from_args(["codex", "app-server"].as_ref());
assert!(!app_server.analytics_default_enabled);
assert!(!app_server.remote_control);
assert_eq!(
app_server.listen,
codex_app_server::AppServerTransport::Stdio