o7 0.1.1

O7 workflow DSL runner
Documentation
use crate::state::types::RunStatus;

fn quote_shell_arg(value: &str) -> String {
    let escaped = value.replace('\'', "'\"'\"'");
    format!("'{}'", escaped)
}

pub fn build_quit_summary(
    run_id: &str,
    root_workflow: &str,
    status: &RunStatus,
    project_root: &str,
) -> String {
    let project_arg = quote_shell_arg(project_root);
    let mut lines = vec![
        "Run summary:".to_string(),
        format!("  Run ID: {}", run_id),
        format!("  Status: {}", status),
        format!("  Workflow: {}", root_workflow),
        format!("  Inspect: o7 inspect {} --project {}", run_id, project_arg),
    ];

    if *status == RunStatus::Paused {
        lines.push(format!(
            "  Resume:  o7 resume {} --project {}",
            run_id, project_arg
        ));
    } else {
        lines.push(format!("  Resume:  not available (run is {})", status));
    }

    lines.join("\n")
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_build_quit_summary_for_paused_run() {
        let summary =
            build_quit_summary("run-123", "main", &RunStatus::Paused, "/tmp/project root");
        assert!(summary.contains("Run ID: run-123"));
        assert!(summary.contains("Status: paused"));
        assert!(summary.contains("Workflow: main"));
        assert!(summary.contains("o7 resume run-123 --project '/tmp/project root'"));
    }

    #[test]
    fn test_build_quit_summary_for_completed_run() {
        let summary =
            build_quit_summary("run-456", "deploy", &RunStatus::Completed, "/tmp/project");
        assert!(summary.contains("Run ID: run-456"));
        assert!(summary.contains("Status: completed"));
        assert!(summary.contains("Resume:  not available (run is completed)"));
    }
}