diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index f82efb784f..0127857c77 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1195,7 +1195,6 @@ dependencies = [ "codex-common", "codex-core", "codex-file-search", - "codex-git-tooling", "codex-login", "codex-ollama", "codex-protocol", diff --git a/codex-rs/tui/Cargo.toml b/codex-rs/tui/Cargo.toml index 7356ae334b..06cb064d3a 100644 --- a/codex-rs/tui/Cargo.toml +++ b/codex-rs/tui/Cargo.toml @@ -35,7 +35,6 @@ codex-common = { workspace = true, features = [ ] } codex-core = { workspace = true } codex-file-search = { workspace = true } -codex-git-tooling = { workspace = true } codex-login = { workspace = true } codex-ollama = { workspace = true } codex-protocol = { workspace = true } diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index d88b375918..26000dbf90 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -586,6 +586,8 @@ impl ChatWidget { fn on_background_event(&mut self, message: String) { debug!("BackgroundEvent: {message}"); + self.add_to_history(history_cell::new_background_event(message)); + self.request_redraw(); } fn on_stream_error(&mut self, message: String) { diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index 01ebb11be2..d24d0b62db 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -16,6 +16,7 @@ use codex_core::protocol::AgentMessageEvent; use codex_core::protocol::AgentReasoningDeltaEvent; use codex_core::protocol::AgentReasoningEvent; use codex_core::protocol::ApplyPatchApprovalRequestEvent; +use codex_core::protocol::BackgroundEventEvent; use codex_core::protocol::Event; use codex_core::protocol::EventMsg; use codex_core::protocol::ExecApprovalRequestEvent; @@ -173,6 +174,31 @@ fn entered_review_mode_defaults_to_current_changes_banner() { assert!(chat.is_review_mode); } +/// Background events produce a visible info cell in the history. +#[test] +fn background_event_renders_in_history() { + let (mut chat, mut rx, _ops) = make_chatwidget_manual(); + + chat.handle_codex_event(Event { + id: "bg".to_string(), + msg: EventMsg::BackgroundEvent(BackgroundEventEvent { + message: "Restored workspace to snapshot deadbeef".to_string(), + }), + }); + + let cells = drain_insert_history(&mut rx); + assert_eq!(cells.len(), 1, "expected a single background event cell"); + let rendered = lines_to_single_string(&cells[0]); + assert!( + rendered.contains("Restored workspace to snapshot deadbeef"), + "background event text should be present" + ); + assert!( + rendered.starts_with("• "), + "background events should use a bullet prefix" + ); +} + /// Completing review with findings shows the selection popup and finishes with /// the closing banner while clearing review mode state. #[test] diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index 4121a98397..0589ceb0cc 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -246,6 +246,30 @@ impl HistoryCell for PlainHistoryCell { } } +#[derive(Debug)] +pub(crate) struct BackgroundEventCell { + message: String, +} + +impl BackgroundEventCell { + pub(crate) fn new(message: String) -> Self { + Self { message } + } +} + +impl HistoryCell for BackgroundEventCell { + fn display_lines(&self, width: u16) -> Vec> { + let wrap_width = width.max(2) as usize; + let message_line = Line::from(self.message.as_str()).style(Style::default().dim()); + word_wrap_lines( + &[message_line], + RtOptions::new(wrap_width) + .initial_indent(Line::from("• ".dim())) + .subsequent_indent(Line::from(" ")), + ) + } +} + #[derive(Debug)] pub(crate) struct TranscriptOnlyHistoryCell { lines: Vec>, @@ -933,6 +957,10 @@ pub(crate) fn new_stream_error_event(message: String) -> PlainHistoryCell { PlainHistoryCell { lines } } +pub(crate) fn new_background_event(message: String) -> BackgroundEventCell { + BackgroundEventCell::new(message) +} + /// Render a user‑friendly plan update styled like a checkbox todo list. pub(crate) fn new_plan_update(update: UpdatePlanArgs) -> PlanUpdateCell { let UpdatePlanArgs { explanation, plan } = update; diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs index 14604a736d..e9a2321ff8 100644 --- a/codex-rs/tui/src/slash_command.rs +++ b/codex-rs/tui/src/slash_command.rs @@ -87,7 +87,7 @@ pub fn built_in_slash_commands() -> Vec<(&'static str, SlashCommand)> { SlashCommand::iter() .filter(|cmd| { if *cmd == SlashCommand::Undo { - show_beta_features + true } else { true }