lean-ctx 3.5.12

Context Runtime for AI Agents with CCP. 57 MCP tools, 10 read modes, 95+ compression patterns, cross-session memory (CCP), persistent AI knowledge with temporal facts + contradiction detection, multi-agent context sharing + diaries, LITM-aware positioning, AAAK compact format, adaptive compression with Thompson Sampling bandits. Supports 24 AI tools. Reduces LLM token consumption by up to 99%.
Documentation
use crate::core::config;
use crate::core::theme;

pub fn cmd_theme(args: &[String]) {
    let sub = args.first().map_or("list", std::string::String::as_str);
    let r = theme::rst();
    let b = theme::bold();
    let d = theme::dim();

    match sub {
        "list" => {
            let cfg = config::Config::load();
            let active = cfg.theme.as_str();
            println!();
            println!("  {b}Available themes:{r}");
            println!("  {ln}", ln = "".repeat(40));
            for name in theme::PRESET_NAMES {
                let marker = if *name == active { " ◀ active" } else { "" };
                let Some(t) = theme::from_preset(name) else {
                    continue;
                };
                let preview = format!(
                    "{p}██{r}{s}██{r}{a}██{r}{sc}██{r}{w}██{r}",
                    p = t.primary.fg(),
                    s = t.secondary.fg(),
                    a = t.accent.fg(),
                    sc = t.success.fg(),
                    w = t.warning.fg(),
                );
                println!("  {preview}  {b}{name:<12}{r}{d}{marker}{r}");
            }
            if let Some(path) = theme::theme_file_path() {
                if path.exists() {
                    let custom = theme::load_theme("_custom_");
                    let preview = format!(
                        "{p}██{r}{s}██{r}{a}██{r}{sc}██{r}{w}██{r}",
                        p = custom.primary.fg(),
                        s = custom.secondary.fg(),
                        a = custom.accent.fg(),
                        sc = custom.success.fg(),
                        w = custom.warning.fg(),
                    );
                    let marker = if active == "custom" {
                        " ◀ active"
                    } else {
                        ""
                    };
                    println!("  {preview}  {b}{:<12}{r}{d}{marker}{r}", custom.name);
                }
            }
            println!();
            println!("  {d}Set theme: lean-ctx theme set <name>{r}");
            println!();
        }
        "set" => {
            if args.len() < 2 {
                eprintln!("Usage: lean-ctx theme set <name>");
                std::process::exit(1);
            }
            let name = &args[1];
            if theme::from_preset(name).is_none() && name != "custom" {
                eprintln!(
                    "Unknown theme '{name}'. Available: {}",
                    theme::PRESET_NAMES.join(", ")
                );
                std::process::exit(1);
            }
            let mut cfg = config::Config::load();
            cfg.theme.clone_from(name);
            match cfg.save() {
                Ok(()) => {
                    let t = theme::load_theme(name);
                    println!("  {sc}{r} Theme set to {b}{name}{r}", sc = t.success.fg());
                    let preview = t.gradient_bar(0.75, 30);
                    println!("  {preview}");
                }
                Err(e) => eprintln!("Error: {e}"),
            }
        }
        "export" => {
            let cfg = config::Config::load();
            let t = theme::load_theme(&cfg.theme);
            println!("{}", t.to_toml());
        }
        "import" => {
            if args.len() < 2 {
                eprintln!("Usage: lean-ctx theme import <path>");
                std::process::exit(1);
            }
            let path = std::path::Path::new(&args[1]);
            if !path.exists() {
                eprintln!("File not found: {}", args[1]);
                std::process::exit(1);
            }
            match std::fs::read_to_string(path) {
                Ok(content) => match toml::from_str::<theme::Theme>(&content) {
                    Ok(imported) => match theme::save_theme(&imported) {
                        Ok(()) => {
                            let mut cfg = config::Config::load();
                            cfg.theme = "custom".to_string();
                            let _ = cfg.save();
                            println!(
                                "  {sc}{r} Imported theme '{name}' → ~/.lean-ctx/theme.toml",
                                sc = imported.success.fg(),
                                name = imported.name,
                            );
                            println!("  Config updated: theme = custom");
                        }
                        Err(e) => eprintln!("Error saving theme: {e}"),
                    },
                    Err(e) => eprintln!("Invalid theme file: {e}"),
                },
                Err(e) => eprintln!("Error reading file: {e}"),
            }
        }
        "preview" => {
            let name = args.get(1).map_or("default", std::string::String::as_str);
            let Some(t) = theme::from_preset(name) else {
                eprintln!("Unknown theme: {name}");
                std::process::exit(1);
            };
            println!();
            println!(
                "  {icon} {title}  {d}Theme Preview: {name}{r}",
                icon = t.header_icon(),
                title = t.brand_title(),
            );
            println!("  {ln}", ln = t.border_line(50));
            println!();
            println!(
                "  {b}{sc} 1.2M      {r}  {b}{sec} 87.3%     {r}  {b}{wrn} 4,521    {r}  {b}{acc} $12.50   {r}",
                sc = t.success.fg(),
                sec = t.secondary.fg(),
                wrn = t.warning.fg(),
                acc = t.accent.fg(),
            );
            println!("  {d} tokens saved   compression    commands       USD saved{r}");
            println!();
            println!(
                "  {b}{txt}Gradient Bar{r}      {bar}",
                txt = t.text.fg(),
                bar = t.gradient_bar(0.85, 30),
            );
            println!(
                "  {b}{txt}Sparkline{r}         {spark}",
                txt = t.text.fg(),
                spark = t.gradient_sparkline(&[20, 40, 30, 80, 60, 90, 70]),
            );
            println!();
            println!("  {top}", top = t.box_top(50));
            println!(
                "  {side}  {b}{txt}Box content with themed borders{r}                  {side_r}",
                side = t.box_side(),
                side_r = t.box_side(),
                txt = t.text.fg(),
            );
            println!("  {bot}", bot = t.box_bottom(50));
            println!();
        }
        _ => {
            eprintln!("Usage: lean-ctx theme [list|set|export|import|preview]");
            std::process::exit(1);
        }
    }
}