use crate::config::workflows::WorkflowsConfig;
use anyhow::Result;
use serde_json::{Value, json};
pub fn list_workflows(workflows: &WorkflowsConfig) -> Result<Value> {
let mut workflow_list: Vec<Value> = Vec::new();
for (name, config) in &workflows.named_workflows {
let source = config.source_file.as_ref().map(|p| p.display().to_string());
workflow_list.push(json!({
"name": name,
"description": config.description,
"source_file": source,
"states": config.states.keys().collect::<Vec<_>>(),
"phases": config.phases.keys().collect::<Vec<_>>(),
}));
}
workflow_list.sort_by(|a, b| {
a.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.cmp(b.get("name").and_then(|v| v.as_str()).unwrap_or(""))
});
let default_workflow = workflows.default_workflow_key.as_ref();
let mut overlay_list: Vec<Value> = workflows
.named_overlays
.iter()
.map(|(name, config)| {
json!({
"name": name,
"description": config.description,
})
})
.collect();
overlay_list.sort_by(|a, b| {
a.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.cmp(b.get("name").and_then(|v| v.as_str()).unwrap_or(""))
});
Ok(json!({
"workflows": workflow_list,
"overlays": overlay_list,
"default_workflow": default_workflow,
"count": workflows.named_workflows.len(),
}))
}
pub fn get_workflow(workflows: &WorkflowsConfig, name: &str) -> Result<Value> {
let config = workflows
.named_workflows
.get(name)
.ok_or_else(|| anyhow::anyhow!("Workflow '{}' not found", name))?;
let source = config.source_file.as_ref().map(|p| p.display().to_string());
let states: Vec<Value> = config
.states
.iter()
.map(|(state_name, state)| {
json!({
"name": state_name,
"exits": state.exits,
"timed": state.timed,
"has_enter_prompt": state.prompts.enter.is_some(),
"has_exit_prompt": state.prompts.exit.is_some(),
})
})
.collect();
let phases: Vec<Value> = config
.phases
.iter()
.map(|(phase_name, phase)| {
json!({
"name": phase_name,
"has_enter_prompt": phase.prompts.enter.is_some(),
"has_exit_prompt": phase.prompts.exit.is_some(),
})
})
.collect();
Ok(json!({
"name": name,
"description": config.description,
"source_file": source,
"settings": {
"initial_state": config.settings.initial_state,
"disconnect_state": config.settings.disconnect_state,
"blocking_states": config.settings.blocking_states,
},
"states": states,
"phases": phases,
"combo_count": config.combos.len(),
}))
}
pub fn list_overlays(workflows: &WorkflowsConfig) -> Result<Value> {
let mut overlay_list: Vec<Value> = Vec::new();
for (name, config) in &workflows.named_overlays {
let source = config.source_file.as_ref().map(|p| p.display().to_string());
overlay_list.push(json!({
"name": name,
"description": config.description,
"source_file": source,
}));
}
overlay_list.sort_by(|a, b| {
a.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.cmp(b.get("name").and_then(|v| v.as_str()).unwrap_or(""))
});
Ok(json!({
"overlays": overlay_list,
"count": workflows.named_overlays.len(),
}))
}
pub fn get_overlay(workflows: &WorkflowsConfig, name: &str) -> Result<Value> {
let config = workflows
.named_overlays
.get(name)
.ok_or_else(|| anyhow::anyhow!("Overlay '{}' not found", name))?;
let source = config.source_file.as_ref().map(|p| p.display().to_string());
let states: Vec<Value> = config
.states
.iter()
.map(|(state_name, state)| {
json!({
"name": state_name,
"exits": state.exits,
"timed": state.timed,
"has_enter_prompt": state.prompts.enter.is_some(),
"has_exit_prompt": state.prompts.exit.is_some(),
})
})
.collect();
let phases: Vec<Value> = config
.phases
.iter()
.map(|(phase_name, phase)| {
json!({
"name": phase_name,
"has_enter_prompt": phase.prompts.enter.is_some(),
"has_exit_prompt": phase.prompts.exit.is_some(),
})
})
.collect();
let gates: Vec<Value> = config
.gates
.iter()
.map(|(gate_key, gate_defs)| {
let defs: Vec<Value> = gate_defs
.iter()
.map(|g| {
json!({
"type": g.gate_type,
"enforcement": format!("{:?}", g.enforcement),
"description": g.description,
})
})
.collect();
json!({
"key": gate_key,
"definitions": defs,
})
})
.collect();
let roles: Vec<Value> = config
.roles
.iter()
.map(|(role_name, role)| {
json!({
"name": role_name,
"description": role.description,
"tags": role.tags,
"max_claims": role.max_claims,
"can_assign": role.can_assign,
"can_create_subtasks": role.can_create_subtasks,
})
})
.collect();
let advisories: Vec<Value> = config
.advisories
.iter()
.map(|(topic, advisory)| {
json!({
"topic": topic,
"level": advisory.level,
"phase": advisory.phase,
"role": advisory.role,
"domain": advisory.domain,
"content": advisory.content,
})
})
.collect();
let role_prompts: Value = config
.role_prompts
.iter()
.map(|(role_name, prompts)| (role_name.clone(), json!(prompts)))
.collect::<serde_json::Map<String, Value>>()
.into();
Ok(json!({
"name": name,
"description": config.description,
"source_file": source,
"states": states,
"phases": phases,
"gates": gates,
"roles": roles,
"advisories": advisories,
"role_prompts": role_prompts,
"combo_count": config.combos.len(),
}))
}