(
reason: ExitReason,
options?: {
getAppState?: () => AppState
setAppState?: (updater: (prev: AppState) => AppState) => void
signal?: AbortSignal
timeoutMs?: number
},
)
| 4254 | * @returns Promise that resolves when all hooks complete |
| 4255 | */ |
| 4256 | export async function executeSessionEndHooks( |
| 4257 | reason: ExitReason, |
| 4258 | options?: { |
| 4259 | getAppState?: () => AppState |
| 4260 | setAppState?: (updater: (prev: AppState) => AppState) => void |
| 4261 | signal?: AbortSignal |
| 4262 | timeoutMs?: number |
| 4263 | }, |
| 4264 | ): Promise<void> { |
| 4265 | const { |
| 4266 | getAppState, |
| 4267 | setAppState, |
| 4268 | signal, |
| 4269 | timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS, |
| 4270 | } = options || {} |
| 4271 | |
| 4272 | const hookInput = { |
| 4273 | ...createBaseHookInput(undefined), |
| 4274 | hook_event_name: 'SessionEnd' as const, |
| 4275 | reason, |
| 4276 | } as unknown as SessionEndHookInput |
| 4277 | |
| 4278 | const results = await executeHooksOutsideREPL({ |
| 4279 | getAppState, |
| 4280 | hookInput, |
| 4281 | matchQuery: reason, |
| 4282 | signal, |
| 4283 | timeoutMs, |
| 4284 | }) |
| 4285 | |
| 4286 | // During shutdown, Ink is unmounted so we can write directly to stderr |
| 4287 | for (const result of results) { |
| 4288 | if (!result.succeeded && result.output) { |
| 4289 | process.stderr.write( |
| 4290 | `SessionEnd hook [${result.command}] failed: ${result.output}\n`, |
| 4291 | ) |
| 4292 | } |
| 4293 | } |
| 4294 | |
| 4295 | // Clear session hooks after execution |
| 4296 | if (setAppState) { |
| 4297 | const sessionId = getSessionId() |
| 4298 | clearSessionHooks(setAppState, sessionId) |
| 4299 | } |
| 4300 | } |
| 4301 | |
| 4302 | /** |
| 4303 | * Execute permission request hooks if configured |
no test coverage detected