Files
Kigi-CLI/crates/codegen/kigi-tui/src/views/welcome/prompt.rs
T
ZacharyZhang-NY ea0ce9d15f F3: Kimi inference pipeline + full grok cloud-surface excision
Sampler / inference (PRD F3):
- kimi_compat.rs: single adaptation point for the Kimi chat/completions
  dialect (thinking-field mapping, model_id stripping, empty-content
  tool-call message fix, stream_options.include_usage), with kimi-cli
  source citations
- Rate-limit handling reworked for Kimi/Moonshot semantics; UA kigi/{version}
- /models replaces the xAI models-v2 endpoint everywhere; idle model
  refresh carries X-Msh-* device headers only (X-XAI-Token-Auth and
  x-grok-client-mode/CLIENT_MODE_HEADER machinery deleted)

Cloud-surface excision (PRD §5, zero-egress):
- remote/ conversations lane, cli-chat-proxy-types crate, prod/ dir,
  share command, credit bar: deleted (single local session lane;
  paginate() replaces merge_and_paginate)
- Subscription/tier gate stack deleted end-to-end: AppView
  gate/tier/team/ZDR fields, app/subscription.rs watch loop,
  dispatch/billing.rs paywall + SuperGrok upsell, free-usage-exhausted
  chain, tier-restricted commands, GateInfo, RemoteSettings gate fields,
  SettingsUpdateNotification gate fields
- /privacy + coding-data-sharing setting deleted (backed by a dead xAI
  RPC; Kigi is zero-egress — nothing to share or retain remotely)

Auth UX correctness (user-reported):
- Device-flow fixtures now mirror the live Kimi payload shape
  (https://www.kimi.com/code/authorize_device?user_code=..., verified
  against auth.kimi.com); the fabricated auth.kimi.com/device?code=...
  URLs are gone
- open_browser_detached is a no-op under cfg(test): unit tests drove
  wiremock fixture URLs into the real browser (root cause of the
  "garbage mock link" ABCD-1234 tabs)
- Welcome/pager-minimal rebrand: Grok Build -> Kigi, grok.com ->
  kimi.com, "Sign in to Grok" -> "Sign in to Kimi"
2026-07-17 16:05:51 -04:00

120 lines
3.7 KiB
Rust

//! Prompt component — renders the welcome screen prompt using PromptWidget.
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use crate::views::prompt_widget::{PromptInfo, PromptStyle, PromptWidget};
use super::WelcomePromptFocus;
pub fn prompt_inset(compact: bool) -> u16 {
if compact { 0 } else { 2 }
}
/// Render the welcome prompt using the shared PromptWidget.
/// Returns the cursor position and ownership-bearing post-flush output.
#[allow(clippy::too_many_arguments)]
pub fn render_prompt(
area: Rect,
buf: &mut Buffer,
focus: WelcomePromptFocus,
prompt: &mut PromptWidget,
info: &PromptInfo<'_>,
pad_left: u16,
pad_right: u16,
compact: bool,
) -> (
Option<(u16, u16)>,
Option<crate::terminal::overlay::PostFlush>,
) {
let focused = focus == WelcomePromptFocus::Focused;
let style = PromptStyle {
focused,
show_prefix: true,
vpad_top: 1,
compact,
chrome: true,
chrome_pad_left: pad_left,
chrome_pad_right: pad_right,
placeholder_override: Some("Type a message..."),
..PromptStyle::default()
};
// Inset the prompt area so the selection box border sits over dark background.
// In compact mode, no inset (prompt_inset returns 0) to match session layout.
let inset = prompt_inset(compact);
let inset_area = Rect {
x: area.x + inset,
y: area.y,
width: area.width.saturating_sub(inset * 2),
height: area.height,
};
let result = prompt.draw(buf, inset_area, None, &style, Some(info));
(result.cursor_pos, result.post_flush_escapes.map(Into::into))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::terminal::image::{GraphicsProtocol, set_protocol_for_test};
use crossterm::Command;
fn png() -> [u8; 8] {
[0x89, b'P', b'N', b'G', b'\r', b'\n', 0x1a, b'\n']
}
#[test]
fn prompt_post_flush_keeps_ownership_when_plain_bytes_are_appended() {
let _guard = set_protocol_for_test(GraphicsProtocol::Kitty);
crate::terminal::overlay::reset_owner();
let _ = crate::terminal::overlay::static_image(&png(), 20, 10, 0, 0, 71)
.unwrap()
.commit();
let area = Rect::new(0, 0, 80, 3);
let mut buf = Buffer::empty(area);
let mut prompt = PromptWidget::new();
let info = PromptInfo {
model_name: "test",
flags: &[],
multiline: false,
};
let (_, post_flush) = render_prompt(
area,
&mut buf,
WelcomePromptFocus::Focused,
&mut prompt,
&info,
2,
2,
false,
);
let mut post_flush = post_flush.expect("welcome clear");
let mut cursor_bytes = String::new();
let _ = crate::terminal::SetPointerCursor.write_ansi(&mut cursor_bytes);
assert!(!cursor_bytes.is_empty());
post_flush.append_plain(&cursor_bytes);
assert!(post_flush.as_str().contains("a=d"));
assert!(post_flush.as_str().ends_with(cursor_bytes.as_str()));
assert!(
!crate::terminal::overlay::static_image(&png(), 20, 10, 0, 0, 71)
.unwrap()
.as_str()
.contains("a=t"),
"constructing welcome output must not commit its clear"
);
let mut emitted = Vec::new();
post_flush.write_to(&mut emitted).unwrap();
assert!(
crate::terminal::overlay::static_image(&png(), 20, 10, 0, 0, 71)
.unwrap()
.as_str()
.contains("a=t"),
"writing welcome output must commit its clear"
);
}
}