scud/commands/weave/
explain.rs1use anyhow::Result;
2use colored::Colorize;
3use std::path::PathBuf;
4
5use scud_core::weave::{Decision, Event};
6
7use super::check::{build_coordinator, core_storage};
8
9pub fn run(project_root: Option<PathBuf>, event_json: &str) -> Result<()> {
10 let storage = core_storage(project_root);
11 let event: Event = serde_json::from_str(event_json)
12 .map_err(|e| anyhow::anyhow!("Invalid event JSON: {}", e))?;
13
14 let (coord, _tag, _phase) = build_coordinator(&storage)?;
15
16 println!("{}", "Event:".blue().bold());
17 println!(" Kind: {}", event.kind);
18 if let Some(ref agent) = event.agent {
19 println!(" Agent: {}", agent);
20 }
21 if let Some(ref target) = event.target {
22 println!(" Target: {}", target);
23 }
24 if let Some(ref task_id) = event.task_id {
25 println!(" Task: {}", task_id);
26 }
27 println!();
28
29 let decision = coord.evaluate_full(&event);
31
32 match &decision {
33 Decision::Proceed => {
34 println!("{}", "PROCEED".green().bold());
35 println!("No b-threads blocked this event.");
36
37 let checked: Vec<_> = coord.threads.iter().filter(|t| t.enabled).collect();
39 if !checked.is_empty() {
40 println!("\n{}", "Threads evaluated:".dimmed());
41 for t in checked {
42 println!(" {} {} - passed", t.id.cyan(), t.name);
43 }
44 }
45 }
46 Decision::Wait { reason, thread_id } => {
47 println!("{}", "WAIT".yellow().bold());
48 println!("Thread: {}", thread_id.cyan());
49 println!("Reason: {}", reason);
50 println!("\nThe prerequisite has not been satisfied yet.");
51 }
52 Decision::Blocked { reason, thread_id } => {
53 println!("{}", "BLOCKED".red().bold());
54 println!("Thread: {}", thread_id.cyan());
55 println!("Reason: {}", reason);
56
57 if !coord.active_locks.is_empty() {
59 println!("\n{}", "Active locks:".dimmed());
60 for (key, lock) in &coord.active_locks {
61 println!(
62 " {} -> {} (task: {})",
63 key,
64 lock.holder_agent,
65 lock.task_id.as_deref().unwrap_or("-"),
66 );
67 }
68 }
69 }
70 }
71
72 Ok(())
73}