remem-ai 0.4.4

Persistent memory for Claude Code — single binary, zero subprocesses
Documentation
use anyhow::Result;

use crate::db;

pub(in crate::cli) fn run_status() -> Result<()> {
    let conn = db::open_db()?;
    let db_path = db::db_path();
    let db_size = std::fs::metadata(&db_path)
        .map(|metadata| metadata.len())
        .unwrap_or(0);
    let version = env!("CARGO_PKG_VERSION");
    let stats = db::query_system_stats(&conn)?;

    let today_start = chrono::Local::now()
        .date_naive()
        .and_hms_opt(0, 0, 0)
        .map(|dt| dt.and_utc().timestamp())
        .unwrap_or(0);
    let daily_stats = db::query_daily_activity_stats(&conn, today_start)?;
    let top_projects = db::query_top_projects(&conn, 5)?;

    println!("remem v{}", version);
    println!(
        "Database: {} ({:.1} MB)",
        db_path.display(),
        db_size as f64 / 1_048_576.0
    );
    println!();
    println!("  Memories:      {:>6}", stats.active_memories);
    println!("  Observations:  {:>6}", stats.active_observations);
    println!("  Sessions:      {:>6}", stats.session_summaries);
    println!("  Raw messages:  {:>6}", stats.raw_messages);
    println!();
    println!("Capture pipeline:");
    println!("  Captured:     {:>6}", stats.captured_events);
    println!("  Extract todo: {:>6}", stats.pending_extraction_tasks);
    println!("  Extract run:  {:>6}", stats.processing_extraction_tasks);
    println!("  Extract fail: {:>6}", stats.failed_extraction_tasks);
    println!("  Candidates:   {:>6}", stats.pending_memory_candidates);
    if let Some(epoch) = stats.oldest_pending_extraction_epoch {
        let age_secs = chrono::Utc::now().timestamp().saturating_sub(epoch);
        println!("  Oldest task:  {:>6}s", age_secs);
    }
    println!();
    println!("Pending observations:");
    println!("  Ready:        {:>6}", stats.ready_pending_observations);
    println!("  Delayed:      {:>6}", stats.delayed_pending_observations);
    println!(
        "  Processing:   {:>6}",
        stats.processing_pending_observations
    );
    println!(
        "  Expired:      {:>6}",
        stats.expired_processing_pending_observations
    );
    println!("  Failed:       {:>6}", stats.failed_pending_observations);
    if let Some(epoch) = stats.oldest_ready_pending_epoch {
        let age_secs = chrono::Utc::now().timestamp().saturating_sub(epoch);
        println!("  Oldest ready: {:>6}s", age_secs);
    }
    println!();
    println!("Jobs:");
    println!("  Pending:      {:>6}", stats.pending_jobs);
    println!("  Processing:   {:>6}", stats.processing_jobs);
    println!("  Failed:       {:>6}", stats.failed_jobs);
    println!("  Stuck:        {:>6}", stats.stuck_jobs);
    println!();
    println!("Worker daemon:");
    let daemon_health = if stats.worker_daemon_healthy {
        "healthy"
    } else if stats.worker_heartbeat_age_secs.is_some() {
        "stale"
    } else {
        "missing"
    };
    println!("  Health:       {:>7}", daemon_health);
    if let Some(age_secs) = stats.worker_heartbeat_age_secs {
        println!("  Last beat:    {:>6}s", age_secs);
    }
    if let Some(owner) = &stats.worker_heartbeat_owner {
        println!("  Owner:        {}", owner);
    }
    println!();
    println!("Today:");
    println!("  New memories:      {:>4}", daily_stats.memories);
    println!("  New observations:  {:>4}", daily_stats.observations);

    if !top_projects.is_empty() {
        println!();
        println!("Top projects:");
        for project in &top_projects {
            println!("  {:>4}  {}", project.count, project.project);
        }
    }

    println!();
    for line in crate::db::schema::status::format_summary() {
        println!("{}", line);
    }

    Ok(())
}