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));
}
}
}
}