omk 0.5.0

A Rust runtime for Kimi CLI. Turns prompts into proof-backed engineering runs with gates, worktrees, and replay.
Documentation
use ratatui::{
    layout::Rect,
    style::Style,
    text::{Line, Span},
    widgets::Paragraph,
    Frame,
};

use crate::vis::engine::model::{PaneModel, WorkerStatus};
use crate::vis::engine::theme::Theme;

pub fn render(model: &PaneModel, frame: &mut Frame, area: Rect, theme: Theme) {
    if model.workers.is_empty() {
        return;
    }

    let mut lines = vec![Line::from(vec![Span::styled(
        "workers:",
        Style::default().fg(theme.fg_emphasis()),
    )])];

    let mut workers: Vec<_> = model.workers.values().collect();
    workers.sort_by(|a, b| a.worker_id.cmp(&b.worker_id));
    for w in workers {
        let (sym, color) = match w.status {
            WorkerStatus::Running => ('', theme.status_running()),
            WorkerStatus::Done => ('', theme.status_done()),
            WorkerStatus::Failed => ('', theme.status_failed()),
        };

        let elapsed = w.elapsed(model.now);
        let elapsed_str = format_duration(elapsed);

        let task = w.message.as_ref().unwrap_or(&w.task);

        lines.push(Line::from(vec![
            Span::styled(format!("{sym} "), Style::default().fg(color)),
            Span::styled(
                format!("{:10} ", &w.worker_id),
                Style::default().fg(theme.fg_normal()),
            ),
            Span::styled(
                format!("{:24} ", truncate(task, 24)),
                Style::default().fg(theme.fg_normal()),
            ),
            Span::styled(elapsed_str, Style::default().fg(theme.fg_muted())),
        ]));
    }

    frame.render_widget(Paragraph::new(lines), area);
}

fn format_duration(d: std::time::Duration) -> String {
    let secs = d.as_secs();
    let mins = secs / 60;
    let s = secs % 60;
    format!("{:02}:{:02}", mins, s)
}

fn truncate(s: &str, max_chars: usize) -> String {
    if s.chars().count() > max_chars {
        let idx = s
            .char_indices()
            .nth(max_chars - 1)
            .map(|(i, _)| i)
            .unwrap_or(s.len());
        format!("{}", &s[..idx])
    } else {
        s.to_string()
    }
}