diff --git a/crates/codegen/kigi-pager-render/src/glyphs.rs b/crates/codegen/kigi-pager-render/src/glyphs.rs index db38510..ead71c6 100644 --- a/crates/codegen/kigi-pager-render/src/glyphs.rs +++ b/crates/codegen/kigi-pager-render/src/glyphs.rs @@ -218,10 +218,12 @@ pub fn diamond_hollow_char() -> char { /// 1-column ASCII spinner (`|`, `/`, `-`, `\`) on legacy ConHost. /// /// The U+2800 Braille Patterns block is not part of CP437 and renders as -/// tofu on the legacy console raster font, so the turn-status line, the -/// MCP-connecting chip, the image-viewer loader, and the `/btw` overlay -/// all fall back to the classic ASCII spinner there. Every frame in both -/// sets is exactly 1 column so the surrounding layout never shifts. +/// tofu on the legacy console raster font, so the starting-session row, +/// the MCP-connecting chip, the image-viewer loader, and the `/btw` +/// overlay all fall back to the classic ASCII spinner there. Every frame +/// in both sets is exactly 1 column so the surrounding layout never +/// shifts. (The turn-status "Waiting for response…" line uses +/// [`moon_spinner_frames`] instead.) pub fn braille_spinner_frames() -> &'static [&'static str] { const FANCY: &[&str] = &[ "\u{280b}", "\u{2819}", "\u{2839}", "\u{2838}", "\u{283c}", "\u{2834}", "\u{2826}", @@ -235,6 +237,34 @@ pub fn braille_spinner_frames() -> &'static [&'static str] { } } +/// Moon-phase spinner frames (`πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜`) normally; the ASCII +/// spinner on legacy ConHost. +/// +/// The turn-status "Waiting for response…" line reuses the official +/// kimi-cli's lunation animation (rich's `moon` spinner) β€” one full +/// lunation per cycle, matching the welcome-screen moon logo. Emoji +/// frames are 2 columns wide; the caller measures the rendered frame +/// (`spinner_str.width()`) so the layout adapts. Legacy ConHost's raster +/// font has no emoji, so it falls back to the 1-column ASCII spinner. +pub fn moon_spinner_frames() -> &'static [&'static str] { + const FANCY: &[&str] = &[ + "\u{1f311}", + "\u{1f312}", + "\u{1f313}", + "\u{1f314}", + "\u{1f315}", + "\u{1f316}", + "\u{1f317}", + "\u{1f318}", + ]; + const FALLBACK: &[&str] = &["|", "/", "-", "\\"]; + if is_legacy_windows_console() { + FALLBACK + } else { + FANCY + } +} + /// Pulsing dot progress-spinner frames (`β‹… : βΈ¬ ⁙`) normally; a quiet /// 1-column dot cycle (`.`, `:`, `Β·`) on legacy ConHost. /// diff --git a/crates/codegen/kigi-tui/src/views/turn_status.rs b/crates/codegen/kigi-tui/src/views/turn_status.rs index b114769..3e5200c 100644 --- a/crates/codegen/kigi-tui/src/views/turn_status.rs +++ b/crates/codegen/kigi-tui/src/views/turn_status.rs @@ -351,13 +351,13 @@ pub fn render_turn_status( // ── Build components ── // While a tool is blocked on a permission prompt or `ask_user_question`, - // swap the running braille spinner for a pulsing `β—†`. Same animation - // shape the drain-blocked and plan-approval indicators already use, - // so every "your turn" status reads with one consistent visual cue. + // swap the spinning moon for a pulsing `β—†`. Same animation shape the + // drain-blocked and plan-approval indicators already use, so every + // "your turn" status reads with one consistent visual cue. let spinner_str = if is_pending_user_input { format!("{} ", crate::glyphs::diamond_filled()) } else { - let frames = crate::glyphs::braille_spinner_frames(); + let frames = crate::glyphs::moon_spinner_frames(); let frame_idx = (tick / SPINNER_DIVISOR) as usize % frames.len(); format!("{} ", frames[frame_idx]) };