use super::{
App, ComposerMode, Entry, InlineChoice, InlineChoiceModal, InlineChoiceOption,
InlineChoicePending, InteractiveRuntime,
};
use crate::tools::computer_use::{
setup_platform, ComputerUseControl, ComputerUsePreference, ComputerUseStatus,
UpdateCheckStatus, UpdateOutcome,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum UpdateRequest {
OfferInstall,
CheckOnly,
}
impl App {
pub(super) fn auto_check_computer_update(&self) {
let Some(control) = &self.computer_use else {
return;
};
if control.update_check_status() != UpdateCheckStatus::NotChecked {
return;
}
let trusted = match control.status() {
ComputerUseStatus::Connecting | ComputerUseStatus::Connected => true,
ComputerUseStatus::Installing | ComputerUseStatus::Closing => false,
ComputerUseStatus::Off => {
control.saved_session_preference() == Some(ComputerUsePreference::Enabled)
}
};
if trusted {
let _ = control.start_update_check();
}
}
pub(in crate::tui) fn check_computer_update(&mut self) {
let Some(control) = self.computer_use.clone() else {
return;
};
match control.start_update_check() {
Ok(()) => self.set_status("checking for Cua Driver updates"),
Err(error) => self.insert_entry(&Entry::Error(format!(
"could not check for Cua Driver updates: {error}"
))),
}
}
pub(super) fn update_computer(&mut self, request: UpdateRequest) {
let Some(control) = self.computer_use.clone() else {
return;
};
let (current, latest) = match control.update_check_status() {
UpdateCheckStatus::Checking => {
self.set_status("checking for Cua Driver updates");
self.show_computer_status();
return;
}
UpdateCheckStatus::Checked(UpdateOutcome::Available {
current, latest, ..
}) => (current, latest),
UpdateCheckStatus::Checked(
UpdateOutcome::UpToDate { .. } | UpdateOutcome::Unavailable { .. },
)
| UpdateCheckStatus::NotChecked
| UpdateCheckStatus::Failed(_) => {
self.check_computer_update();
self.show_computer_status();
return;
}
};
let blocker = match (request, control.status()) {
(UpdateRequest::CheckOnly, _) => {
Some("finish the current turn and leave plan mode first")
}
(UpdateRequest::OfferInstall, ComputerUseStatus::Off) => None,
(UpdateRequest::OfferInstall, ComputerUseStatus::Installing) => {
Some("an installation is already pending")
}
(
UpdateRequest::OfferInstall,
ComputerUseStatus::Connecting
| ComputerUseStatus::Connected
| ComputerUseStatus::Closing,
) => Some("/computer off first; updating never reconnects automatically"),
};
if let Some(blocker) = blocker {
self.insert_entry(&Entry::Error(format!(
"could not update Cua Driver to {latest}: {blocker}"
)));
return;
}
if let Err(error) = control.ensure_managed_driver() {
self.insert_entry(&Entry::Error(format!(
"could not update Cua Driver: {error}"
)));
return;
}
let platform = setup_platform();
let choice = InlineChoice::new(
format!("Update Cua Driver {current} to {latest}?"),
format!("Download and execute {}, pinned to {latest}. Writes to {}. The installer may replace Cua files and stop running Cua daemons. {} Rho forces Cua telemetry off for the installer and leaves your saved telemetry preference unchanged. Desktop access stays off; /computer on reconnects and saves access on again.", platform.source, platform.locations, platform.notes),
vec![
InlineChoiceOption::available("cancel", 'c', "Cancel", "Keep the current driver"),
InlineChoiceOption::available("update", 'u', "Update driver", "Download and execute Cua's installer").require_full_visibility(),
],
);
match choice {
Ok(choice) => {
self.input_ui
.set_composer(ComposerMode::InlineChoice(InlineChoiceModal {
choice,
pending: InlineChoicePending::ComputerUpdate {
from: current,
to: latest,
},
parent_picker: None,
}))
}
Err(error) => self.insert_entry(&Entry::Error(format!(
"could not show Cua Driver update confirmation: {error}"
))),
}
}
pub(in crate::tui) fn confirm_computer_update(
&mut self,
value: &str,
from: &str,
to: &str,
agent: &InteractiveRuntime,
) {
if value != "update" {
self.set_status("Cua Driver update not authorized");
return;
}
match agent.update_computer_driver(from, to) {
Ok(log) => self.insert_entry(&Entry::Notice(format!(
"updating Cua Driver to {to}; desktop access remains off. /computer off cancels. Installer output: {}",
log.display()
))),
Err(error) => self.insert_entry(&Entry::Error(format!(
"could not update Cua Driver: {error}"
))),
}
}
}
impl ComputerUseControl {
pub(in crate::tui) fn update_hint(&self) -> &'static str {
match self.status() {
ComputerUseStatus::Off => "/computer update installs it",
ComputerUseStatus::Installing => "installation pending",
ComputerUseStatus::Connecting
| ComputerUseStatus::Connected
| ComputerUseStatus::Closing => "/computer off, then /computer update",
}
}
}