Add SessionEnd hooks for thread teardown (#33895)

## What changed

- Add the `SessionEnd` hook event to hook configuration, protocol schemas, analytics, and the hooks browser.
- Run matching hooks for root threads during shutdown, including app-server archive, delete, idle unload, and graceful shutdown. Flush the transcript first and provide the session ID, transcript path, working directory, and `reason: "other"`.
- Keep teardown bounded: hook output is advisory, the default timeout is one second, configured timeouts are capped at three seconds, and async hooks run synchronously with a warning.

## Testing

- Cover transcript availability, matcher selection, timeout normalization, ignored control output, subagent exclusion, archive/delete ordering, and graceful shutdown of multiple loaded threads.

GitOrigin-RevId: 5d19a658677a137caf836ed5042dcb43f5eb6d1a
This commit is contained in:
Abhinav authored and copyberry committed 2026-07-17 19:58:56 +00:00
1 parent b9680065b0
commit 7bd44085e1
46 files changed
+930 -14

No files matched your search

+8 -3
View File
@@ -16,13 +16,14 @@ pub use declarations::plugin_hook_declarations;
pub use engine::HookListEntry;
pub use events::common::SubagentHookContext;
/// Hook event names as they appear in hooks JSON and config files.
pub const HOOK_EVENT_NAMES: [&str; 10] = [
pub const HOOK_EVENT_NAMES: [&str; 11] = [
"PreToolUse",
"PermissionRequest",
"PostToolUse",
"PreCompact",
"PostCompact",
"SessionStart",
"SessionEnd",
"UserPromptSubmit",
"SubagentStart",
"SubagentStop",
@@ -33,14 +34,15 @@ pub const HOOK_EVENT_NAMES: [&str; 10] = [
///
/// Other events can appear in hooks JSON, but Codex ignores their matcher
/// fields because those events do not dispatch against a tool, compaction
/// trigger, or session-start source.
pub const HOOK_EVENT_NAMES_WITH_MATCHERS: [&str; 8] = [
/// trigger, session-start source, or session-end reason.
pub const HOOK_EVENT_NAMES_WITH_MATCHERS: [&str; 9] = [
"PreToolUse",
"PermissionRequest",
"PostToolUse",
"PreCompact",
"PostCompact",
"SessionStart",
"SessionEnd",
"SubagentStart",
"SubagentStop",
];
@@ -56,6 +58,8 @@ pub use events::post_tool_use::PostToolUseOutcome;
pub use events::post_tool_use::PostToolUseRequest;
pub use events::pre_tool_use::PreToolUseOutcome;
pub use events::pre_tool_use::PreToolUseRequest;
pub use events::session_end::SessionEndOutcome;
pub use events::session_end::SessionEndRequest;
pub use events::session_start::SessionStartOutcome;
pub use events::session_start::SessionStartRequest;
pub use events::session_start::SessionStartSource;
@@ -89,6 +93,7 @@ pub fn hook_event_key_label(event_name: HookEventName) -> &'static str {
HookEventName::PreCompact => "pre_compact",
HookEventName::PostCompact => "post_compact",
HookEventName::SessionStart => "session_start",
HookEventName::SessionEnd => "session_end",
HookEventName::UserPromptSubmit => "user_prompt_submit",
HookEventName::SubagentStart => "subagent_start",
HookEventName::SubagentStop => "subagent_stop",