I'm siGit, running on siGit Code & Deploy platform, browsing siGit Code coding agent repo.
Move the startup check results from the splash into the chat info lines
The splash now shows the wordmark and caption only. The checks still gate it, and their results print under the quote as Account, Models, Workspace and Tools lines. The static rainbow banner in the chat history is gone, since the splash already shows it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Seto Elkahfi committed
Oct 28, 2026 at 09:31 UTC
aa548fbe88000090a9b4d9277b583d445862e71a
2 files changed
+17
-93
crates/cli/src/chat.rs
+17
-92
@@ -529,9 +529,9 @@ mod tui {
529
};
530
use crate::program_status::{Reporter, Status};
531
use crate::session_store::SessionEntry;
532
- use crate::splash::{self, BANNER_ART, Phase, Splash, Wordmark};
532
+ use crate::splash::{self, Phase, Splash, Wordmark};
533
use crate::startup::{
534
- self, CHECK_ROWS, Check, Checks, Report, account_check, models_check, tools_check,
534
+ self, Check, Checks, Report, account_check, models_check, tools_check,
535
workspace_check,
536
};
537
use ratatui::{
@@ -551,8 +551,6 @@ mod tui {
551
User,
552
Assistant,
553
System,
554
- /// rainbow-colored banner art
555
- Banner,
554
/// a collapsible tool-call entry (`text` holds the title line)
555
Tool,
556
}
@@ -602,16 +600,6 @@ mod tui {
600
}
601
}
602
605
- fn banner(text: impl Into<String>) -> Self {
606
- Self {
607
- role: Role::Banner,
608
- text: text.into(),
609
- think_block: None,
610
- tool_detail: None,
611
- tool_result: None,
612
- }
613
- }
614
-
603
fn tool_call(title: impl Into<String>, detail: impl Into<String>) -> Self {
604
Self {
605
role: Role::Tool,
@@ -1133,16 +1121,20 @@ mod tui {
1121
}
1122
}
1123
1136
- /// switch to chat phase and show the welcome banner
1124
+ /// switch to chat phase and show the welcome notes
1125
fn finish_loading(&mut self) {
1126
self.is_loading = false;
1139
- for line in BANNER_ART.lines() {
1140
- self.messages.push(ChatMessage::banner(line));
1141
- }
1142
- self.messages.push(ChatMessage::system(""));
1127
self.messages.push(ChatMessage::system(
1128
"In this world, nothing can be said to be certain, except death and taxes. ~ Pak Sigit",
1129
));
1130
+ for (label, check) in self.checks.rows() {
1131
+ match check {
1132
+ Check::Ok(d) | Check::Note(d) | Check::Warn(d) => self
1133
+ .messages
1134
+ .push(ChatMessage::system(format!("{label}: {d}"))),
1135
+ Check::Pending => {}
1136
+ }
1137
+ }
1138
if self.backend.is_remote() {
1139
self.messages.push(ChatMessage::system(format!(
1140
"Current model: {}",
@@ -2267,11 +2259,10 @@ mod tui {
2259
}
2260
}
2261
2270
- /// The launch splash: the wordmark with the startup checks under it. Too
2271
- /// small a terminal gets the caption and the checks without the art.
2262
+ /// The launch splash: the wordmark with a caption under it. The startup
2263
+ /// checks still gate it, and their results land in the chat's info lines.
2264
+ /// Too small a terminal gets the caption without the art.
2265
fn render_splash(frame: &mut Frame, app: &App, area: ratatui::layout::Rect) {
2273
- const SPINNER: &[&str] = &["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
2274
- const CHECKS: u16 = CHECK_ROWS as u16;
2266
let now = std::time::Instant::now();
2267
let reduced = app.splash.reduced();
2268
let tc = app.splash.truecolor;
@@ -2284,14 +2275,14 @@ mod tui {
2275
let exit = app.splash.exit_progress(now);
2276
let vis = 1.0 - exit;
2277
2287
- // caption, a gap, the checklist
2278
+ // the wordmark, a gap, the caption
2279
let art = app
2280
.splash
2281
.banner
2282
.size(area.width)
2292
- .filter(|(_, h)| area.height >= h + 2 + 1 + CHECKS);
2283
+ .filter(|(_, h)| area.height >= h + 2);
2284
let art_h = art.map_or(0, |(_, h)| h + 1);
2294
- let total = art_h + 1 + 1 + CHECKS;
2285
+ let total = art_h + 1;
2286
let top = area.y + area.height.saturating_sub(total) / 2;
2287
let rect = |y: u16, h: u16| ratatui::layout::Rect::new(area.x, y, area.width, h);
2288
@@ -2315,56 +2306,6 @@ mod tui {
2306
)))
2307
.alignment(ratatui::layout::Alignment::Center);
2308
frame.render_widget(caption, rect(caption_y, 1));
2318
-
2319
- // The checklist fades in once the flame has caught.
2320
- let shown = vis * ((ms - 700.0) / 300.0).clamp(0.0, 1.0);
2321
- if shown <= 0.0 {
2322
- return;
2323
- }
2324
- let spin = SPINNER[(ms as usize / 100) % SPINNER.len()];
2325
- let rows: Vec<(String, Line)> = app
2326
- .checks
2327
- .rows()
2328
- .into_iter()
2329
- .map(|(label, check)| {
2330
- let (glyph, detail, glyph_rgb, detail_rgb) = match check {
2331
- Check::Pending => (spin, "…".to_string(), splash::EMBER, splash::MUTED),
2332
- Check::Ok(d) => ("✓", d.clone(), splash::INK, splash::INK),
2333
- Check::Note(d) => ("·", d.clone(), splash::MUTED, splash::MUTED),
2334
- Check::Warn(d) => ("!", d.clone(), splash::EMBER, splash::EMBER),
2335
- };
2336
- let line = Line::from(vec![
2337
- Span::styled(
2338
- format!("{glyph} "),
2339
- Style::default().fg(splash::fade(glyph_rgb, shown, tc)),
2340
- ),
2341
- Span::styled(
2342
- format!("{label:<9} "),
2343
- Style::default().fg(splash::fade(splash::MUTED, shown, tc)),
2344
- ),
2345
- Span::styled(
2346
- detail.clone(),
2347
- Style::default().fg(splash::fade(detail_rgb, shown, tc)),
2348
- ),
2349
- ]);
2350
- (format!("{glyph} {label:<9} {detail}"), line)
2351
- })
2352
- .collect();
2353
- // One left edge for every line, centred as a block.
2354
- let width = rows
2355
- .iter()
2356
- .map(|(plain, _)| plain.chars().count())
2357
- .max()
2358
- .unwrap_or(0) as u16;
2359
- let x = area.x + area.width.saturating_sub(width) / 2;
2360
- for (i, (_, line)) in rows.into_iter().enumerate() {
2361
- let y = caption_y + 2 + i as u16;
2362
- if y >= area.y + area.height {
2363
- break;
2364
- }
2365
- let r = ratatui::layout::Rect::new(x, y, area.width.saturating_sub(x - area.x), 1);
2366
- frame.render_widget(Paragraph::new(line), r);
2367
- }
2309
}
2310
2311
fn render_loading_title(frame: &mut Frame, app: &App, area: ratatui::layout::Rect) {
@@ -2563,22 +2504,6 @@ mod tui {
2504
lines.push(Line::from(Span::styled(format!(" {entry_line}"), dim)));
2505
}
2506
}
2566
- Role::Banner => {
2567
- let palette = [
2568
- Color::Red,
2569
- Color::Yellow,
2570
- Color::Green,
2571
- Color::Cyan,
2572
- Color::Blue,
2573
- Color::Magenta,
2574
- ];
2575
- let mut spans = Vec::new();
2576
- for (i, ch) in msg.text.chars().enumerate() {
2577
- let color = palette[i % palette.len()];
2578
- spans.push(Span::styled(ch.to_string(), Style::default().fg(color)));
2579
- }
2580
- lines.push(Line::from(spans));
2581
- }
2507
Role::System => {
2508
for text_line in msg.text.split('\n') {
2509
let trimmed = text_line.trim();
crates/cli/src/splash.rs
-1
@@ -54,7 +54,6 @@ const RAMP: [Rgb; 4] = [
54
];
55
pub(crate) const INK: Rgb = [0xf3, 0xf4, 0xf6];
56
pub(crate) const MUTED: Rgb = [0x6b, 0x72, 0x80];
57
-pub(crate) const EMBER: Rgb = RAMP[2];
57
58
/// Heat per digit. 0 and 9 are the densest in the art, 7 and 1 the thinnest.
59
const HEAT: [f32; 10] = [1.0, 0.2, 0.45, 0.55, 0.5, 0.4, 0.65, 0.15, 0.8, 1.0];