merge code-branch-20251026-150523 via /merge

This commit is contained in:
James Peter
2025-10-27 08:36:48 +10:00
parent b0a728348f
commit f068efc696
27 changed files with 487 additions and 181 deletions
+19 -4
View File
@@ -1,9 +1,9 @@
use std::env;
use ratatui::style::{Modifier, Style};
use ratatui::style::{Color, Modifier, Style};
use ratatui::widgets::BorderType;
use crate::colors;
use crate::{card_theme, colors};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AutoDriveVariant {
@@ -183,8 +183,23 @@ pub struct ComposerStyle {
pub title_style: Style,
}
fn auto_drive_accent_color() -> Color {
if is_dark_theme_active() {
card_theme::auto_drive_dark_theme().theme.gradient.left
} else {
card_theme::auto_drive_light_theme().theme.gradient.left
}
}
fn is_dark_theme_active() -> bool {
let (r, g, b) = colors::color_to_rgb(colors::background());
let luminance = (0.2126 * r as f32 + 0.7152 * g as f32 + 0.0722 * b as f32) / 255.0;
luminance < 0.5
}
fn sentinel_style() -> AutoDriveStyle {
let primary = colors::primary();
let accent = auto_drive_accent_color();
AutoDriveStyle {
variant: AutoDriveVariant::Sentinel,
frame: FrameStyle {
@@ -208,13 +223,13 @@ fn sentinel_style() -> AutoDriveStyle {
disabled_style: Style::default().fg(colors::text_dim()),
},
composer: ComposerStyle {
border_style: Style::default().fg(primary),
border_style: Style::default().fg(accent),
border_type: BorderType::Rounded,
background_style: Style::default().bg(colors::background()),
goal_title_prefix: " ▶ Goal ",
goal_title_suffix: " ",
title_style: Style::default()
.fg(primary)
.fg(accent)
.add_modifier(Modifier::BOLD),
},
footer_separator: " • ",
@@ -110,6 +110,11 @@ impl AutoCoordinatorView {
self.model = model;
}
#[cfg(test)]
pub(crate) fn model(&self) -> &AutoCoordinatorViewModel {
&self.model
}
pub fn set_style(&mut self, style: AutoDriveStyle) {
self.style = style;
}
@@ -645,6 +650,10 @@ impl AutoCoordinatorView {
rows
}
fn has_pending_prompt_content(model: &AutoActiveViewModel) -> bool {
model.cli_prompt.is_some() || model.cli_context.is_some()
}
fn render_pending_prompt_block(
&self,
area: Rect,
@@ -1208,29 +1217,35 @@ impl AutoCoordinatorView {
}
let mut prompt_lines = self.cli_prompt_lines(model);
let has_pending_prompt = Self::has_pending_prompt_content(model);
let mut top_lines: Vec<Line<'static>> = Vec::new();
let mut after_lines: Vec<Line<'static>> = Vec::new();
let mut button_block = self.button_block_lines(&ctx);
if !model.editing_prompt {
let base_y = inner.y;
let base_height = inner.height;
let used = self.render_pending_prompt_block(inner, buf, model);
if used == 0 {
if has_pending_prompt {
let base_y = inner.y;
let base_height = inner.height;
let used = self.render_pending_prompt_block(inner, buf, model);
if used >= base_height {
return;
}
if used > 0 {
let new_y = base_y + used;
let remaining_height =
base_height.saturating_sub(new_y.saturating_sub(base_y));
inner = Rect {
x: inner.x,
y: new_y,
width: inner.width,
height: remaining_height,
};
} else {
Self::clear_rect(inner, buf);
}
} else {
Self::clear_rect(inner, buf);
return;
}
if used >= base_height {
return;
}
let new_y = base_y + used;
let remaining_height = base_height.saturating_sub(new_y.saturating_sub(base_y));
inner = Rect {
x: inner.x,
y: new_y,
width: inner.width,
height: remaining_height,
};
} else if let Some(mut lines) = prompt_lines.take() {
top_lines.append(&mut lines);
}
+1 -1
View File
@@ -192,7 +192,7 @@ impl BottomPane<'_> {
.as_ref()
.and_then(|view| view.as_any())
.and_then(|any| any.downcast_ref::<AutoCoordinatorView>())
.map(|view| view.model.clone())
.map(|view| view.model().clone())
}
fn apply_auto_drive_style(&mut self) {
+24 -1
View File
@@ -14877,6 +14877,10 @@ Have we met every part of this goal and is there no further work to do?"#
.filter(|value| !value.trim().is_empty());
let bootstrap_pending = self.auto_pending_goal_request;
let continue_mode = self.auto_state.continue_mode;
let continue_cta_active = self.auto_state.awaiting_coordinator_submit()
&& !self.auto_state.is_paused_manual()
&& continue_mode != AutoContinueMode::Manual;
let countdown_limit = self.auto_state.countdown_seconds();
let countdown_active = self.auto_state.countdown_active();
@@ -14894,6 +14898,8 @@ Have we met every part of this goal and is there no further work to do?"#
let button = if self.auto_state.awaiting_coordinator_submit() {
let base_label = if bootstrap_pending {
"Complete Current Task"
} else if continue_cta_active {
"Continue current task"
} else {
"Send prompt"
};
@@ -14915,6 +14921,12 @@ Have we met every part of this goal and is there no further work to do?"#
Some("Edit the prompt, then press Enter to continue.".to_string())
} else if bootstrap_pending {
None
} else if continue_cta_active {
if countdown_active {
Some("Enter to continue now • Esc to stop".to_string())
} else {
Some("Enter to continue • Esc to stop".to_string())
}
} else if countdown_active {
Some("Enter to send now • Esc to edit".to_string())
} else {
@@ -14929,6 +14941,8 @@ Have we met every part of this goal and is there no further work to do?"#
"Esc to cancel".to_string()
} else if bootstrap_pending {
"Esc enter new goal".to_string()
} else if continue_cta_active {
"Esc to stop".to_string()
} else {
"Esc to edit".to_string()
}
@@ -18085,6 +18099,15 @@ Have we met every part of this goal and is there no further work to do?"#
}
if self.auto_state.is_active() {
let continue_mode = self.auto_state.continue_mode;
let awaiting_continue_cta = self.auto_state.awaiting_coordinator_submit()
&& !self.auto_state.is_paused_manual()
&& continue_mode != AutoContinueMode::Manual;
if awaiting_continue_cta {
return EscRoute::new(EscIntent::AutoStopDuringApproval, true, false);
}
if self.auto_state.countdown_active()
|| (self.auto_state.awaiting_coordinator_submit()
&& !self.auto_state.is_paused_manual())
@@ -22206,7 +22229,7 @@ mod tests {
use crate::bottom_pane::AutoCoordinatorViewModel;
use crate::chatwidget::message::UserMessage;
use crate::chatwidget::smoke_helpers::ChatWidgetHarness;
use crate::history_cell::{self, ExploreAggregationCell, HistoryCellType, PlainHistoryCell};
use crate::history_cell::{self, ExploreAggregationCell, HistoryCellType};
use code_auto_drive_core::{
AutoContinueMode,
AutoRunPhase,
+45 -9
View File
@@ -895,12 +895,25 @@ pub(super) fn handle_exec_begin_now(
let has_read_command = parsed_command
.iter()
.any(|p| matches!(p, ParsedCommand::ReadCommand { .. }));
let mut upgraded_tool_idx = if let Some(entry) = chat
.tools_state
.running_custom_tools
.remove(&super::ToolCallId(ev.call_id.clone()))
{
running_tools::resolve_entry_index(chat, &entry, &ev.call_id)
.or_else(|| running_tools::find_by_call_id(chat, &ev.call_id))
} else {
running_tools::find_by_call_id(chat, &ev.call_id)
};
if matches!(
action,
ExecAction::Read | ExecAction::Search | ExecAction::List
) || has_read_command
{
if let Some(idx) = upgraded_tool_idx.take() {
chat.history_remove_at(idx);
}
let mut created_new = false;
let mut agg_idx = chat.exec.running_explore_agg_index.and_then(|idx| {
if idx < chat.history_cells.len()
@@ -993,19 +1006,42 @@ pub(super) fn handle_exec_begin_now(
let exec_record = exec_record_from_begin(&ev);
let key = chat.provider_order_key_from_order_meta(order);
let cell = history_cell::ExecCell::from_record(exec_record.clone());
let idx = chat.history_insert_with_key_global_tagged(
Box::new(cell),
key,
"exec-begin",
Some(HistoryDomainRecord::Exec(exec_record)),
);
let history_idx = if let Some(idx) = upgraded_tool_idx {
let replacement = history_cell::ExecCell::from_record(exec_record.clone());
chat.history_replace_with_record(
idx,
Box::new(replacement),
HistoryDomainRecord::Exec(exec_record.clone()),
);
if idx < chat.cell_order_seq.len() {
chat.cell_order_seq[idx] = key;
}
if idx < chat.cell_order_dbg.len() {
chat.cell_order_dbg[idx] = None;
}
chat.last_assigned_order = Some(
chat
.last_assigned_order
.map(|prev| prev.max(key))
.unwrap_or(key),
);
chat.bottom_pane.set_has_chat_history(true);
idx
} else {
let cell = history_cell::ExecCell::from_record(exec_record.clone());
chat.history_insert_with_key_global_tagged(
Box::new(cell),
key,
"exec-begin",
Some(HistoryDomainRecord::Exec(exec_record.clone())),
)
};
chat.exec.running_commands.insert(
super::ExecCallId(ev.call_id.clone()),
super::RunningCommand {
command: ev.command.clone(),
parsed: parsed_command,
history_index: Some(idx),
history_index: Some(history_idx),
history_id: None,
explore_entry: None,
stdout: String::new(),
@@ -1023,7 +1059,7 @@ pub(super) fn handle_exec_begin_now(
let history_id = chat
.history_state
.history_id_for_exec_call(&ev.call_id)
.or_else(|| chat.history_cell_ids.get(idx).and_then(|slot| *slot));
.or_else(|| chat.history_cell_ids.get(history_idx).and_then(|slot| *slot));
running.history_id = history_id;
}
if !chat.tools_state.web_search_sessions.is_empty() {
+1 -1
View File
@@ -107,7 +107,7 @@ impl AgentStatusKind {
fn color(self) -> Color {
match self {
AgentStatusKind::Running => colors::info(),
AgentStatusKind::Running => colors::primary(),
AgentStatusKind::Completed => colors::success(),
AgentStatusKind::Failed => colors::error(),
AgentStatusKind::Cancelled => colors::text_dim(),
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1278
expression: output
---
+----------------------------------------------------------------------------+
@@ -22,14 +23,14 @@ expression: output
| Run targeted regression suite
|
| Agents
| • claude running (18s)
| • claude running (Xs)
|
| Actions
| 0s Started agent run for qa-bot
| MM:SS Started agent run for qa-bot
|
+- [Ctrl+A] Expand · [Esc] Stop
+----------------------------- ✶ Responding... ------------------------------+
+----------------------------- ✶ Responding... -----------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Read Only (Shift+Tab change) Ctrl+H help
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1627
expression: output
---
+----------------------------------------------------------------------------+
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1480
expression: "&output"
---
+--------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+--------------------------------------------------------------------------------------------+
+ Agents - Ctrl+A to close-------------------------------------------------------------------+
| |
@@ -16,17 +17,17 @@ expression: "&output"
| | | |
| | Action History | |
| | | |
| | [MM:SS:29] claude-3-opus status: Status → Running | |
| | [MM:SS] claude-3-opus status: Status → Running | |
| | | |
| | [MM:SS:29] claude-3-opus progress: Collecting release notes| |
| | Reviewing eng updates | |
| | [MM:SS] claude-3-opus detail: … | |
| |
| | | |
| | [MM:SS:29] gpt-4o status: Status → Pending | |
| | [MM:SS] gpt-4o status: Status → Pending | |
| | | |
| | [MM:SS:29] claude-3-opus status: Status → Completed | |
| | | |
| | [MM:SS:29] claude-3-opus progress: Synthesizing highlights | |
| | [MM:SS] claude-3-opus status: Status → Completed | |
| | | |
| | [MM:SS] claude-3-opus detail: … | |
| |
| +------------------------------------------------------------+ |
| ↑/↓ Navigate/Scroll →/Enter Focus output ← Back to list Tab Next agent PgUp/PgDn Page |
| |
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 416
expression: "frames.join(\"\\n---FRAME---\\n\")"
---
+----------------------------------------------------------------------------+
@@ -14,45 +15,7 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Comparing diffs against last run. ✶ Thinking (1s)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Comparing diffs against last run. ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo test --workspace |
+----------------------------------------------------------------------------+
+------------------+
| Send prompt (6s) | Esc to edit
+------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Awaiting review (1s)
Auto Drive > Comparing diffs against last run. ✶ Thinking (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
@@ -71,7 +34,45 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Queued new command for execution. ✶ Thinking (1s)
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Awaiting review (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Queued new command for execution. ✶ Thinking (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 452
expression: "frames.join(\"\\n---FRAME---\\n\")"
---
+----------------------------------------------------------------------------+
@@ -8,9 +9,9 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Installed dependencies > Running cargo check... ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo check |
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
@@ -21,9 +22,9 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Installed dependencies > Running cargo check... ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo check |
Auto Drive > Installed dependencies > Running cargo check... ✶ Thinking (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
@@ -34,8 +35,8 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Installed dependencies > Running cargo check... ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo check |
Auto Drive > Installed dependencies > Running cargo check... ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
@@ -1,59 +1,60 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 371
expression: "frames.join(\"\\n---FRAME---\\n\")"
---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo nextest run --no-fail-fast |
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
+------------------+
| Send prompt (9s) | Esc to edit
+------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo nextest run --no-fail-fast |
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
+------------------+
| Send prompt (9s) | Esc to edit
+------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo nextest run --no-fail-fast |
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
+------------------+
| Send prompt (9s) | Esc to edit
+------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
@@ -1,42 +1,24 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 489
expression: "frames.join(\"\\n---FRAME---\\n\")"
---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo fmt --check |
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
+------------------+
| Send prompt (3s) | Esc to edit
+------------------+
Agents Disabled • Diagnostics Enabl… Ctrl+S settings • Esc stop Auto Drive
---FRAME---
| What can I code for you today? |
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| cargo fmt --check |
+----------------------------------------------------------------------------+
+------------------+
| Send prompt (1s) | Esc to edit
+------------------+
Agents Disabled • Diagnostics Enabl… Ctrl+S settings • Esc stop Auto Drive
---FRAME---
@@ -52,7 +34,26 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Running cargo fmt --check. ✶ Thinking (1s)
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
Agents Disabled • Diagnostics Enabl… Ctrl+S settings • Esc stop Auto Drive
---FRAME---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Running cargo fmt --check. ✶ Thinking (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
@@ -1,21 +1,22 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 533
expression: frame
---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Waiting (1s)
+ Next Prompt ---------------------------------------------------------------+
| justfile run manual |
Auto Drive > Working ✶ Running (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
+-------------------+
| Send prompt (10s) | Esc to edit
+-------------------+
Agents Enabled • Diagnostics Enabled Ctrl+S settings • Esc stop Auto Drive
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 511
expression: frame
---
+----------------------------------------------------------------------------+
@@ -14,7 +15,7 @@ expression: frame
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Awaiting review (1s)
Auto Drive > Working ✶ Awaiting review (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 560
expression: "frames.join(\"\\n---FRAME---\\n\")"
---
+----------------------------------------------------------------------------+
@@ -14,7 +15,7 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Working ✶ Awaiting review (1s)
Auto Drive > Working ✶ Awaiting review (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
@@ -33,7 +34,7 @@ expression: "frames.join(\"\\n---FRAME---\\n\")"
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
Auto Drive > Coordinator resumed the workflow. ✶ Thinking (1s)
Auto Drive > Coordinator resumed the workflow. ✶ Thinking (Xs)
+----------------------------------------------------------------------------+
| What can I code for you today? |
+----------------------------------------------------------------------------+
@@ -1,31 +1,32 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 967
expression: output
---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
› Open docs and find login button
+- +Browser--------------------------------+
| |Screenshot: |
| |browser_session.png | 0s Opened https://examp
| | | le.com/docs
| | | 5s Clicked Sign in
| +---------------------------------------+ button
| 18s Scrolled dy=640
| 32s Typed docs search
+- +Browser-----------------------------+
| |Screenshot: |
| |browser_session.png | Actions
| | | MM:SS Opened https://ex
| | | ample.com/
| +------------------------------------+ docs
| MM:SS Clicked Sign in
| button
| MM:SS Scrolled dy=640
| MM:SS Typed docs
| search
|
| Console: ⚠️ cdp warning:
| Refused to load script from
| cdn.example.com
| Console: ⚠️ cdp warning:
| Refused to load script from
| cdn.example.com
|
+- [Ctrl+B] View · [Esc] Stop
@@ -1,5 +1,6 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1052
expression: output
---
+----------------------------------------------------------------------------+
@@ -9,7 +10,6 @@ expression: output
★ Popular commands:
/settings - manage all settings in one place NEW
/auto - work autonomously on long tasks with Auto Drive UPDATED
@@ -21,9 +21,10 @@ expression: output
+- Browser (headless): example.com
|
| 0s Opened https://example.com
| 3s Typed pizza
| 5s Pressed Enter
| Actions
| MM:SS Opened https://example.com
| MM:SS Typed pizza
| MM:SS Pressed Enter
|
| Console: ⚠️ Encountering captcha block
|
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1506
expression: closed
---
+------------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+------------------------------------------------------------------------------------------------+
+Settings ▸ Overview-----------------------------------------------------------------------------+
| |
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1502
expression: open
---
+------------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+------------------------------------------------------------------------------------------------+
+Settings ▸ Overview-----------------------------------------------------------------------------+
| |
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1523
expression: section_closed
---
+------------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+------------------------------------------------------------------------------------------------+
+Settings ▸ Model--------------------------------------------------------------------------------+
| |
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1519
expression: section_open
---
+------------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+------------------------------------------------------------------------------------------------+
+Settings ▸ Model--------------------------------------------------------------------------------+
| |
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1431
expression: output
---
+------------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+------------------------------------------------------------------------------------------------+
+Settings ▸ Overview-----------------------------------------------------------------------------+
| |
@@ -1,9 +1,10 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 1469
expression: output
---
+------------------------------------------------------------------------------------------------+
| Code • Directory: ~/.code/working/code/branches/code-branch-20251024-135958/code-rs/tui |
| Code • Directory: ~/.code/working/code/branches/code-branch-20251026-150523/code-rs/tui |
+------------------------------------------------------------------------------------------------+
+Settings ▸ Overview-----------------------------------------------------------------------------+
| |
@@ -1,26 +1,28 @@
---
source: tui/tests/vt100_chatwidget_snapshot.rs
assertion_line: 850
expression: output
---
+----------------------------------------------------------------------------+
| Code |
+----------------------------------------------------------------------------+
/auto - work autonomously on long tasks with Auto Drive UPDATED
/chrome - connect to your Chrome browser
/plan - create a comprehensive plan (multiple agents)
/code - perform a coding task (multiple agents)
› Can you gather details from the latest docs update?
✔ Web Search, duration: Xms
+ query: ratatui widget patterns
⚙ Web Search... (Xm Ys)
+ query: async rust tui example
+- Web Search · Completed
|
| Actions
| MM:SS • Searching…
| MM:SS • Query: "ratatui widget patterns"
| MM:SS ✓ Results ready
|
+- [Ctrl+S] Settings · [Esc] Stop
+- Browser (headless): Browser Session
|
| 0s Clicked #login-button
| Actions
| MM:SS Clicked #login-button
|
+- [Ctrl+B] View · [Esc] Stop
@@ -32,10 +34,9 @@ expression: output
| No agent updates yet
|
| Actions
| 0s Started agent run for qa-bot
| 0s Waiting for agents
| MM:SS Started agent run for qa-bot
| MM:SS Waiting for agents
|
+- [Ctrl+A] Expand
+----------------------------------------------------------------------------+
| What can I code for you today? |
+64
View File
@@ -3,6 +3,8 @@ use code_core::protocol::{
EventMsg,
ExecCommandBeginEvent,
ExecCommandEndEvent,
McpInvocation,
McpToolCallBeginEvent,
OrderMeta,
PatchApplyBeginEvent,
PatchApplyEndEvent,
@@ -180,3 +182,65 @@ fn synthetic_end_clears_cancelled_exec_spinner() {
after
);
}
#[test]
fn exec_begin_upgrades_running_tool_cell() {
let mut harness = ChatWidgetHarness::new();
let mut seq = 0_u64;
let call_id = "call_coalesce".to_string();
let cwd = PathBuf::from("/tmp");
harness.handle_event(Event {
id: "mcp-begin".to_string(),
event_seq: 0,
msg: EventMsg::McpToolCallBegin(McpToolCallBeginEvent {
call_id: call_id.clone(),
invocation: McpInvocation {
server: "demo".to_string(),
tool: "run_command".to_string(),
arguments: None,
},
}),
order: Some(next_order_meta(1, &mut seq)),
});
harness.handle_event(Event {
id: "exec-begin-coalesce".to_string(),
event_seq: 1,
msg: EventMsg::ExecCommandBegin(ExecCommandBeginEvent {
call_id: call_id.clone(),
command: vec!["bash".into(), "-lc".into(), "echo upgraded".into()],
cwd: cwd.clone(),
parsed_cmd: Vec::new(),
}),
order: Some(next_order_meta(1, &mut seq)),
});
harness.handle_event(Event {
id: "exec-end-coalesce".to_string(),
event_seq: 2,
msg: EventMsg::ExecCommandEnd(ExecCommandEndEvent {
call_id: call_id,
stdout: "upgraded\n".into(),
stderr: String::new(),
exit_code: 0,
duration: Duration::from_millis(5),
}),
order: Some(next_order_meta(1, &mut seq)),
});
let output = render_chat_widget_to_vt100(&mut harness, 80, 12);
assert!(
!output.contains("Working..."),
"running tool spinner should be upgraded to an exec cell:\n{output}",
);
let command_occurrences = output.matches("echo upgraded").count();
assert_eq!(
command_occurrences, 1,
"expected exactly one exec command row after upgrade:\n{output}",
);
assert!(
output.contains("upgraded"),
"exec output should remain attached to the upgraded cell:\n{output}",
);
}
+135 -1
View File
@@ -30,7 +30,7 @@ use code_tui::test_helpers::{
ChatWidgetHarness,
};
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyEventState, KeyModifiers};
use regex_lite::Regex;
use regex_lite::{Captures, Regex};
use serde_json::json;
use std::path::PathBuf;
use std::sync::OnceLock;
@@ -42,6 +42,8 @@ fn normalize_output(text: String) -> String {
.map(normalize_glyph)
.collect::<String>()
.pipe(normalize_timers)
.pipe(normalize_auto_drive_layout)
.pipe(normalize_agent_history_details)
.pipe(normalize_spacer_rows)
}
@@ -96,8 +98,15 @@ fn normalize_timers(text: String) -> String {
static IN_SECONDS_RE: OnceLock<Regex> = OnceLock::new();
static T_MINUS_RE: OnceLock<Regex> = OnceLock::new();
static MM_SS_RE: OnceLock<Regex> = OnceLock::new();
static MM_SS_SUFFIX_RE: OnceLock<Regex> = OnceLock::new();
static MS_RE: OnceLock<Regex> = OnceLock::new();
static MIN_SEC_RE: OnceLock<Regex> = OnceLock::new();
static PAREN_SECONDS_RE: OnceLock<Regex> = OnceLock::new();
static PAREN_MINUTES_RE: OnceLock<Regex> = OnceLock::new();
static PAREN_MINUTES_SECONDS_RE: OnceLock<Regex> = OnceLock::new();
static PAREN_HOURS_MINUTES_RE: OnceLock<Regex> = OnceLock::new();
static PAREN_HOURS_MINUTES_SECONDS_RE: OnceLock<Regex> = OnceLock::new();
static RAW_SECONDS_SUFFIX_RE: OnceLock<Regex> = OnceLock::new();
let text = IN_SECONDS_RE
.get_or_init(|| Regex::new(r"\bin\s+\d+s\b").expect("valid in seconds regex"))
@@ -114,17 +123,142 @@ fn normalize_timers(text: String) -> String {
.replace_all(&text, "MM:SS")
.into_owned();
let text = MM_SS_SUFFIX_RE
.get_or_init(|| Regex::new(r"MM:SS:\d{2}").expect("valid mm:ss suffix regex"))
.replace_all(&text, "MM:SS")
.into_owned();
let text = MS_RE
.get_or_init(|| Regex::new(r"\b\d+ms\b").expect("valid milliseconds regex"))
.replace_all(&text, "Xms")
.into_owned();
let text = PAREN_SECONDS_RE
.get_or_init(|| Regex::new(r"\(\d+s\)").expect("valid paren seconds regex"))
.replace_all(&text, "(Xs)")
.into_owned();
let text = PAREN_MINUTES_RE
.get_or_init(|| Regex::new(r"\(\d+m\)").expect("valid paren minutes regex"))
.replace_all(&text, "(Xm)")
.into_owned();
let text = PAREN_MINUTES_SECONDS_RE
.get_or_init(|| Regex::new(r"\(\d+m\s+\d+s\)").expect("valid paren minutes seconds regex"))
.replace_all(&text, "(Xm Xs)")
.into_owned();
let text = PAREN_HOURS_MINUTES_RE
.get_or_init(|| Regex::new(r"\(\d+h\s+\d+m\)").expect("valid paren hours minutes regex"))
.replace_all(&text, "(Xh Xm)")
.into_owned();
let text = PAREN_HOURS_MINUTES_SECONDS_RE
.get_or_init(|| Regex::new(r"\(\d+h\s+\d+m\s+\d+s\)").expect("valid paren hours minutes seconds regex"))
.replace_all(&text, "(Xh Xm Xs)")
.into_owned();
let text = RAW_SECONDS_SUFFIX_RE
.get_or_init(|| Regex::new(r"\b\d+s\b").expect("valid raw seconds suffix regex"))
.replace_all(&text, "Xs")
.into_owned();
MIN_SEC_RE
.get_or_init(|| Regex::new(r"\b\d+m\s+\d+s\b").expect("valid minute-second regex"))
.replace_all(&text, "Xm Ys")
.into_owned()
}
fn normalize_auto_drive_layout(text: String) -> String {
static AUTO_DRIVE_STATUS_ALIGN_RE: OnceLock<Regex> = OnceLock::new();
static AUTO_DRIVE_BANNER_RE: OnceLock<Regex> = OnceLock::new();
let text = AUTO_DRIVE_STATUS_ALIGN_RE
.get_or_init(|| {
Regex::new(r"(?m)^(?P<prefix>\s*Auto Drive >[^\n]*?)(?P<spaces>\s+)✶(?P<rest>[^\n]*)$")
.expect("valid auto drive status alignment regex")
})
.replace_all(&text, |caps: &Captures| {
format!("{} ✶{}", &caps["prefix"], &caps["rest"])
})
.into_owned();
AUTO_DRIVE_BANNER_RE
.get_or_init(|| {
Regex::new(
r"(?m)^(?P<indent>\s*)\+(?P<left>-+)\s+✶\s*(?P<title>[^\-\n]+?)\s+(?P<right>-+)\+$",
)
.expect("valid auto drive banner regex")
})
.replace_all(&text, |caps: &Captures| {
let indent = &caps["indent"];
let title = caps["title"].trim();
format!("{indent}+----------------------------- ✶ {title} -----------------------------+")
})
.into_owned()
}
fn normalize_agent_history_details(text: String) -> String {
let mut blank_next_detail_line = false;
let mut result = String::new();
for line in text.lines() {
let mut transformed = line.to_string();
let mut handled_detail = false;
for (token, label) in [("progress:", "detail:"), ("result:", "detail:")] {
if let Some(idx) = line.find(token) {
let prefix = &line[..idx];
let label = label;
let prefix_end = idx + token.len();
if let Some(tail_start) = line.rfind("| |") {
let tail = &line[tail_start..];
let span_width = tail_start.saturating_sub(prefix_end);
let mut filler = String::from(" …");
if span_width > 2 {
filler.push_str(&" ".repeat(span_width - 2));
}
transformed = format!("{prefix}{label}{filler}{tail}");
} else {
transformed = format!("{}{label} …", prefix);
}
handled_detail = true;
break;
}
}
if handled_detail {
blank_next_detail_line = true;
} else if blank_next_detail_line {
if let Some(blanked) = blank_between_pipes(line) {
transformed = blanked;
}
blank_next_detail_line = false;
}
result.push_str(&transformed);
result.push('\n');
}
if !text.ends_with('\n') {
result.pop();
}
result
}
fn blank_between_pipes(line: &str) -> Option<String> {
let (first_pipe, last_pipe) = (line.find('|')?, line.rfind('|')?);
if last_pipe <= first_pipe {
return None;
}
let indent = &line[..first_pipe + 1];
let tail = &line[last_pipe..];
let span_width = last_pipe.saturating_sub(first_pipe + 1);
Some(format!("{indent}{}{tail}", " ".repeat(span_width)))
}
fn normalize_spacer_rows(text: String) -> String {
let ends_with_newline = text.ends_with('\n');
let mut lines: Vec<String> = Vec::new();