darq 0.1.0

darq CLI + TUI — autonomous issue → PR pipeline with SAT and a learning loop.
Documentation
//! Milestone commands: sweep.

use crate::daemon::client::DaemonClient;
use crate::daemon::protocol::Method;

pub async fn handle_sweep(
    client: &mut DaemonClient,
    milestone_name: &str,
    dry_run: bool,
) -> anyhow::Result<()> {
    println!(
        "Sweeping milestone: {}{}",
        milestone_name,
        if dry_run { " (dry run)" } else { "" }
    );

    let params = serde_json::json!({
        "milestone": milestone_name,
        "dry_run": dry_run,
    });

    let response = client.send(Method::Sweep, params).await?;

    if let Some(err) = DaemonClient::extract_error(&response) {
        eprintln!("Sweep error: {err}");
        return Ok(());
    }

    let result =
        DaemonClient::extract_result(&response).ok_or_else(|| anyhow::anyhow!("no result"))?;

    // Print per-issue results
    println!();
    println!("{:<8} {:<40} {:<15} Status", "Issue", "Title", "Action");
    println!("{}", "-".repeat(80));

    if let Some(issues) = result.get("issues").and_then(|v| v.as_array()) {
        for issue in issues {
            let number = issue.get("number").and_then(|v| v.as_u64()).unwrap_or(0);
            let title = issue.get("title").and_then(|v| v.as_str()).unwrap_or("?");
            let action = issue.get("action").and_then(|v| v.as_str()).unwrap_or("?");
            let executed = issue
                .get("executed")
                .and_then(|v| v.as_bool())
                .unwrap_or(false);
            let error = issue.get("error").and_then(|v| v.as_str());

            let status = if let Some(e) = error {
                format!("ERROR: {e}")
            } else if executed {
                "executed".into()
            } else {
                "skipped".into()
            };

            let short_title = if title.len() > 38 {
                format!("{}...", &title[..35])
            } else {
                title.to_string()
            };

            let short_action = action.split(':').next().unwrap_or(action);

            println!(
                "#{:<7} {:<40} {:<15} {}",
                number, short_title, short_action, status
            );
        }
    }

    // Print summary
    println!();
    let total = result.get("total").and_then(|v| v.as_u64()).unwrap_or(0);
    let completed = result
        .get("completed")
        .and_then(|v| v.as_u64())
        .unwrap_or(0);
    let skipped = result.get("skipped").and_then(|v| v.as_u64()).unwrap_or(0);
    let errored = result.get("errored").and_then(|v| v.as_u64()).unwrap_or(0);
    let duration = result
        .get("duration_ms")
        .and_then(|v| v.as_u64())
        .unwrap_or(0);

    println!(
        "Total: {total} | Completed: {completed} | Skipped: {skipped} | Errored: {errored} | Duration: {duration}ms"
    );

    if errored > 0 {
        eprintln!("\n{errored} issue(s) had errors");
    }

    Ok(())
}