supercode-frontend-tui 0.4.6

Attachable terminal frontend primitives for Supercode SDK runtimes.
Documentation
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use serde_json::Value;
use supercode::frontend::FrontendEvent;
use supercode::ChatMessage;
use supercode_frontend_tui::terminal::palette::ColorCapabilities;
use supercode_frontend_tui::terminal::palette::ColorLevel;
use supercode_frontend_tui::transcript::CellState;
use supercode_frontend_tui::transcript::TranscriptKind;
use supercode_frontend_tui::transcript::TranscriptModel;
use supercode_frontend_tui::transcript::TranscriptRenderer;

fn fixture() -> (u64, Vec<ChatMessage>, Vec<FrontendEvent>) {
    let value: Value =
        serde_json::from_str(include_str!("fixtures/late_attach.json")).expect("valid fixture");
    let cursor = value["history_cursor"].as_u64().expect("history cursor");
    let history = serde_json::from_value(value["history"].clone()).expect("history messages");
    let events = serde_json::from_value(value["events"].clone()).expect("frontend events");
    (cursor, history, events)
}

fn capabilities() -> ColorCapabilities {
    ColorCapabilities {
        level: ColorLevel::TrueColor,
        color_enabled: true,
    }
}

fn snapshot(model: &TranscriptModel, width: u16) -> String {
    let area = Rect::new(0, 0, width, 40);
    let mut buffer = Buffer::empty(area);
    TranscriptRenderer::new(model, capabilities()).render_buffer(area, &mut buffer);
    (0..area.height)
        .map(|y| {
            (0..area.width)
                .map(|x| buffer[(x, y)].symbol())
                .collect::<String>()
                .trim_end()
                .to_string()
        })
        .collect::<Vec<_>>()
        .join("\n")
        .trim_end()
        .to_string()
}

#[test]
fn recorded_late_attach_replays_then_streams_without_duplicates_across_resizes() {
    let (cursor, history, events) = fixture();
    let mut model = TranscriptModel::from_history(&history, cursor);

    let attached = snapshot(&model, 80);
    assert_eq!(
        attached,
        "✓ You\n  Continue the migration without repeating the prior answer.\n\n✓ Assistant\n  Earlier context is loaded and the source session remains unchanged."
    );

    for event in &events[..4] {
        model.apply_event(event);
    }
    let first_resize = snapshot(&model, 40);
    assert_eq!(
        first_resize,
        "✓ You\n  Continue the migration without\n  repeating the prior answer.\n\n✓ Assistant\n  Earlier context is loaded and the\n  source session remains unchanged.\n\n✓ Command: exec_command\n  171 tests passed\n\n◌ Assistant\n  ## Result\n  The attach boundary keeps one\n  canonical transcript while live output\n  arrives.\n\n  • history is replayed once\n  • streaming updates one assistant cell\n\n  │ Check            │ State           │\n  ├──────────────────┼─────────────────┤\n  │ source session   │ unchanged       │\n  │ live stream      │ attached        │"
    );

    for event in &events[4..] {
        model.apply_event(event);
    }
    let second_resize = snapshot(&model, 64);
    assert_eq!(
        second_resize,
        "✓ You\n  Continue the migration without repeating the prior answer.\n\n✓ Assistant\n  Earlier context is loaded and the source session remains\n  unchanged.\n\n✓ Command: exec_command\n  171 tests passed\n\n✓ Assistant\n  ## Result\n  The attach boundary keeps one canonical transcript while live\n  output arrives.\n\n  • history is replayed once\n  • streaming updates one assistant cell\n\n  │ Check                        │ State                       │\n  ├──────────────────────────────┼─────────────────────────────┤\n  │ source session               │ unchanged                   │\n  │ live stream                  │ attached                    │\n\n  ┌─ rust\n  │ fn resume_losslessly() -> bool { true }\n  └─\n  The final answer is deliberately long enough to reflow when\n  the terminal width changes a second time."
    );

    assert_eq!(
        model
            .cells()
            .iter()
            .filter(|cell| cell.kind == TranscriptKind::User)
            .count(),
        1,
        "the event at the canonical cursor must not duplicate the prompt"
    );
    assert_eq!(
        model
            .cells()
            .iter()
            .filter(|cell| cell.kind == TranscriptKind::Assistant)
            .count(),
        2,
        "one replayed answer plus one live answer"
    );
    assert_eq!(model.cells().last().unwrap().state, CellState::Complete);
}