feat(tui): add usage overlay and sidebar for displaying usage statistics and tasks

feat(tui): implement status bar with connection and turn state indicators
feat(tui): create workflow panel for agent status and progress visualization
feat(web): introduce web frontend interface with static file serving
feat(ws): add WebSocket interface for real-time communication and session management
This commit is contained in:
asepharyana committed 2026-07-20 09:04:57 +07:00
1 parent bceba665c0
commit da2ed6da25
454 files changed
+13979 -29539

No files matched your search

@@ -0,0 +1,62 @@
//! Overlay: Rewind / session history — shows recent messages and lets the user
//! pick a point to rewind the transcript back to.
use crate::view::theme::Theme;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Paragraph};
use ratatui::Frame;
use zesdex_domain::core::Role;
/// Render the Rewind overlay.
pub fn render(
frame: &mut Frame,
area: ratatui::layout::Rect,
block: Block<'static>,
state: &crate::state::AppStateRest,
) {
let block = block
.title(Span::styled(
" Rewind ",
Style::default()
.fg(Theme::ACCENT_ORANGE)
.add_modifier(Modifier::BOLD),
))
.border_style(Style::default().fg(Theme::ACCENT_ORANGE));
let mut lines: Vec<Line> = vec![
Line::from(Span::styled(
" Use ↑↓ to navigate, Enter to rewind to that point",
Style::default().fg(Theme::TEXT_DIM),
)),
Line::from(Span::raw("")),
];
let messages = &state.transcript_cache.messages;
if messages.is_empty() {
lines.push(Line::from(Span::styled(
" No messages in current session.",
Style::default().fg(Theme::TEXT_DIM),
)));
} else {
let start = if messages.len() > 8 { messages.len() - 8 } else { 0 };
for msg in &messages[start..] {
let role_str = match msg.role {
Role::User => "User",
Role::Assistant => "Asst",
Role::System => "Sys",
Role::Tool => "Tool",
};
let preview: String = msg.content.chars().take(70).collect();
lines.push(Line::from(Span::styled(
format!(" [{role_str}] {preview}"),
Style::default().fg(if msg.role == Role::User { Theme::INFO } else { Theme::TEXT }),
)));
}
if messages.len() > 8 {
lines.push(Line::from(Span::styled(
format!(" ... and {} more messages", messages.len() - 8),
Style::default().fg(Theme::TEXT_DIM),
)));
}
}
let paragraph = Paragraph::new(lines).block(block);
frame.render_widget(paragraph, area);
}