(
reason: ExitReason,
options?: {
getAppState?: () => AppState
setAppState?: (updater: (prev: AppState) => AppState) => void
signal?: AbortSignal
timeoutMs?: number
},
)
| 4190 | * @returns Promise that resolves when all hooks complete |
| 4191 | */ |
| 4192 | export async function executeSessionEndHooks( |
| 4193 | reason: ExitReason, |
| 4194 | options?: { |
| 4195 | getAppState?: () => AppState |
| 4196 | setAppState?: (updater: (prev: AppState) => AppState) => void |
| 4197 | signal?: AbortSignal |
| 4198 | timeoutMs?: number |
| 4199 | }, |
| 4200 | ): Promise<void> { |
| 4201 | const { |
| 4202 | getAppState, |
| 4203 | setAppState, |
| 4204 | signal, |
| 4205 | timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS, |
| 4206 | } = options || {} |
| 4207 | |
| 4208 | const hookInput = { |
| 4209 | ...createBaseHookInput(undefined), |
| 4210 | hook_event_name: 'SessionEnd' as const, |
| 4211 | reason, |
| 4212 | } as unknown as SessionEndHookInput |
| 4213 | |
| 4214 | const results = await executeHooksOutsideREPL({ |
| 4215 | getAppState, |
| 4216 | hookInput, |
| 4217 | matchQuery: reason, |
| 4218 | signal, |
| 4219 | timeoutMs, |
| 4220 | }) |
| 4221 | |
| 4222 | // During shutdown, Ink is unmounted so we can write directly to stderr |
| 4223 | for (const result of results) { |
| 4224 | if (!result.succeeded && result.output) { |
| 4225 | process.stderr.write( |
| 4226 | `SessionEnd hook [${result.command}] failed: ${result.output}\n`, |
| 4227 | ) |
| 4228 | } |
| 4229 | } |
| 4230 | |
| 4231 | // Clear session hooks after execution |
| 4232 | if (setAppState) { |
| 4233 | const sessionId = getSessionId() |
| 4234 | clearSessionHooks(setAppState, sessionId) |
| 4235 | } |
| 4236 | } |
| 4237 | |
| 4238 | /** |
| 4239 | * Execute permission request hooks if configured |
no test coverage detected