darq 0.1.0

darq CLI + TUI — autonomous issue → PR pipeline with SAT and a learning loop.
Documentation
//! Daemon IPC module.
//!
//! Provides the socket server (daemon side), socket client (CLI/TUI side),
//! protocol types, and lifecycle management.

pub mod client;
pub mod lifecycle;
pub mod protocol;
pub mod server;

use std::sync::Arc;

/// Handle `darq daemon start`.
pub async fn handle_start(config_path: &str, background: bool) -> anyhow::Result<()> {
    if background {
        eprintln!("[daemon] starting in background mode");
        tracing::info!("daemon: running in background mode");
        let config = darq_core::config::load_or_default();
        eprintln!("[daemon] config loaded: repo={:?}", config.project.repo);
        let api = Arc::new(darq_core::api::Api::from_config(&config)?);
        eprintln!("[daemon] API initialized");
        let workspace_base = dirs::home_dir()
            .unwrap_or_else(|| std::path::PathBuf::from("."))
            .join(".darq")
            .join("runs");
        tokio::fs::create_dir_all(&workspace_base).await?;
        let engine = Arc::new(darq_core::workflow::chain::WorkflowEngine::new(
            api.clone(),
            config.clone(),
            workspace_base,
        ));
        let (server, _shutdown_rx) = server::SocketServer::new(api, engine);
        let server = if let Some(repo) = config.project.repo {
            server.with_repo(repo)
        } else {
            server
        };
        server.run().await?;
    } else {
        // Spawn a detached background daemon process
        lifecycle::spawn_daemon(config_path).await?;
        println!("Daemon started on {}", lifecycle::socket_path().display());
    }
    Ok(())
}

/// Handle `darq daemon stop`.
pub async fn handle_stop() -> anyhow::Result<()> {
    let mut daemon_client = client::DaemonClient::connect().await?;
    let response = daemon_client.call(protocol::Method::Shutdown).await?;
    if let Some(err) = client::DaemonClient::extract_error(&response) {
        eprintln!("Error: {err}");
    } else {
        println!("Daemon stopped");
    }
    Ok(())
}

/// Handle `darq daemon status`.
pub fn handle_daemon_status() {
    if lifecycle::is_daemon_running() {
        let pid = lifecycle::daemon_pid().unwrap_or(0);
        println!("Daemon running (pid: {pid})");
        println!("Socket: {}", lifecycle::socket_path().display());
    } else {
        println!("Daemon not running");
    }
}