rusty-beads 0.1.0

Git-backed graph issue tracker for AI coding agents - a Rust implementation with context store, dependency tracking, and semantic compaction
Documentation
//! Background daemon for Beads.
//!
//! Provides a persistent background service for faster issue operations
//! and automatic git synchronization.

mod protocol;
mod server;
mod client;
mod config;

pub use protocol::{Request, Response, Operation};
pub use server::Daemon;
pub use client::DaemonClient;
pub use config::DaemonConfig;

use std::path::PathBuf;
use sha2::{Digest, Sha256};

/// Default socket filename.
pub const SOCKET_FILE: &str = "bd.sock";

/// Maximum socket path length (macOS limit).
const MAX_SOCKET_PATH_LEN: usize = 104;

/// Get the socket path for a given beads directory.
pub fn get_socket_path(beads_dir: &std::path::Path) -> PathBuf {
    let primary = beads_dir.join(SOCKET_FILE);

    // Check if path is too long (macOS has 104-char limit)
    if primary.to_string_lossy().len() <= MAX_SOCKET_PATH_LEN {
        primary
    } else {
        // Use fallback path in /tmp with hashed name
        let mut hasher = Sha256::new();
        hasher.update(beads_dir.to_string_lossy().as_bytes());
        let hash = hex::encode(&hasher.finalize()[..4]);
        PathBuf::from(format!("/tmp/beads-{}/{}", hash, SOCKET_FILE))
    }
}

/// Get the PID file path for a given beads directory.
pub fn get_pid_path(beads_dir: &std::path::Path) -> PathBuf {
    beads_dir.join("daemon.pid")
}

/// Check if the daemon is running for the given beads directory.
pub fn is_daemon_running(beads_dir: &std::path::Path) -> bool {
    let pid_path = get_pid_path(beads_dir);
    if !pid_path.exists() {
        return false;
    }

    if let Ok(pid_str) = std::fs::read_to_string(&pid_path) {
        if let Ok(pid) = pid_str.trim().parse::<u32>() {
            // Check if process is running
            return is_process_running(pid);
        }
    }

    false
}

/// Check if a process with the given PID is running.
#[cfg(unix)]
fn is_process_running(pid: u32) -> bool {
    unsafe {
        libc::kill(pid as i32, 0) == 0
    }
}

#[cfg(not(unix))]
fn is_process_running(_pid: u32) -> bool {
    // On non-Unix systems, assume not running
    false
}