mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
Merge branch 'code-branch-20251217-230845'
This commit is contained in:
@@ -2355,7 +2355,7 @@ impl App<'_> {
|
||||
}
|
||||
SlashCommand::Demo => {
|
||||
if let AppState::Chat { widget } = &mut self.app_state {
|
||||
widget.handle_demo_command();
|
||||
widget.handle_demo_command(command_args);
|
||||
}
|
||||
}
|
||||
// Prompt-expanding commands should have been handled in submit_user_message
|
||||
|
||||
@@ -13997,7 +13997,21 @@ impl ChatWidget<'_> {
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
pub(crate) fn handle_demo_command(&mut self) {
|
||||
pub(crate) fn handle_demo_command(&mut self, command_args: String) {
|
||||
let trimmed_args = command_args.trim();
|
||||
if !trimmed_args.is_empty() {
|
||||
if self.handle_demo_auto_drive_card_background_palette(trimmed_args) {
|
||||
self.request_redraw();
|
||||
return;
|
||||
}
|
||||
|
||||
self.history_push_plain_state(history_cell::new_warning_event(format!(
|
||||
"demo: unknown args '{trimmed_args}' (try: /demo auto drive card)",
|
||||
)));
|
||||
self.request_redraw();
|
||||
return;
|
||||
}
|
||||
|
||||
use ratatui::style::Modifier as RtModifier;
|
||||
use ratatui::style::Style as RtStyle;
|
||||
use ratatui::text::Span;
|
||||
@@ -14436,6 +14450,96 @@ impl ChatWidget<'_> {
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
fn handle_demo_auto_drive_card_background_palette(&mut self, args: &str) -> bool {
|
||||
if !Self::demo_command_is_auto_drive_card_backgrounds(args) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let (r, g, b) = crate::colors::color_to_rgb(crate::colors::background());
|
||||
let luminance = (0.2126 * r as f32 + 0.7152 * g as f32 + 0.0722 * b as f32) / 255.0;
|
||||
let theme_label = if luminance < 0.5 { "dark" } else { "light" };
|
||||
|
||||
self.history_push_plain_state(history_cell::plain_message_state_from_lines(
|
||||
vec![
|
||||
ratatui::text::Line::from("Auto Drive card — ANSI-16 background palette"),
|
||||
ratatui::text::Line::from(format!(
|
||||
"Theme context: {theme_label} (based on current /theme background)",
|
||||
)),
|
||||
ratatui::text::Line::from(
|
||||
"Tip: switch /theme (dark/light) and rerun to compare.".to_string(),
|
||||
),
|
||||
],
|
||||
HistoryCellType::Notice,
|
||||
));
|
||||
|
||||
use ratatui::style::Color;
|
||||
const PALETTE: &[(Color, &str)] = &[
|
||||
(Color::Black, "Black"),
|
||||
(Color::Red, "Red"),
|
||||
(Color::Green, "Green"),
|
||||
(Color::Yellow, "Yellow"),
|
||||
(Color::Blue, "Blue"),
|
||||
(Color::Magenta, "Magenta"),
|
||||
(Color::Cyan, "Cyan"),
|
||||
(Color::Gray, "Gray"),
|
||||
(Color::DarkGray, "DarkGray"),
|
||||
(Color::LightRed, "LightRed"),
|
||||
(Color::LightGreen, "LightGreen"),
|
||||
(Color::LightYellow, "LightYellow"),
|
||||
(Color::LightBlue, "LightBlue"),
|
||||
(Color::LightMagenta, "LightMagenta"),
|
||||
(Color::LightCyan, "LightCyan"),
|
||||
(Color::White, "White"),
|
||||
];
|
||||
|
||||
for (idx, (bg, name)) in PALETTE.iter().enumerate() {
|
||||
let ordinal = idx + 1;
|
||||
let goal = format!("ANSI-16 bg {ordinal:02}: {name}");
|
||||
let mut auto_drive_card = history_cell::AutoDriveCardCell::new(Some(goal));
|
||||
auto_drive_card.disable_reveal();
|
||||
auto_drive_card.set_background_override(Some(*bg));
|
||||
auto_drive_card.push_action(
|
||||
"Queued smoke tests across agents",
|
||||
AutoDriveActionKind::Info,
|
||||
);
|
||||
auto_drive_card.push_action(
|
||||
"Warning: macOS shard flaked",
|
||||
AutoDriveActionKind::Warning,
|
||||
);
|
||||
auto_drive_card.push_action(
|
||||
"Action required: retry or pause run",
|
||||
AutoDriveActionKind::Error,
|
||||
);
|
||||
auto_drive_card.set_status(AutoDriveStatus::Paused);
|
||||
self.history_push(auto_drive_card);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn demo_command_is_auto_drive_card_backgrounds(args: &str) -> bool {
|
||||
let normalized = args.trim().to_ascii_lowercase();
|
||||
let simplified = normalized.replace(['-', '_'], " ");
|
||||
let tokens: std::collections::HashSet<&str> = simplified.split_whitespace().collect();
|
||||
if tokens.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let wants_auto_drive = (tokens.contains("auto") && tokens.contains("drive"))
|
||||
|| tokens.contains("autodrive")
|
||||
|| tokens.contains("auto-drive");
|
||||
let wants_card = tokens.contains("card") || tokens.contains("cards");
|
||||
let wants_background = tokens.contains("bg")
|
||||
|| tokens.contains("background")
|
||||
|| tokens.contains("backgrounds")
|
||||
|| tokens.contains("color")
|
||||
|| tokens.contains("colors")
|
||||
|| tokens.contains("colour")
|
||||
|| tokens.contains("colours");
|
||||
|
||||
wants_auto_drive && (wants_card || wants_background)
|
||||
}
|
||||
|
||||
fn add_perf_output(&mut self, text: String) {
|
||||
let mut lines: Vec<ratatui::text::Line<'static>> = Vec::new();
|
||||
lines.push(ratatui::text::Line::from("performance".dim()));
|
||||
|
||||
@@ -15,7 +15,9 @@ use super::{HistoryCell, HistoryCellType, ToolCellStatus};
|
||||
use crate::card_theme;
|
||||
use crate::glitch_animation::{gradient_multi, mix_rgb};
|
||||
use crate::gradient_background::{GradientBackground, RevealRender};
|
||||
use crate::util::buffer::fill_rect;
|
||||
use crate::colors;
|
||||
use crate::theme::{palette_mode, PaletteMode};
|
||||
use code_common::elapsed::format_duration_digital;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Rect;
|
||||
@@ -97,6 +99,7 @@ pub(crate) struct AutoDriveCardCell {
|
||||
actions: Vec<AutoDriveAction>,
|
||||
cell_key: Option<String>,
|
||||
signature: Option<String>,
|
||||
background_override: Option<Color>,
|
||||
reveal_started_at: Option<Instant>,
|
||||
first_action_at: Option<Instant>,
|
||||
completion_message: Option<String>,
|
||||
@@ -105,16 +108,21 @@ pub(crate) struct AutoDriveCardCell {
|
||||
|
||||
impl AutoDriveCardCell {
|
||||
pub(crate) fn new(goal: Option<String>) -> Self {
|
||||
let reveal_started_at = active_auto_drive_theme()
|
||||
.theme
|
||||
.reveal
|
||||
.map(|_| Instant::now());
|
||||
let reveal_started_at = if palette_mode() == PaletteMode::Ansi16 {
|
||||
None
|
||||
} else {
|
||||
active_auto_drive_theme()
|
||||
.theme
|
||||
.reveal
|
||||
.map(|_| Instant::now())
|
||||
};
|
||||
let cell = Self {
|
||||
goal: goal.and_then(Self::normalize_text),
|
||||
status: AutoDriveStatus::Running,
|
||||
actions: Vec::new(),
|
||||
cell_key: None,
|
||||
signature: None,
|
||||
background_override: None,
|
||||
reveal_started_at,
|
||||
first_action_at: None,
|
||||
completion_message: None,
|
||||
@@ -152,6 +160,14 @@ impl AutoDriveCardCell {
|
||||
self.status = status;
|
||||
}
|
||||
|
||||
pub(crate) fn set_background_override(&mut self, background: Option<Color>) {
|
||||
self.background_override = background;
|
||||
}
|
||||
|
||||
pub(crate) fn disable_reveal(&mut self) {
|
||||
self.reveal_started_at = None;
|
||||
}
|
||||
|
||||
pub(crate) fn push_action(&mut self, text: impl Into<String>, kind: AutoDriveActionKind) {
|
||||
let now = Instant::now();
|
||||
let base = self.first_action_at.get_or_insert(now);
|
||||
@@ -1038,6 +1054,15 @@ impl AutoDriveCardCell {
|
||||
}
|
||||
|
||||
fn celebration_background_style() -> Style {
|
||||
if palette_mode() == PaletteMode::Ansi16 {
|
||||
let fg = if is_dark_theme_active() {
|
||||
Color::White
|
||||
} else {
|
||||
Color::Black
|
||||
};
|
||||
return Style::default().fg(fg);
|
||||
}
|
||||
|
||||
Style::default().fg(Color::Rgb(255, 255, 255))
|
||||
}
|
||||
|
||||
@@ -1059,21 +1084,44 @@ impl AutoDriveCardCell {
|
||||
}
|
||||
let style = auto_drive_card_style();
|
||||
|
||||
let reveal = self.reveal_progress().and_then(|(progress, theme)| {
|
||||
theme.theme.reveal.map(|config| RevealRender {
|
||||
progress,
|
||||
variant: config.variant,
|
||||
intro_light: !is_dark_theme_active(),
|
||||
})
|
||||
});
|
||||
|
||||
let draw_width = area.width - 2;
|
||||
let render_area = Rect {
|
||||
width: draw_width,
|
||||
..area
|
||||
};
|
||||
|
||||
GradientBackground::render(buf, render_area, &style.gradient, style.text_primary, reveal);
|
||||
if let Some(bg) = self.background_override {
|
||||
fill_rect(
|
||||
buf,
|
||||
render_area,
|
||||
Some(' '),
|
||||
Style::default().fg(style.text_primary).bg(bg),
|
||||
);
|
||||
} else if palette_mode() == PaletteMode::Ansi16 {
|
||||
fill_rect(
|
||||
buf,
|
||||
render_area,
|
||||
Some(' '),
|
||||
Style::default()
|
||||
.fg(style.text_primary)
|
||||
.bg(style.gradient.left),
|
||||
);
|
||||
} else {
|
||||
let reveal = self.reveal_progress().and_then(|(progress, theme)| {
|
||||
theme.theme.reveal.map(|config| RevealRender {
|
||||
progress,
|
||||
variant: config.variant,
|
||||
intro_light: !is_dark_theme_active(),
|
||||
})
|
||||
});
|
||||
GradientBackground::render(
|
||||
buf,
|
||||
render_area,
|
||||
&style.gradient,
|
||||
style.text_primary,
|
||||
reveal,
|
||||
);
|
||||
}
|
||||
|
||||
let rows = self.build_card_rows(render_area.width, &style);
|
||||
let lines = rows_to_lines(&rows, &style, render_area.width);
|
||||
|
||||
@@ -7,6 +7,8 @@ use crate::card_theme;
|
||||
use crate::card_theme::{CardThemeDefinition, GradientSpec};
|
||||
use crate::colors;
|
||||
use crate::gradient_background::GradientBackground;
|
||||
use crate::theme::{palette_mode, PaletteMode};
|
||||
use crate::util::buffer::fill_rect;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct CardStyle {
|
||||
@@ -60,16 +62,34 @@ impl CardRow {
|
||||
|
||||
pub(crate) const CARD_ACCENT_WIDTH: usize = 2;
|
||||
|
||||
pub(crate) fn agent_card_style(_write_enabled: Option<bool>) -> CardStyle {
|
||||
// Agent batches should share the calmer green theme regardless of write access so
|
||||
// mixed read/write runs stay visually consistent.
|
||||
pub(crate) fn agent_card_style(write_enabled: Option<bool>) -> CardStyle {
|
||||
// Agent batches share the calmer green theme in full-color terminals.
|
||||
// In ANSI-16 mode we swap to solid backgrounds for legibility (green for read,
|
||||
// yellow when write mode is enabled).
|
||||
let is_dark = is_dark_theme_active();
|
||||
let definition = if is_dark {
|
||||
card_theme::agent_read_only_dark_theme()
|
||||
} else {
|
||||
card_theme::agent_read_only_light_theme()
|
||||
};
|
||||
style_from_theme(definition, is_dark)
|
||||
let mut style = style_from_theme(definition, is_dark);
|
||||
|
||||
if palette_mode() == PaletteMode::Ansi16 {
|
||||
let bg = if write_enabled == Some(true) {
|
||||
if is_dark {
|
||||
Color::Yellow
|
||||
} else {
|
||||
Color::LightYellow
|
||||
}
|
||||
} else if is_dark {
|
||||
Color::Green
|
||||
} else {
|
||||
Color::LightGreen
|
||||
};
|
||||
apply_ansi16_background(&mut style, bg, is_dark);
|
||||
}
|
||||
|
||||
style
|
||||
}
|
||||
|
||||
pub(crate) fn browser_card_style() -> CardStyle {
|
||||
@@ -79,7 +99,14 @@ pub(crate) fn browser_card_style() -> CardStyle {
|
||||
} else {
|
||||
card_theme::browser_light_theme()
|
||||
};
|
||||
style_from_theme(definition, is_dark)
|
||||
let mut style = style_from_theme(definition, is_dark);
|
||||
|
||||
if palette_mode() == PaletteMode::Ansi16 {
|
||||
let bg = if is_dark { Color::Red } else { Color::LightRed };
|
||||
apply_ansi16_background(&mut style, bg, is_dark);
|
||||
}
|
||||
|
||||
style
|
||||
}
|
||||
|
||||
pub(crate) fn auto_drive_card_style() -> CardStyle {
|
||||
@@ -89,7 +116,28 @@ pub(crate) fn auto_drive_card_style() -> CardStyle {
|
||||
} else {
|
||||
card_theme::auto_drive_light_theme()
|
||||
};
|
||||
style_from_theme(definition, is_dark)
|
||||
let mut style = style_from_theme(definition, is_dark);
|
||||
|
||||
if palette_mode() == PaletteMode::Ansi16 {
|
||||
let bg = if is_dark { Color::Magenta } else { Color::LightMagenta };
|
||||
apply_ansi16_background(&mut style, bg, is_dark);
|
||||
}
|
||||
|
||||
style
|
||||
}
|
||||
|
||||
fn apply_ansi16_background(style: &mut CardStyle, background: Color, is_dark: bool) {
|
||||
style.gradient = GradientSpec {
|
||||
left: background,
|
||||
right: background,
|
||||
bias: 0.0,
|
||||
};
|
||||
|
||||
let text = if is_dark { Color::White } else { Color::Black };
|
||||
style.accent_fg = text;
|
||||
style.text_primary = text;
|
||||
style.text_secondary = text;
|
||||
style.title_text = text;
|
||||
}
|
||||
|
||||
pub(crate) fn web_search_card_style() -> CardStyle {
|
||||
@@ -152,7 +200,21 @@ fn adjust_gradient(gradient: GradientSpec, _is_dark: bool) -> GradientSpec {
|
||||
}
|
||||
|
||||
pub(crate) fn fill_card_background(buf: &mut Buffer, area: Rect, style: &CardStyle) {
|
||||
GradientBackground::render(buf, area, &style.gradient, style.text_primary, None);
|
||||
if palette_mode() == PaletteMode::Ansi16
|
||||
&& style.gradient.left == style.gradient.right
|
||||
&& !matches!(style.gradient.left, Color::Rgb(_, _, _))
|
||||
{
|
||||
fill_rect(
|
||||
buf,
|
||||
area,
|
||||
Some(' '),
|
||||
Style::default()
|
||||
.bg(style.gradient.left)
|
||||
.fg(style.text_primary),
|
||||
);
|
||||
} else {
|
||||
GradientBackground::render(buf, area, &style.gradient, style.text_primary, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn pad_icon(icon: &str, width: usize) -> String {
|
||||
|
||||
@@ -99,6 +99,8 @@ typically start multiple agents. They require a task/problem description.
|
||||
|
||||
- `/demo`: populate the chat history with assorted sample cells (available in
|
||||
dev and perf builds for UI testing).
|
||||
- `/demo auto drive card`: render the Auto Drive card once for each ANSI-16
|
||||
background color so you can compare theme contrast.
|
||||
- `/test-approval`: test approval request (available in debug builds only).
|
||||
|
||||
Implementation Notes
|
||||
|
||||
Reference in New Issue
Block a user