lean-ctx 3.1.3

Context Runtime for AI Agents with CCP. 42 MCP tools, 10 read modes, 90+ 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 std::path::PathBuf;

const LOG_FILENAME: &str = "slow-commands.log";
const MAX_LOG_ENTRIES: usize = 500;

fn slow_log_path() -> Option<PathBuf> {
    dirs::home_dir().map(|h| h.join(".lean-ctx").join(LOG_FILENAME))
}

pub fn record(command: &str, duration_ms: u128, exit_code: i32) {
    let path = match slow_log_path() {
        Some(p) => p,
        None => return,
    };

    if let Some(parent) = path.parent() {
        let _ = std::fs::create_dir_all(parent);
    }

    let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
    let entry = format!("{ts}\t{duration_ms}ms\texit:{exit_code}\t{command}\n");

    let existing = std::fs::read_to_string(&path).unwrap_or_default();
    let lines: Vec<&str> = existing.lines().collect();

    let kept = if lines.len() >= MAX_LOG_ENTRIES {
        &lines[lines.len() - MAX_LOG_ENTRIES + 1..]
    } else {
        &lines[..]
    };

    let mut content = kept.join("\n");
    if !content.is_empty() {
        content.push('\n');
    }
    content.push_str(&entry);

    let _ = std::fs::write(&path, content);
}

pub fn list() -> String {
    let path = match slow_log_path() {
        Some(p) => p,
        None => return "Cannot determine home directory.".to_string(),
    };

    match std::fs::read_to_string(&path) {
        Ok(content) if !content.trim().is_empty() => {
            let lines: Vec<&str> = content.lines().collect();
            let header = format!(
                "Slow command log ({} entries)  [~/.lean-ctx/{}]\n{}\n",
                lines.len(),
                LOG_FILENAME,
                "".repeat(72)
            );
            let table: String = lines
                .iter()
                .map(|l| {
                    let parts: Vec<&str> = l.splitn(4, '\t').collect();
                    if parts.len() == 4 {
                        format!(
                            "{:<20}  {:>8}  {:>8}  {}",
                            parts[0], parts[1], parts[2], parts[3]
                        )
                    } else {
                        l.to_string()
                    }
                })
                .collect::<Vec<_>>()
                .join("\n");
            format!("{header}{table}\n")
        }
        Ok(_) => "No slow commands recorded yet.".to_string(),
        Err(_) => format!("No slow log found at ~/.lean-ctx/{LOG_FILENAME}"),
    }
}

pub fn clear() -> String {
    let path = match slow_log_path() {
        Some(p) => p,
        None => return "Cannot determine home directory.".to_string(),
    };

    if !path.exists() {
        return "No slow log to clear.".to_string();
    }

    match std::fs::remove_file(&path) {
        Ok(()) => format!("Cleared ~/.lean-ctx/{LOG_FILENAME}"),
        Err(e) => format!("Error clearing log: {e}"),
    }
}