codex-wrangler 1.3.0

Linux/X11/i3 tray switcher for live coding-agent TUI sessions
use std::cmp::Ordering;

use crate::contract::{Harness, Work};

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Card {
    pub harness: Harness,
    pub thread: String,
    pub name: Option<String>,
    pub cwd: String,
    pub tile_preview: String,
    pub work: Work,
    pub window: Option<u32>,
    pub workspace: Option<u32>,
    pub updated_at_ms: i64,
}

impl Card {
    pub fn assert_lawful(&self) {
        assert_eq!(
            self.work == Work::Closed,
            self.window.is_none(),
            "Closed must be exactly terminal absence"
        );
    }
}

pub fn snip(text: &str, limit: usize) -> String {
    let mut flat = String::with_capacity(text.len().min(limit + 1));
    for word in text.split_whitespace() {
        if !flat.is_empty() {
            flat.push(' ');
        }
        flat.push_str(word);
        if flat.chars().count() > limit {
            break;
        }
    }
    let mut chars = flat.chars();
    let head = chars.by_ref().take(limit).collect::<String>();
    if chars.next().is_some() {
        format!("{head}")
    } else {
        head
    }
}

impl Ord for Card {
    fn cmp(&self, other: &Self) -> Ordering {
        rank(self.work)
            .cmp(&rank(other.work))
            .then_with(|| other.updated_at_ms.cmp(&self.updated_at_ms))
            .then_with(|| self.harness.cmp(&other.harness))
            .then_with(|| self.thread.cmp(&other.thread))
    }
}

impl PartialOrd for Card {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

const fn rank(work: Work) -> u8 {
    match work {
        Work::Error => 0,
        Work::Input => 1,
        Work::Goal => 2,
        Work::Turn => 3,
        Work::Sleep | Work::Done => 4,
        Work::Closed => 5,
    }
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Census {
    pub cards: Vec<Card>,
    pub fault: Option<String>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn preview_contraction_is_unicode_safe_and_whitespace_canonical() {
        assert_eq!(snip("  alpha\n βeta   gamma ", 8), "alpha βe…");
    }

    #[test]
    fn stopped_live_sessions_share_recency_while_closed_remains_last() {
        let card = |thread: &str, work, updated_at_ms| Card {
            harness: Harness::Codex,
            thread: thread.to_owned(),
            name: None,
            cwd: "/work".to_owned(),
            tile_preview: String::new(),
            work,
            window: (work != Work::Closed).then_some(1),
            workspace: None,
            updated_at_ms,
        };
        let mut cards = [
            card("old-sleep", Work::Sleep, 10),
            card("new-done", Work::Done, 20),
            card("newest-closed", Work::Closed, 30),
        ];
        cards.sort();
        assert_eq!(
            cards.map(|card| card.thread),
            ["new-done", "old-sleep", "newest-closed"]
        );
    }
}