Files
codex/codex-rs/cli/src/daemon_install.rs
Eric Traut 321dcf5a6f Allow daemon updates to restore pinned packages to latest stable (#45780)
## Why

`codex app-server daemon update` previously required a latest-channel installation, leaving pinned and local managed packages unable to return to production updates through that command.

## What changed

- Allow explicit updates to restore managed packages to the latest stable release while preserving the automatic-update preference. Extend legacy migration to local and pinned packages when the published installer and release support it.
- Bind restoration to the selected release with a single-use updater authorization and installer guards. Scheduled updates and ordinary updater socket requests continue to respect pins.
- Restart a running daemon when its selected package changes, even if the binary and version are identical; leave stopped daemons stopped.
- Reject incompatible production packages before selecting them, resolve Windows junction targets for ownership checks, and show the restoration command after installing a pinned CLI package.

## Testing

Extend daemon and installer tests to cover local-package migration, restoration with automatic updates enabled or disabled, same-binary package restarts, stopped-daemon preservation, selection races, incompatible releases, and socket requests that must not undo pins.

GitOrigin-RevId: d64520c1190b5c7bac084fb4a1b6b24998b08dfa
2026-09-15 19:51:06 +00:00

43 lines
1.4 KiB
Rust

//! Confirmation for copying the invoking CLI package into a daemon installation.
use std::io::IsTerminal;
use anyhow::Result;
use codex_app_server_daemon::InstallRequest;
pub(crate) fn confirm_install(request: &InstallRequest, yes: bool) -> Result<bool> {
eprintln!("{}", describe_install(request));
if yes {
return Ok(true);
}
anyhow::ensure!(
std::io::stdin().is_terminal() && std::io::stderr().is_terminal(),
"daemon installation requires confirmation; rerun with --yes to copy this CLI package"
);
let confirmed = crate::confirm("Copy this package? [y/N]: ")?;
if !confirmed {
eprintln!("Daemon installation cancelled.");
}
Ok(confirmed)
}
fn describe_install(request: &InstallRequest) -> String {
let mut message = format!(
"Replace installed daemon version {} with CLI version {} from {}.\nThe daemon package will be installed in {}.\nThe selected package will be pinned. Run `codex app-server daemon update` to return to production updates.",
request.installed_version.as_deref().unwrap_or("unknown"),
request.version,
request.source.display(),
request.destination.display()
);
if request.restart_required {
message.push_str(
"\nThe running daemon will restart; active or queued work may be interrupted.",
);
}
message
}
#[cfg(test)]
#[path = "daemon_install_tests.rs"]
mod tests;