rigg 0.17.0

Configuration-as-code CLI for Azure AI Search and Microsoft Foundry
//! Poll the server for changes and pull updates automatically

use std::time::Duration;

use anyhow::Result;
use tokio::time::sleep;

use crate::cli::ResourceTypeFlags;
use crate::commands::common::resolve_resource_selection_from_flags;
use crate::commands::load_config_and_env;
use crate::commands::pull::execute_pull;

pub async fn run(
    flags: &ResourceTypeFlags,
    filter: Option<String>,
    force: bool,
    interval: u64,
    env_override: Option<&str>,
) -> Result<()> {
    let (project_root, config, env) = load_config_and_env(env_override)?;
    let files_root = config.files_root(&project_root);

    let selection = resolve_resource_selection_from_flags(flags, env.sync.include_preview, true);

    if selection.is_empty() {
        println!("No resource types specified. Use --all or specify types (e.g., --indexes)");
        return Ok(());
    }

    println!("Watching for changes (env: {})...", env.name);
    println!("  Interval: {}s", interval);
    if force {
        println!("  Auto-update: enabled (--force)");
    }
    println!();
    println!("Press Ctrl+C to stop");
    println!();

    let interval_duration = Duration::from_secs(interval);
    let mut consecutive_failures: u32 = 0;

    loop {
        let timestamp = chrono::Local::now().format("%H:%M:%S");

        match execute_pull(
            &project_root,
            &files_root,
            &env,
            &selection,
            filter.as_deref(),
            force,
            false, // no AI explanations in watch mode
        )
        .await
        {
            Ok(()) => {
                consecutive_failures = 0;
            }
            Err(e) => {
                consecutive_failures = consecutive_failures.saturating_add(1);
                let backoff_secs = std::cmp::min(interval * 2u64.pow(consecutive_failures), 300);
                println!(
                    "[{}] Error: {}. Backing off for {}s ({} consecutive failure(s))",
                    timestamp, e, backoff_secs, consecutive_failures
                );
                sleep(Duration::from_secs(backoff_secs)).await;
                continue;
            }
        }

        sleep(interval_duration).await;
    }
}