feat: better UI for unified_exec (#6515)

<img width="376" height="132" alt="Screenshot 2025-11-12 at 17 36 22"
src="https://github.com/user-attachments/assets/ce693f0d-5ca0-462e-b170-c20811dcc8d5"
/>
This commit is contained in:
jif-oai
2025-11-14 16:31:12 +01:00
committed by GitHub
parent 4788fb179a
commit 63c8c01f40
17 changed files with 563 additions and 129 deletions

View File

@@ -23,6 +23,7 @@ use codex_core::protocol::EventMsg;
use codex_core::protocol::ExecApprovalRequestEvent;
use codex_core::protocol::ExecCommandBeginEvent;
use codex_core::protocol::ExecCommandEndEvent;
use codex_core::protocol::ExecCommandSource;
use codex_core::protocol::ExitedReviewModeEvent;
use codex_core::protocol::ListCustomPromptsResponseEvent;
use codex_core::protocol::McpListToolsResponseEvent;
@@ -129,7 +130,7 @@ const USER_SHELL_COMMAND_HELP_HINT: &str = "Example: !ls";
struct RunningCommand {
command: Vec<String>,
parsed_cmd: Vec<ParsedCommand>,
is_user_shell_command: bool,
source: ExecCommandSource,
}
const RATE_LIMIT_WARNING_THRESHOLDS: [f64; 3] = [75.0, 90.0, 95.0];
@@ -724,6 +725,9 @@ impl ChatWidget {
fn on_background_event(&mut self, message: String) {
debug!("BackgroundEvent: {message}");
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(true);
self.set_status_header(message);
}
fn on_undo_started(&mut self, event: UndoStartedEvent) {
@@ -833,10 +837,16 @@ impl ChatWidget {
pub(crate) fn handle_exec_end_now(&mut self, ev: ExecCommandEndEvent) {
let running = self.running_commands.remove(&ev.call_id);
let (command, parsed, is_user_shell_command) = match running {
Some(rc) => (rc.command, rc.parsed_cmd, rc.is_user_shell_command),
None => (vec![ev.call_id.clone()], Vec::new(), false),
let (command, parsed, source) = match running {
Some(rc) => (rc.command, rc.parsed_cmd, rc.source),
None => (
vec![ev.call_id.clone()],
Vec::new(),
ExecCommandSource::Agent,
),
};
let is_unified_exec_interaction =
matches!(source, ExecCommandSource::UnifiedExecInteraction);
let needs_new = self
.active_cell
@@ -849,7 +859,8 @@ impl ChatWidget {
ev.call_id.clone(),
command,
parsed,
is_user_shell_command,
source,
None,
)));
}
@@ -858,15 +869,20 @@ impl ChatWidget {
.as_mut()
.and_then(|c| c.as_any_mut().downcast_mut::<ExecCell>())
{
cell.complete_call(
&ev.call_id,
let output = if is_unified_exec_interaction {
CommandOutput {
exit_code: ev.exit_code,
formatted_output: String::new(),
aggregated_output: String::new(),
}
} else {
CommandOutput {
exit_code: ev.exit_code,
formatted_output: ev.formatted_output.clone(),
aggregated_output: ev.aggregated_output.clone(),
},
ev.duration,
);
}
};
cell.complete_call(&ev.call_id, output, ev.duration);
if cell.should_flush() {
self.flush_active_cell();
}
@@ -928,9 +944,10 @@ impl ChatWidget {
RunningCommand {
command: ev.command.clone(),
parsed_cmd: ev.parsed_cmd.clone(),
is_user_shell_command: ev.is_user_shell_command,
source: ev.source,
},
);
let interaction_input = ev.interaction_input.clone();
if let Some(cell) = self
.active_cell
.as_mut()
@@ -939,7 +956,8 @@ impl ChatWidget {
ev.call_id.clone(),
ev.command.clone(),
ev.parsed_cmd.clone(),
ev.is_user_shell_command,
ev.source,
interaction_input.clone(),
)
{
*cell = new_exec;
@@ -950,7 +968,8 @@ impl ChatWidget {
ev.call_id.clone(),
ev.command.clone(),
ev.parsed_cmd,
ev.is_user_shell_command,
ev.source,
interaction_input,
)));
}