bctx-weave 0.1.29

bctx-weave — FilterMesh lens pipeline, CLI interception, domain compression
Documentation
use super::log_dedup;
use forge::signal::compactor;
use once_cell::sync::Lazy;
use regex::Regex;

// journalctl timestamp + host prefix: "May 05 12:34:56 hostname"
static JOURNAL_PREFIX_RE: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(?m)^[A-Z][a-z]{2} \d{2} \d{2}:\d{2}:\d{2} \S+ ").unwrap());
// systemctl status decorative lines (dots, dashes)
#[allow(dead_code)]
static STATUS_DOTS_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^[●○]\s+").unwrap());

// ── journalctl ────────────────────────────────────────────────────────────────

pub fn compress_journalctl(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Strip verbose timestamp+hostname prefix from each line
    let stripped = JOURNAL_PREFIX_RE.replace_all(&cleaned, "");
    // Apply log dedup (collapses repeated lines)
    let deduped = log_dedup(&stripped);
    // Tail at 150 lines if still long
    let lines: Vec<&str> = deduped.lines().collect();
    if lines.len() > 150 {
        let omitted = lines.len() - 150;
        return format!(
            "... [{} earlier lines omitted] ...\n{}",
            omitted,
            lines[lines.len() - 150..].join("\n")
        );
    }
    deduped
}

// ── systemctl status ──────────────────────────────────────────────────────────

pub fn compress_systemctl_status(raw: &str) -> String {
    let cleaned = compactor::normalise(raw);
    // Keep: service name line, Active/Loaded/Main PID lines, recent log lines
    // Strip verbose CGroup tree entries beyond depth 1
    let mut in_cgroup = false;
    let kept: Vec<&str> = cleaned
        .lines()
        .filter(|l| {
            let t = l.trim();
            if t.starts_with("CGroup:") || t.starts_with("└─") || t.starts_with("├─") {
                in_cgroup = true;
            }
            if in_cgroup && t.starts_with("└─") {
                return true; // Keep first cgroup entry
            }
            if in_cgroup && (t.starts_with("") || t.starts_with("├─")) {
                return false; // Strip nested cgroup entries
            }
            true
        })
        .collect();
    compactor::collapse_blanks(&kept.join("\n"))
}

// ── systemctl (generic) ───────────────────────────────────────────────────────

pub fn compress_systemctl(subcmd: &str, raw: &str) -> String {
    let sub = subcmd.trim();
    if sub.starts_with("status") {
        return compress_systemctl_status(raw);
    }
    if sub.starts_with("list-units") || sub.starts_with("list-timers") {
        // Truncate long unit lists
        let cleaned = compactor::normalise(raw);
        let lines: Vec<&str> = cleaned.lines().collect();
        if lines.len() > 40 {
            return format!(
                "{}\n... [{} more units] ...",
                lines[..40].join("\n"),
                lines.len() - 40
            );
        }
        return cleaned;
    }
    // start/stop/restart/enable/disable — keep status output
    compactor::normalise(raw)
}

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

    #[test]
    fn journalctl_strips_timestamps() {
        let raw = "May 05 12:34:56 myhost nginx[1234]: starting\nMay 05 12:34:57 myhost nginx[1234]: ready\n";
        let out = compress_journalctl(raw);
        assert!(!out.contains("May 05 12:34:56 myhost"), "{out}");
        assert!(out.contains("starting") || out.contains("nginx"), "{out}");
    }

    #[test]
    fn journalctl_deduplicates_repeats() {
        let raw = (0..20)
            .map(|_| "May 05 12:34:56 h svc: connection refused\n")
            .collect::<String>();
        let out = compress_journalctl(&raw);
        assert!(out.contains("repeated"), "{out}");
    }

    #[test]
    fn systemctl_status_keeps_active_line() {
        let raw = "● nginx.service - A high performance web server\n   Loaded: loaded (/lib/systemd/system/nginx.service)\n   Active: active (running) since Mon 2024-01-01\n   Main PID: 1234\n";
        let out = compress_systemctl_status(raw);
        assert!(out.contains("Active"), "{out}");
    }
}