(
reason: ExitReason,
options?: {
getAppState?: () => AppState
setAppState?: (updater: (prev: AppState) => AppState) => void
signal?: AbortSignal
timeoutMs?: number
},
)
| 4099 | * @returns Promise that resolves when all hooks complete |
| 4100 | */ |
| 4101 | export async function executeSessionEndHooks( |
| 4102 | reason: ExitReason, |
| 4103 | options?: { |
| 4104 | getAppState?: () => AppState |
| 4105 | setAppState?: (updater: (prev: AppState) => AppState) => void |
| 4106 | signal?: AbortSignal |
| 4107 | timeoutMs?: number |
| 4108 | }, |
| 4109 | ): Promise<void> { |
| 4110 | const { |
| 4111 | getAppState, |
| 4112 | setAppState, |
| 4113 | signal, |
| 4114 | timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS, |
| 4115 | } = options || {} |
| 4116 | |
| 4117 | const hookInput: SessionEndHookInput = { |
| 4118 | ...createBaseHookInput(undefined), |
| 4119 | hook_event_name: 'SessionEnd', |
| 4120 | reason, |
| 4121 | } |
| 4122 | |
| 4123 | const results = await executeHooksOutsideREPL({ |
| 4124 | getAppState, |
| 4125 | hookInput, |
| 4126 | matchQuery: reason, |
| 4127 | signal, |
| 4128 | timeoutMs, |
| 4129 | }) |
| 4130 | |
| 4131 | // During shutdown, Ink is unmounted so we can write directly to stderr |
| 4132 | for (const result of results) { |
| 4133 | if (!result.succeeded && result.output) { |
| 4134 | process.stderr.write( |
| 4135 | `SessionEnd hook [${result.command}] failed: ${result.output}\n`, |
| 4136 | ) |
| 4137 | } |
| 4138 | } |
| 4139 | |
| 4140 | // Clear session hooks after execution |
| 4141 | if (setAppState) { |
| 4142 | const sessionId = getSessionId() |
| 4143 | clearSessionHooks(setAppState, sessionId) |
| 4144 | } |
| 4145 | } |
| 4146 | |
| 4147 | /** |
| 4148 | * Execute permission request hooks if configured |
no test coverage detected