kiromi-ai-cli 0.2.2

Operator and developer CLI for the kiromi-ai-memory store: append, search, snapshot, regenerate, migrate-scheme, gc, audit-tail.
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Tracing subscriber installation. Library code never installs one โ€” that's
//! the binary's job (spec ยง 19).

use tracing_subscriber::EnvFilter;

/// Install a `tracing-subscriber` with the given verbosity. `0` = info on the
/// CLI crate, warn elsewhere; `1` = debug on the CLI crate; `2+` = trace.
///
/// Honours `KIROMI_AI_LOG` if set โ€” that wins over `--verbose`.
pub(crate) fn init(verbose: u8) {
    let env = std::env::var("KIROMI_AI_LOG").ok();
    let filter = if let Some(s) = env {
        EnvFilter::try_new(s).unwrap_or_else(|_| EnvFilter::new("info"))
    } else {
        let level = match verbose {
            0 => "info",
            1 => "debug",
            _ => "trace",
        };
        EnvFilter::try_new(format!(
            "warn,kiromi_ai_cli={level},kiromi_ai_memory={level}"
        ))
        .unwrap_or_else(|_| EnvFilter::new("info"))
    };
    let _ = tracing_subscriber::fmt()
        .with_env_filter(filter)
        .with_writer(std::io::stderr)
        .try_init();
}

#[cfg(test)]
#[allow(unsafe_code)]
mod tests {
    use super::init;

    #[test]
    fn init_is_idempotent_at_each_verbosity() {
        // try_init only succeeds once per process โ€” these are idempotent calls
        // that exercise the verbosity branch matrix without panicking.
        init(0);
        init(1);
        init(2);
    }

    #[test]
    fn init_honours_kiromi_ai_log_env() {
        // SAFETY: tests run sequentially within a single binary by default;
        // `set_var` is unsynchronised but bounded to this test's body.
        unsafe {
            std::env::set_var("KIROMI_AI_LOG", "info");
        }
        init(0);
        unsafe {
            std::env::remove_var("KIROMI_AI_LOG");
        }
    }
}