scud/commands/
warmup.rs

1use anyhow::Result;
2use colored::Colorize;
3use std::path::PathBuf;
4use std::process::Command;
5
6use crate::commands::helpers::flatten_all_tasks;
7use crate::storage::Storage;
8
9pub fn run(project_root: Option<PathBuf>) -> Result<()> {
10    let storage = Storage::new(project_root);
11
12    if !storage.is_initialized() {
13        println!("{}", "SCUD not initialized. Run: scud init".yellow());
14        return Ok(());
15    }
16
17    println!("{}", "SCUD Session Warmup".cyan().bold());
18    println!("{}", "=".repeat(50).dimmed());
19
20    // 1. Show working directory
21    let cwd = std::env::current_dir()?;
22    println!("\n{} {}", "Working directory:".bold(), cwd.display());
23
24    // 2. Show recent git commits
25    println!("\n{}", "Recent commits:".bold());
26    match Command::new("git")
27        .args(["log", "--oneline", "-5", "--no-decorate"])
28        .output()
29    {
30        Ok(output) if output.status.success() => {
31            let commits = String::from_utf8_lossy(&output.stdout);
32            if commits.trim().is_empty() {
33                println!("  {}", "(no commits yet)".dimmed());
34            } else {
35                for line in commits.lines() {
36                    println!("  {}", line.dimmed());
37                }
38            }
39        }
40        _ => println!("  {}", "(not a git repository)".dimmed()),
41    }
42
43    // 3. Show active tag and stats
44    println!("\n{}", "Task status:".bold());
45    match storage.get_active_group()? {
46        Some(tag) => {
47            println!("  Active tag: {}", tag.green());
48
49            // Load and show stats
50            if let Ok(phase) = storage.load_group(&tag) {
51                let stats = phase.get_stats();
52                println!(
53                    "  Progress: {}/{} tasks done ({}%)",
54                    stats.done.to_string().green(),
55                    stats.total,
56                    if stats.total > 0 {
57                        (stats.done * 100 / stats.total).to_string()
58                    } else {
59                        "0".to_string()
60                    }
61                );
62                println!(
63                    "  Status: {} pending, {} in-progress, {} blocked",
64                    stats.pending.to_string().yellow(),
65                    stats.in_progress.to_string().cyan(),
66                    stats.blocked.to_string().red()
67                );
68            }
69        }
70        None => {
71            println!("  {}", "No active tag set".yellow());
72            println!("  Run: scud tags <tag-name>");
73        }
74    }
75
76    // 4. Show current assignments
77    println!("\n{}", "Current assignments:".bold());
78    let tasks = storage.load_tasks()?;
79    let mut found_assignments = false;
80
81    for (tag, phase) in &tasks {
82        for task in &phase.tasks {
83            if let Some(ref assigned_to) = task.assigned_to {
84                found_assignments = true;
85                let status_str = task.status.as_str();
86                println!(
87                    "  {} | {} | {} | {}",
88                    tag.dimmed(),
89                    task.id.cyan(),
90                    assigned_to.yellow(),
91                    status_str
92                );
93            }
94        }
95    }
96    if !found_assignments {
97        println!("  {}", "(no assignments)".dimmed());
98    }
99
100    // 5. Show next available task (with cross-tag dependency checking)
101    println!("\n{}", "Next available task:".bold());
102    let all_tasks_flat = flatten_all_tasks(&tasks);
103    if let Some(tag) = storage.get_active_group()? {
104        if let Some(phase) = tasks.get(&tag) {
105            let available: Vec<_> = phase
106                .tasks
107                .iter()
108                .filter(|t| {
109                    t.status == crate::models::TaskStatus::Pending
110                        && t.has_dependencies_met_refs(&all_tasks_flat)
111                })
112                .collect();
113
114            if let Some(task) = available.first() {
115                println!(
116                    "  {} {} (complexity: {})",
117                    task.id.cyan(),
118                    task.title,
119                    task.complexity
120                );
121                println!("  Run: {}", "scud set-status <task-id> in-progress".green());
122            } else if phase
123                .tasks
124                .iter()
125                .all(|t| t.status == crate::models::TaskStatus::Done)
126            {
127                println!("  {}", "All tasks complete!".green());
128            } else {
129                println!("  {}", "(no tasks available - check dependencies)".yellow());
130            }
131        }
132    } else {
133        println!("  {}", "(set active tag first)".dimmed());
134    }
135
136    println!("\n{}", "=".repeat(50).dimmed());
137    println!(
138        "Ready to work. Use {} to find your next task.",
139        "scud next".cyan()
140    );
141
142    Ok(())
143}