lean-ctx 3.5.2

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
pub fn try_glab_pattern(cmd: &str, output: &str) -> Option<String> {
    let parts: Vec<&str> = cmd.split_whitespace().collect();
    if parts.is_empty() || parts[0] != "glab" {
        return None;
    }
    if parts.len() < 2 {
        return None;
    }

    match parts[1] {
        "issue" => try_glab_issue(parts.get(2).copied(), output),
        "mr" => try_glab_mr(parts.get(2).copied(), output),
        "ci" => try_glab_ci(parts.get(2).copied(), output),
        _ => None,
    }
}

fn try_glab_issue(subcommand: Option<&str>, output: &str) -> Option<String> {
    match subcommand.unwrap_or("") {
        "list" => Some(compress_table_output("glab issues", output)),
        "view" => Some(compress_detail_output("issue", output)),
        _ => None,
    }
}

fn try_glab_mr(subcommand: Option<&str>, output: &str) -> Option<String> {
    match subcommand.unwrap_or("") {
        "list" => Some(compress_table_output("glab MRs", output)),
        "view" => Some(compress_detail_output("MR", output)),
        _ => None,
    }
}

fn try_glab_ci(subcommand: Option<&str>, output: &str) -> Option<String> {
    match subcommand.unwrap_or("") {
        "status" | "list" | "view" => Some(compress_ci_output(output)),
        _ => None,
    }
}

fn compress_table_output(label: &str, output: &str) -> String {
    let lines: Vec<&str> = output.lines().collect();
    if lines.is_empty() {
        return format!("{label}: (empty)");
    }
    let count = lines.len().saturating_sub(1);
    let mut result = format!("{label} ({count}):\n");
    for line in &lines {
        let trimmed = line.trim();
        if !trimmed.is_empty() {
            result.push_str(&format!("  {trimmed}\n"));
        }
    }
    result
}

fn compress_detail_output(kind: &str, output: &str) -> String {
    let mut result = String::new();
    let mut in_body = false;
    let mut body_lines = 0;
    const MAX_BODY_LINES: usize = 30;

    for line in output.lines() {
        let trimmed = line.trim();
        if trimmed.starts_with("title:")
            || trimmed.starts_with("state:")
            || trimmed.starts_with("author:")
            || trimmed.starts_with("labels:")
            || trimmed.starts_with("milestone:")
            || trimmed.starts_with("assignees:")
            || trimmed.starts_with("created:")
            || trimmed.starts_with("updated:")
        {
            result.push_str(&format!("{trimmed}\n"));
            in_body = false;
        } else if trimmed == "--" || trimmed.starts_with("---") {
            in_body = true;
            result.push_str("---\n");
        } else if in_body {
            body_lines += 1;
            if body_lines <= MAX_BODY_LINES {
                result.push_str(&format!("{line}\n"));
            } else if body_lines == MAX_BODY_LINES + 1 {
                result.push_str(&format!("... ({kind} body truncated)\n"));
            }
        } else if !trimmed.is_empty() {
            result.push_str(&format!("{trimmed}\n"));
        }
    }
    result
}

fn compress_ci_output(output: &str) -> String {
    let mut result = String::from("CI pipeline:\n");
    for line in output.lines() {
        let trimmed = line.trim();
        if trimmed.is_empty() {
            continue;
        }
        result.push_str(&format!("  {trimmed}\n"));
    }
    result
}