codex-cli-captain 0.0.10

Codex-Cli-Captain runtime, installer, and MCP server for Codex CLI.
pub(crate) fn summarize_text_for_visibility(text: &str, max_chars: usize) -> String {
    let normalized = text.split_whitespace().collect::<Vec<_>>().join(" ");
    if normalized.chars().count() <= max_chars {
        return normalized;
    }
    normalized
        .chars()
        .take(max_chars.saturating_sub(3))
        .collect::<String>()
        + "..."
}

fn is_policy_or_code_sensitive_text(text: &str) -> bool {
    let lower = text.to_ascii_lowercase();
    [
        "error",
        "failed",
        "blocked",
        "fallback",
        "reclaim",
        "reassign",
        "restart",
        "ghost",
        "sentinel",
        "check-install",
        "evidence_path",
        "evidence paths",
        "unauthorized",
        "permission denied",
    ]
    .iter()
    .any(|needle| lower.contains(needle))
        || text.contains("```")
        || text.contains('{')
        || text.contains('}')
}

fn is_removable_filler_token(token: &str) -> bool {
    let word = token
        .trim_matches(|character: char| !character.is_ascii_alphabetic())
        .to_ascii_lowercase();
    matches!(
        word.as_str(),
        "a" | "an"
            | "the"
            | "that"
            | "this"
            | "these"
            | "those"
            | "very"
            | "really"
            | "basically"
            | "simply"
            | "just"
            | "please"
            | "likely"
            | "probably"
            | "generally"
            | "actually"
            | "currently"
    )
}

pub(crate) fn compact_prose_for_visibility(text: &str, max_chars: usize) -> String {
    let normalized = text.split_whitespace().collect::<Vec<_>>().join(" ");
    if normalized.is_empty() || is_policy_or_code_sensitive_text(&normalized) {
        return summarize_text_for_visibility(&normalized, max_chars);
    }

    let compact = normalized
        .split_whitespace()
        .filter(|token| !is_removable_filler_token(token))
        .collect::<Vec<_>>()
        .join(" ");
    let compact = if compact.trim().is_empty() {
        normalized
    } else {
        compact
    };
    summarize_text_for_visibility(&compact, max_chars)
}

fn normalize_compact_text(text: &str) -> String {
    text.split_whitespace().collect::<Vec<_>>().join(" ")
}

pub(crate) fn compact_prompt_text(text: &str, max_chars: usize) -> String {
    summarize_text_for_visibility(text, max_chars.max(24))
}

pub(crate) fn prompt_fields_match(left: &str, right: &str) -> bool {
    !left.trim().is_empty() && normalize_compact_text(left) == normalize_compact_text(right)
}

#[cfg(test)]
mod tests {
    use super::{compact_prose_for_visibility, summarize_text_for_visibility};

    #[test]
    fn compact_prose_removes_filler_but_preserves_code_like_tokens() {
        let text =
            "The implementation simply updates rust/ccc-mcp/src/main.rs and keeps run_id exact.";
        let compact = compact_prose_for_visibility(text, 160);

        assert!(!compact.contains(" simply "));
        assert!(compact.contains("rust/ccc-mcp/src/main.rs"));
        assert!(compact.contains("run_id"));
    }

    #[test]
    fn compact_prose_does_not_rewrite_policy_or_error_text() {
        let text = "Ghost/Sentinel fallback blocked because error status must stay exact.";
        assert_eq!(
            compact_prose_for_visibility(text, 160),
            summarize_text_for_visibility(text, 160)
        );
    }
}