hematite-cli 0.8.2

Senior SysAdmin, Network Admin, Data Analyst, and Software Engineer living in your terminal. A high-precision local AI agent harness for LM Studio, Ollama, and other local OpenAI-compatible runtimes that runs 100% on your own silicon. Reads repos, edits files, runs builds, inspects full network state and workstation telemetry, and runs real Python/JS for data analysis.
Documentation
//! Grounded Output Truncation Module.
//! Ports the "Middle-Truncation" patterns from Codex-RS to ensure
//! Hematite preserves exit codes and headers while providing line metadata.
pub fn formatted_truncate(content: &str, max_bytes: usize) -> String {
    if content.len() <= max_bytes {
        return content.to_string();
    }

    let total_lines = content.lines().count();
    let truncated = truncate_middle(content, max_bytes);

    format!(
        "[TRUNCATED: total lines: {}]\n{}\n[... middle truncated to fit budget ...]\n{}",
        total_lines, truncated.head, truncated.tail
    )
}

pub struct TruncatedOutput {
    pub head: String,
    pub tail: String,
}

/// Truncate a string by keeping the beginning and end, removing the middle.
/// Ensures UTF-8 safety by finding valid character boundaries.
pub fn truncate_middle(content: &str, max_bytes: usize) -> TruncatedOutput {
    if content.len() <= max_bytes {
        return TruncatedOutput {
            head: content.to_string(),
            tail: String::new(),
        };
    }

    // Keep 40% at the start, 40% at the end (roughly).
    let head_size = (max_bytes as f32 * 0.4) as usize;
    let tail_size = (max_bytes as f32 * 0.4) as usize;

    // Find valid UTF-8 boundaries
    let head_boundary = find_valid_boundary_forward(content, head_size);
    let tail_boundary = find_valid_boundary_backward(content, content.len() - tail_size);

    TruncatedOutput {
        head: content[..head_boundary].to_string(),
        tail: content[tail_boundary..].to_string(),
    }
}

/// Returns the longest prefix of `s` that is at most `max_bytes` long and ends on a UTF-8 boundary.
pub fn safe_head(s: &str, max_bytes: usize) -> &str {
    let end = find_valid_boundary_forward(s, max_bytes.min(s.len()));
    &s[..end]
}

/// Returns a suffix of `s` containing at most `max_bytes` bytes, starting on a UTF-8 boundary.
pub fn safe_tail(s: &str, max_bytes: usize) -> &str {
    if s.len() <= max_bytes {
        return s;
    }
    let offset = s.len() - max_bytes;
    // Walk forward from offset to find the nearest char boundary.
    let start = (offset..=s.len())
        .find(|&i| s.is_char_boundary(i))
        .unwrap_or(s.len());
    &s[start..]
}

fn find_valid_boundary_forward(content: &str, target: usize) -> usize {
    let mut pos = target;
    while pos > 0 && !content.is_char_boundary(pos) {
        pos -= 1;
    }
    pos
}

fn find_valid_boundary_backward(content: &str, target: usize) -> usize {
    let mut pos = target;
    while pos < content.len() && !content.is_char_boundary(pos) {
        pos += 1;
    }
    pos
}

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

    #[test]
    fn test_middle_truncation() {
        let input = "1234567890";
        let result = truncate_middle(input, 4);
        // 4 bytes budget -> 40% is 1.6 bytes -> 1 byte head, 1 byte tail
        assert_eq!(result.head, "1");
        assert_eq!(result.tail, "0");
    }

    #[test]
    fn test_utf8_boundary_safety() {
        let input = "πŸ¦€πŸ¦€πŸ¦€πŸ¦€πŸ¦€"; // 每δΈͺθžƒθŸΉ 4 ε­—θŠ‚, ζ€»ε…± 20 ε­—θŠ‚
        let result = truncate_middle(input, 10);
        // 10 bytes budget -> 4 byte head, 4 byte tail
        assert_eq!(result.head, "πŸ¦€");
        assert_eq!(result.tail, "πŸ¦€");
    }
}