yog 0.0.1

yog: a balls-oriented session manager for lernie loops (egui frontend)
Documentation
//! Enumeration order, skipping, the in-progress query, and the live tail.

use super::{AGENT, write_msg, write_response};
use crate::transcript::{EntryKind, build};
use tempfile::tempdir;

#[test]
fn entries_are_ordered_by_filename_counter() {
    let dir = tempdir().unwrap();
    for n in ["003-c.md", "001-a.md", "002-b.md"] {
        write_msg(dir.path(), n, b"x");
    }
    let t = build(dir.path(), AGENT, false);
    let names: Vec<&str> = t.entries.iter().map(|e| e.name.as_str()).collect();
    assert_eq!(names, ["001-a.md", "002-b.md", "003-c.md"]);
}

#[test]
fn non_file_entries_are_skipped() {
    let dir = tempdir().unwrap();
    write_msg(dir.path(), "001-a.md", b"x");
    std::fs::create_dir_all(
        dir.path()
            .join("agents")
            .join(AGENT)
            .join("messages")
            .join("subdir"),
    )
    .unwrap();
    assert_eq!(build(dir.path(), AGENT, false).entries.len(), 1);
}

#[test]
fn absent_messages_dir_yields_empty_transcript() {
    let dir = tempdir().unwrap();
    assert!(build(dir.path(), AGENT, false).entries.is_empty());
}

#[test]
fn tool_in_progress_true_until_result_committed() {
    let dir = tempdir().unwrap();
    write_msg(
        dir.path(),
        "001-m.json",
        br#"[{"type":"tool_use","id":"t1","name":"N","input":{}}]"#,
    );
    assert!(build(dir.path(), AGENT, false).tool_in_progress("t1"));
    write_msg(
        dir.path(),
        "002-tool.json",
        br#"{"tool_use_id":"t1","content":"ok"}"#,
    );
    assert!(!build(dir.path(), AGENT, false).tool_in_progress("t1"));
}

#[test]
fn live_tail_appended_only_when_in_flight() {
    let dir = tempdir().unwrap();
    write_msg(dir.path(), "001-a.md", b"hi");
    write_response(
        dir.path(),
        1,
        b"{\"type\":\"content_delta\",\"index\":0,\"delta\":{\"text_delta\":\"streaming\"}}\n",
    );
    // not in flight → the tail is never merged
    assert_eq!(build(dir.path(), AGENT, false).entries.len(), 1);
    // in flight → folded tail appended as the trailing Streaming entry
    let t = build(dir.path(), AGENT, true);
    assert_eq!(t.entries.len(), 2);
    assert!(matches!(&t.entries[1].kind, EntryKind::Streaming { text } if text == "streaming"));
}

#[test]
fn in_flight_without_stream_text_appends_nothing() {
    let dir = tempdir().unwrap();
    write_msg(dir.path(), "001-a.md", b"hi");
    // no steps/ tree at all → the fold returns None → nothing appended
    assert_eq!(build(dir.path(), AGENT, true).entries.len(), 1);
}