Tighten hook output event schemas (#24962)

# Why

Fixes #23993.

Hook command output schemas are published as the contract for hook
authors and schema-driven tooling. The event-specific output schemas
previously described `hookSpecificOutput.hookEventName` as the global
`HookEventNameWire` enum, so a `pre-tool-use.command.output` schema
would validate mismatched values like `PostToolUse`. That made the
schemas less precise than the intended event-specific contract.

# What

Constrain each hook-specific output schema to the matching literal
`hookEventName` value, mirroring the existing input-schema shape.

Also split `SubagentStartHookSpecificOutputWire` from the session-start
output wire so `subagent-start.command.output.schema.json` can emit
`const: "SubagentStart"` instead of sharing the session-start
definition.

# Verification

- `cargo nextest run -p codex-hooks`
- `just fix -p codex-hooks`
- `just argument-comment-lint -p codex-hooks -- --all-targets`
This commit is contained in:
Abhinav
2026-05-28 15:55:40 -07:00
committed by GitHub
Unverified
parent bcf2b55957
commit a576be2b73
8 changed files with 84 additions and 103 deletions
+5 -4
View File
@@ -94,7 +94,8 @@ pub(crate) fn parse_session_start(stdout: &str) -> Option<SessionStartOutput> {
let wire: SessionStartCommandOutputWire = parse_json(stdout)?;
Some(session_start_output(
wire.universal,
wire.hook_specific_output,
wire.hook_specific_output
.and_then(|output| output.additional_context),
))
}
@@ -102,15 +103,15 @@ pub(crate) fn parse_subagent_start(stdout: &str) -> Option<SessionStartOutput> {
let wire: SubagentStartCommandOutputWire = parse_json(stdout)?;
Some(session_start_output(
wire.universal,
wire.hook_specific_output,
wire.hook_specific_output
.and_then(|output| output.additional_context),
))
}
fn session_start_output(
universal: HookUniversalOutputWire,
hook_specific_output: Option<crate::schema::SessionStartHookSpecificOutputWire>,
additional_context: Option<String>,
) -> SessionStartOutput {
let additional_context = hook_specific_output.and_then(|output| output.additional_context);
SessionStartOutput {
universal: UniversalOutput::from(universal),
additional_context,