remem-ai 0.6.39

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
pub(super) fn event_skip_reason(
    adapter: &dyn crate::adapter::ToolAdapter,
    event: &crate::adapter::ParsedHookEvent,
    has_commit_evidence: bool,
) -> Option<&'static str> {
    event_skip_reason_with_codex_bash_enabled(
        adapter,
        event,
        has_commit_evidence,
        codex_bash_observe_enabled(),
    )
}

fn event_skip_reason_with_codex_bash_enabled(
    adapter: &dyn crate::adapter::ToolAdapter,
    event: &crate::adapter::ParsedHookEvent,
    has_commit_evidence: bool,
    codex_bash_enabled: bool,
) -> Option<&'static str> {
    if adapter.should_skip(event) {
        return Some("adapter_skip");
    }
    if event.tool_name != "Bash" {
        return None;
    }

    let command = event
        .tool_input
        .as_ref()
        .and_then(|value| value.get("command"))
        .and_then(serde_json::Value::as_str);
    let supported_commit = command.is_some_and(crate::git_evidence::is_supported_commit_command);

    if adapter.name() == "codex-cli"
        && !codex_bash_enabled
        && !has_commit_evidence
        && !supported_commit
    {
        return Some("codex_bash_disabled");
    }

    if !has_commit_evidence
        && !supported_commit
        && command.is_some_and(|command| adapter.should_skip_bash(command))
    {
        return Some("bash_read_only");
    }

    None
}

pub(super) fn skip_detail(event: &crate::adapter::ParsedHookEvent) -> Option<String> {
    event
        .tool_input
        .as_ref()
        .and_then(|value| value["command"].as_str())
        .map(|command| crate::adapter::common::redact_hook_payload_preview(command, 240))
}

fn codex_bash_observe_enabled() -> bool {
    std::env::var("REMEM_ENABLE_CODEX_BASH_OBSERVE")
        .map(|value| matches!(value.as_str(), "1" | "true" | "TRUE" | "yes" | "YES"))
        .unwrap_or(false)
}

#[cfg(test)]
mod tests {
    use crate::adapter::{codex::CodexAdapter, ParsedHookEvent};

    use super::event_skip_reason_with_codex_bash_enabled;

    fn codex_bash_event(command: &str) -> ParsedHookEvent {
        ParsedHookEvent {
            session_id: "session".to_string(),
            cwd: Some("/tmp".to_string()),
            project: "/tmp".to_string(),
            reference_time_epoch: None,
            tool_name: "Bash".to_string(),
            tool_input: Some(serde_json::json!({"command": command})),
            tool_response: Some(serde_json::json!({"exitCode": 0})),
        }
    }

    #[test]
    fn quiet_commit_bypasses_disabled_codex_bash_capture_filter() {
        assert_eq!(
            event_skip_reason_with_codex_bash_enabled(
                &CodexAdapter,
                &codex_bash_event("git commit -q -m done"),
                false,
                false,
            ),
            None
        );
    }

    #[test]
    fn proven_commit_bypasses_read_only_prefix_filter() {
        assert_eq!(
            event_skip_reason_with_codex_bash_enabled(
                &CodexAdapter,
                &codex_bash_event("git status --short && git commit -m done"),
                true,
                false,
            ),
            None
        );
    }
}