xbp 10.38.0

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
use crate::cli::commands;
use crate::cli::error::{CliResult, ErrorFactory};
use crate::commands::{
    run_worktree_watch_start, run_worktree_watch_status, run_worktree_watch_stop,
    run_worktree_watch_sync, run_worktree_watch_tray, WorktreeWatchStartOptions,
    WorktreeWatchStatusOptions, WorktreeWatchStopOptions, WorktreeWatchSyncOptions,
    WorktreeWatchTargetOptions, WorktreeWatchTrayOptions,
};

fn map_target(target: commands::WorktreeWatchTarget) -> WorktreeWatchTargetOptions {
    WorktreeWatchTargetOptions {
        repo: target.repo,
        parent: target.parent,
        repos: target.repos,
    }
}

pub async fn handle_worktree_watch(cmd: commands::WorktreeWatchCmd, _debug: bool) -> CliResult<()> {
    let result = match cmd.command {
        commands::WorktreeWatchSubCommand::Start(start_cmd) => {
            run_worktree_watch_start(WorktreeWatchStartOptions {
                target: map_target(start_cmd.target),
                detach: start_cmd.detach,
                sync_interval_seconds: start_cmd.sync_interval_seconds,
                once: start_cmd.once,
            })
            .await
        }
        commands::WorktreeWatchSubCommand::Stop(stop_cmd) => {
            run_worktree_watch_stop(WorktreeWatchStopOptions {
                target: map_target(stop_cmd.target),
                force: stop_cmd.force,
            })
        }
        commands::WorktreeWatchSubCommand::Sync(sync_cmd) => {
            run_worktree_watch_sync(WorktreeWatchSyncOptions {
                target: map_target(sync_cmd.target),
                dry_run: sync_cmd.dry_run,
                resync: sync_cmd.resync,
            })
            .await
        }
        commands::WorktreeWatchSubCommand::Status(status_cmd) => {
            run_worktree_watch_status(WorktreeWatchStatusOptions {
                target: map_target(status_cmd.target),
                json: status_cmd.json,
                records: status_cmd.records,
                record_limit: status_cmd.record_limit,
                stats: status_cmd.stats,
                repo_activity: status_cmd.repo_activity,
                stats_gap_minutes: status_cmd.stats_gap_minutes,
            })
            .await
        }
        commands::WorktreeWatchSubCommand::Tray(tray_cmd) => {
            // Tray owns a blocking native event loop (Windows NotifyIcon / Linux StatusNotifier).
            tokio::task::spawn_blocking(move || {
                run_worktree_watch_tray(WorktreeWatchTrayOptions {
                    target: map_target(tray_cmd.target),
                    sync_interval_seconds: tray_cmd.sync_interval_seconds,
                })
            })
            .await
            .map_err(|error| format!("Worktree-watch tray task failed: {error}"))
            .and_then(|inner| inner)
        }
    };

    result.map_err(|error| {
        ErrorFactory::operation(
            "worktree-watch",
            "process worktree mutations",
            error,
            Some(
                "Run inside a git repository, pass `--repo <path>`, `--repos <path>…`, or `--parent <folder>`. Use `xbp login` before syncing.",
            ),
        )
    })
}