Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions crates/aimee_main/src/banner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,26 +195,35 @@ fn render_chips_slice(
y: u16,
width: u16,
chips: &[(&str, &str)],
color_offset: usize,
_color_offset: usize,
) {
// Warp pill style: key on a filled accent pill, role in muted text —
// one accent per chip, no rainbow cycling.
const PILL_ACCENTS: [ratatui::style::Color; 4] = [
theme::palette::RATATUI_CYAN,
theme::palette::RATATUI_VIOLET,
theme::palette::RATATUI_MAGENTA,
theme::palette::RATATUI_LIME,
];
let mut cursor = x;
for (index, (key, label)) in chips.iter().enumerate() {
let accent = PILL_ACCENTS[index % PILL_ACCENTS.len()];
let key_text = format!(" {key} ");
let label_text = format!(" {label} ");
let key_style = Style::default()
.fg(theme::palette::RATATUI_VOID)
.bg(theme::banner_line_ratatui(color_offset + index))
.add_modifier(Modifier::BOLD);
let label_style = Style::default()
.fg(theme::banner_line_ratatui(color_offset + index))
.bg(theme::palette::RATATUI_VOID)
.bg(accent)
.add_modifier(Modifier::BOLD);
buf.set_stringn(cursor, y, &key_text, width as usize, key_style);
cursor = cursor.saturating_add(key_text.chars().count() as u16);
buf.set_stringn(cursor, y, &label_text, width as usize, label_style);
let label_text = format!(" {label} ");
buf.set_stringn(
cursor,
y,
&label_text,
width as usize,
Style::default().fg(theme::palette::RATATUI_MUTED),
);
cursor = cursor.saturating_add(label_text.chars().count() as u16);
buf.set_stringn(cursor, y, " ", width as usize, Style::default());
cursor = cursor.saturating_add(2);
if cursor >= x.saturating_add(width) {
break;
}
Expand Down
70 changes: 30 additions & 40 deletions crates/aimee_main/src/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ use nu_ansi_term::{Color, Style};
use crate::display_constants::markers;
use crate::utils::humanize_number;

// Nerd font symbols — left prompt
const DIR_SYMBOL: &str = "\u{ea83}"; // 󪃃 folder icon
const BRANCH_SYMBOL: &str = "\u{f418}"; // branch icon
const SUCCESS_SYMBOL: &str = "\u{f013e}"; // 󰄾 chevron

// Nerd font symbols — right prompt (ZSH rprompt)
const AGENT_SYMBOL: &str = "\u{f167a}";
const MODEL_SYMBOL: &str = "\u{ec19}";

/// Warp's prompt opens with a solid accent block (two half-block glyphs).
const WARP_INPUT_BLOCK: &str = "\u{258c}\u{258c}"; // ▌▌

/// Terminal width at which the reasoning effort label switches from the
/// compact three-letter form (e.g. `MED`) to the full uppercase label
/// (e.g. `MEDIUM`). Matches [`crate::zsh::rprompt`] so the CLI and zsh
Expand Down Expand Up @@ -62,20 +60,14 @@ impl AimeePrompt {
}

pub fn render_prompt_left(&self) -> Cow<'_, str> {
// Left prompt layout:
// Warp-style input block:
//
// AGENT_NAME 󪃃 dir branch
// 󰄾
// ▌▌ dir branch
//
// Colors:
// agent → bold white (identifies the active agent)
// dir → bold cyan
// branch → bold green
// chevron → bold green

let dir_style = crate::theme::dir_style();
let branch_style = crate::theme::branch_style();
let chevron_style = crate::theme::chevron_style();
// Colors (Warp):
// block → accent blue, bold
// dir → near-white
// branch → dim muted

let current_dir = self
.cwd
Expand All @@ -84,36 +76,36 @@ impl AimeePrompt {
.map(String::from)
.unwrap_or_else(|| markers::EMPTY.to_string());

let mut result = String::with_capacity(160);
let mut result = String::with_capacity(120);

// Ratatui slash-command chips sit above the directory line so every
// interactive turn shows :aimee / :muse / :sage without a full redraw.
writeln!(result, "{}", crate::banner::chips_ansi()).unwrap();

// Directory — folder icon + name, bold cyan
// Warp's input starts with a solid accent block on the prompt line.
write!(
result,
"{}",
dir_style.paint(format!("{DIR_SYMBOL} {current_dir}"))
crate::theme::warp_input_block_style().paint(WARP_INPUT_BLOCK)
)
.unwrap();

// Git branch — branch icon + name, bold green (only when present and
// different from the directory name, matching existing behaviour)
// Directory — plain near-white after the block.
write!(
result,
" {}",
crate::theme::prompt_dir_style().paint(&current_dir)
)
.unwrap();

// Git branch — dim muted (Warp shows branch quietly).
if let Some(branch) = self.git_branch.as_deref()
&& branch != current_dir
&& branch != current_dir.as_str()
{
write!(
result,
" {}",
branch_style.paint(format!("{BRANCH_SYMBOL} {branch}"))
crate::theme::prompt_branch_style().paint(branch)
)
.unwrap();
}

// Second line: success chevron
write!(result, "\n{} ", chevron_style.paint(SUCCESS_SYMBOL)).unwrap();

Cow::Owned(result)
}

Expand Down Expand Up @@ -297,22 +289,20 @@ mod tests {
let prompt = AimeePrompt::default();
let actual = prompt.render_prompt_left();

// Starship directory icon present
assert!(actual.contains(DIR_SYMBOL));
// Starship success chevron present
assert!(actual.contains(SUCCESS_SYMBOL));
assert!(actual.contains(":aimee"));
assert!(actual.contains(":muse"));
// Warp input block leads the line.
assert!(actual.contains(WARP_INPUT_BLOCK));
// Test cwd "." has no file_name → placeholder marker renders.
assert!(actual.contains(markers::EMPTY));
// No chip row above the prompt anymore (Warp-quiet).
assert!(!actual.contains(":muse"));
}

Comment on lines +292 to 299

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Prompt tests check partial output

The modified tests assert selected substrings instead of defining the required fixture, actual, and complete expected prompt values. This leaves spacing, line structure, and ordering unverified; please update both prompt tests to compare the full rendered output.

Rule Used: # AGENTS.md

House rules for coding agents in the ... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

#[test]
fn test_render_prompt_left_with_branch() {
let prompt = AimeePrompt { git_branch: Some("main".to_string()), ..Default::default() };
let actual = prompt.render_prompt_left();

// Agent name is on the right prompt, not the left
// Branch icon and name present
assert!(actual.contains(BRANCH_SYMBOL));
// Branch renders quietly after the directory.
assert!(actual.contains("main"));
}

Expand Down
15 changes: 15 additions & 0 deletions crates/aimee_main/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,21 @@ pub fn chevron_style() -> Style {
Style::new().bold().fg(palette::LIME)
}

/// Style for the Warp-style solid input block at the start of the prompt.
pub fn warp_input_block_style() -> Style {
Style::new().bold().fg(palette::CYAN)
}

/// Directory text after the input block (Warp: plain body color).
pub fn prompt_dir_style() -> Style {
Style::new().fg(palette::NEAR_WHITE)
}

/// Git branch text (Warp: quiet, dim).
pub fn prompt_branch_style() -> Style {
Style::new().fg(palette::MUTED)
}

/// Banner line colors cycling Warp blue → violet → magenta → gold.
pub fn banner_line_color(index: usize) -> Color {
match index % 4 {
Expand Down
15 changes: 14 additions & 1 deletion crates/aimee_main/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4838,8 +4838,21 @@ impl<A: API + ConsoleWriter + 'static, F: Fn(AimeeConfig) -> A + Send + Sync> UI
self.writeln(title.display())?;
}
ChatResponseContent::ToolOutput(text) => {
// Warp indents tool payload under the tool header so the
// eye groups output with its TOOL lane line.
writer.finish()?;
self.writeln(text)?;
let indented = text
.lines()
.map(|line| {
if line.trim().is_empty() {
String::from(line)
} else {
format!(" {line}")
}
})
.collect::<Vec<_>>()
.join("\n");
self.writeln(indented)?;
}
ChatResponseContent::Markdown { text, partial: _ } => {
writer.write(&text)?;
Expand Down
5 changes: 3 additions & 2 deletions crates/aimee_spinner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ fn styled_loader_line(
.saturating_sub(WRAP_GUARD_COLUMNS)
.max(MIN_TERMINAL_WIDTH);

let tick = tick.green().to_string();
// Warp accent: tick in Warp blue, label in near-white (not terminal green).
let tick = tick.truecolor(0x01, 0xA4, 0xFF).to_string();
let elapsed = elapsed.white().to_string();
let fixed = format!("{tick} {elapsed}");
let message_width = max_width.saturating_sub(visible_width(&fixed)).max(1);
let message = truncate_to_visible_width(message, message_width)
.green()
.truecolor(0xE6, 0xE6, 0xE6)
.bold()
.to_string();
let styled = format!("{tick} {message} {elapsed}");
Expand Down
Loading