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