Alias codex_hooks feature as hooks (#20522)

# Why

The hooks feature flag should use the concise canonical name `hooks`,
while existing configs that still use `codex_hooks` continue to work
during the rename.

# What

- change the canonical `Feature::CodexHooks` key from `codex_hooks` to
`hooks`
- register `codex_hooks` through the existing legacy-alias path
- update the config schema and canonical config fixtures to prefer
`hooks`
- add regression coverage that both `hooks` and `codex_hooks` resolve to
`Feature::CodexHooks`

# Verification

- `cargo test -p codex-features`
- `cargo test -p codex-core config::schema_tests`
- `cargo test -p codex-core
pre_tool_use_blocks_shell_when_defined_in_config_toml`
- `cargo test -p codex-app-server
hooks_list_uses_each_cwds_effective_feature_enablement`
This commit is contained in:
Abhinav authored and GitHub committed 2026-05-01 00:46:33 +00:00
1 parent 5affb7f9d5
commit 0d9a5d20ec
6 files changed
+21 -5

No files matched your search

@@ -63,7 +63,7 @@ fn write_plugin_hook_config(codex_home: &std::path::Path, hooks_json: &str) -> R
r#"[features] r#"[features]
plugins = true plugins = true
plugin_hooks = true plugin_hooks = true
codex_hooks = true hooks = true
[plugins."demo@test"] [plugins."demo@test"]
enabled = true enabled = true
@@ -230,7 +230,7 @@ async fn hooks_list_uses_each_cwds_effective_feature_enablement() -> Result<()>
std::fs::write( std::fs::write(
codex_home.path().join("config.toml"), codex_home.path().join("config.toml"),
r#"[features] r#"[features]
codex_hooks = false hooks = false
"#, "#,
)?; )?;
std::fs::create_dir_all(workspace.path().join(".git"))?; std::fs::create_dir_all(workspace.path().join(".git"))?;
@@ -238,7 +238,7 @@ codex_hooks = false
std::fs::write( std::fs::write(
workspace.path().join(".codex/config.toml"), workspace.path().join(".codex/config.toml"),
r#"[features] r#"[features]
codex_hooks = true hooks = true
[hooks] [hooks]
+6
View File
@@ -448,6 +448,9 @@
"guardian_approval": { "guardian_approval": {
"type": "boolean" "type": "boolean"
}, },
"hooks": {
"type": "boolean"
},
"image_detail_original": { "image_detail_original": {
"type": "boolean" "type": "boolean"
}, },
@@ -3859,6 +3862,9 @@
"guardian_approval": { "guardian_approval": {
"type": "boolean" "type": "boolean"
}, },
"hooks": {
"type": "boolean"
},
"image_detail_original": { "image_detail_original": {
"type": "boolean" "type": "boolean"
}, },
+1 -1
View File
@@ -315,7 +315,7 @@ elif mode == "exit_2":
.unwrap_or_default(); .unwrap_or_default();
let config_toml = format!( let config_toml = format!(
r#"[features] r#"[features]
codex_hooks = true hooks = true
[hooks] [hooks]
+4
View File
@@ -49,6 +49,10 @@ const ALIASES: &[Alias] = &[
legacy_key: "telepathy", legacy_key: "telepathy",
feature: Feature::Chronicle, feature: Feature::Chronicle,
}, },
Alias {
legacy_key: "codex_hooks",
feature: Feature::CodexHooks,
},
]; ];
pub fn legacy_feature_keys() -> impl Iterator<Item = &'static str> { pub fn legacy_feature_keys() -> impl Iterator<Item = &'static str> {
+1 -1
View File
@@ -782,7 +782,7 @@ pub const FEATURES: &[FeatureSpec] = &[
}, },
FeatureSpec { FeatureSpec {
id: Feature::CodexHooks, id: Feature::CodexHooks,
key: "codex_hooks", key: "hooks",
stage: Stage::Stable, stage: Stage::Stable,
default_enabled: true, default_enabled: true,
}, },
+6
View File
@@ -267,6 +267,12 @@ fn collab_is_legacy_alias_for_multi_agent() {
assert_eq!(feature_for_key("collab"), Some(Feature::Collab)); assert_eq!(feature_for_key("collab"), Some(Feature::Collab));
} }
#[test]
fn codex_hooks_is_legacy_alias_for_hooks() {
assert_eq!(feature_for_key("hooks"), Some(Feature::CodexHooks));
assert_eq!(feature_for_key("codex_hooks"), Some(Feature::CodexHooks));
}
#[test] #[test]
fn multi_agent_is_stable_and_enabled_by_default() { fn multi_agent_is_stable_and_enabled_by_default() {
assert_eq!(Feature::Collab.stage(), Stage::Stable); assert_eq!(Feature::Collab.stage(), Stage::Stable);