fn append_convertible_hook_groups()

in codex-rs/external-agent-migration/src/lib.rs [537:660]


fn append_convertible_hook_groups(
    settings: &JsonValue,
    hooks_payload: &mut serde_json::Map<String, JsonValue>,
    target_config_dir: Option<&Path>,
) {
    let Some(hooks_config) = settings.get("hooks").and_then(JsonValue::as_object) else {
        return;
    };

    for event_name in HOOK_EVENT_NAMES {
        let Some(groups) = hooks_config.get(event_name).and_then(JsonValue::as_array) else {
            continue;
        };
        for group in groups {
            let Some(group_object) = group.as_object() else {
                continue;
            };
            if group_object.contains_key("if")
                || group_object
                    .keys()
                    .any(|key| !matches!(key.as_str(), "matcher" | "hooks"))
            {
                continue;
            }
            let mut hook_commands = Vec::new();
            if let Some(hooks) = group_object.get("hooks").and_then(JsonValue::as_array) {
                for hook in hooks {
                    let Some(hook_object) = hook.as_object() else {
                        continue;
                    };
                    let hook_type = hook_object
                        .get("type")
                        .and_then(JsonValue::as_str)
                        .unwrap_or("command");
                    if hook_type != "command" {
                        continue;
                    }
                    if hook_object.keys().any(|key| {
                        !matches!(
                            key.as_str(),
                            "type"
                                | "command"
                                | "timeout"
                                | "timeoutSec"
                                | "statusMessage"
                                | "async"
                        )
                    }) {
                        continue;
                    }
                    if hook_object
                        .get("async")
                        .and_then(JsonValue::as_bool)
                        .unwrap_or(false)
                    {
                        continue;
                    }
                    if ["asyncRewake", "shell", "once"]
                        .into_iter()
                        .any(|field| hook_object.contains_key(field))
                    {
                        continue;
                    }
                    let Some(command) = hook_object
                        .get("command")
                        .and_then(JsonValue::as_str)
                        .map(str::trim)
                        .filter(|command| !command.is_empty())
                    else {
                        continue;
                    };

                    let mut command_payload = serde_json::Map::new();
                    command_payload
                        .insert("type".to_string(), JsonValue::String("command".to_string()));
                    command_payload.insert(
                        "command".to_string(),
                        JsonValue::String(rewrite_hook_command(command, target_config_dir)),
                    );
                    if let Some(timeout) = hook_object
                        .get("timeout")
                        .or_else(|| hook_object.get("timeoutSec"))
                        .and_then(json_u64)
                    {
                        command_payload.insert(
                            "timeout".to_string(),
                            JsonValue::Number(serde_json::Number::from(timeout)),
                        );
                    }
                    if let Some(status_message) =
                        hook_object.get("statusMessage").and_then(JsonValue::as_str)
                    {
                        command_payload.insert(
                            "statusMessage".to_string(),
                            JsonValue::String(rewrite_external_agent_terms(status_message)),
                        );
                    }
                    hook_commands.push(JsonValue::Object(command_payload));
                }
            }
            if hook_commands.is_empty() {
                continue;
            }

            let mut group_payload = serde_json::Map::new();
            if HOOK_EVENT_NAMES_WITH_MATCHERS.contains(&event_name)
                && let Some(matcher) = group_object.get("matcher").and_then(JsonValue::as_str)
            {
                group_payload.insert(
                    "matcher".to_string(),
                    JsonValue::String(matcher.to_string()),
                );
            }
            group_payload.insert("hooks".to_string(), JsonValue::Array(hook_commands));
            if let Some(groups) = hooks_payload
                .entry(event_name.to_string())
                .or_insert_with(|| JsonValue::Array(Vec::new()))
                .as_array_mut()
            {
                groups.push(JsonValue::Object(group_payload));
            }
        }
    }
}