o7 0.1.0

O7 workflow DSL runner
Documentation
use std::path::Path;

use crate::harness::types::HarnessConfig;

/// Load and parse the harness configuration from .7/harnesses.toml.
pub fn load_harness_config(project_root: &str) -> Result<HarnessConfig, String> {
    let config_path = Path::new(project_root).join(".7").join("harnesses.toml");

    let raw = std::fs::read_to_string(&config_path)
        .map_err(|_| format!("Harness config not found: {}", config_path.display()))?;

    let config: HarnessConfig = toml::from_str(&raw)
        .map_err(|e| format!("Invalid harness config: {}", e))?;

    // Validate business rules that serde can't enforce
    for (name, entry) in &config.harness {
        if entry.args_mapping != "flags" {
            return Err(format!(
                "Harness \"{}\" has invalid args_mapping \"{}\", must be \"flags\"",
                name, entry.args_mapping
            ));
        }
    }

    Ok(config)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use tempfile::TempDir;

    #[test]
    fn test_load_valid_config() {
        let dir = TempDir::new().unwrap();
        let dot7 = dir.path().join(".7");
        fs::create_dir_all(&dot7).unwrap();
        fs::write(
            dot7.join("harnesses.toml"),
            r#"
[harness.echo-test]
command = "echo"
prompt_slot = "--prompt"
args_mapping = "flags"
"#,
        )
        .unwrap();

        let config = load_harness_config(dir.path().to_str().unwrap()).unwrap();
        assert!(config.harness.contains_key("echo-test"));
        assert_eq!(config.harness["echo-test"].command, "echo");
    }

    #[test]
    fn test_load_missing_config() {
        let result = load_harness_config("/nonexistent/path");
        assert!(result.is_err());
    }

    #[test]
    fn test_invalid_args_mapping() {
        let dir = TempDir::new().unwrap();
        let dot7 = dir.path().join(".7");
        fs::create_dir_all(&dot7).unwrap();
        fs::write(
            dot7.join("harnesses.toml"),
            r#"
[harness.bad]
command = "echo"
prompt_slot = "--prompt"
args_mapping = "positional"
"#,
        )
        .unwrap();

        let result = load_harness_config(dir.path().to_str().unwrap());
        assert!(result.is_err());
        assert!(result.unwrap_err().contains("args_mapping"));
    }
}