MCPcopy
hub / github.com/codeaashu/claude-code / executeHooksOutsideREPL

Function executeHooksOutsideREPL

src/utils/hooks.ts:3003–3381  ·  view source on GitHub ↗

* Execute hooks outside of the REPL (e.g. notifications, session end) * * Unlike executeHooks() which yields messages that are exposed to the model as * system messages, this function only logs errors via logForDebugging (visible * with --debug). Callers that need to surface errors to users shou

({
  getAppState,
  hookInput,
  matchQuery,
  signal,
  timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS,
}: {
  getAppState?: () => AppState
  hookInput: HookInput
  matchQuery?: string
  signal?: AbortSignal
  timeoutMs: number
})

Source from the content-addressed store, hash-verified

3001 * @returns Array of HookOutsideReplResult objects containing command, succeeded, and output
3002 */
3003async function executeHooksOutsideREPL({
3004 getAppState,
3005 hookInput,
3006 matchQuery,
3007 signal,
3008 timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS,
3009}: {
3010 getAppState?: () => AppState
3011 hookInput: HookInput
3012 matchQuery?: string
3013 signal?: AbortSignal
3014 timeoutMs: number
3015}): Promise<HookOutsideReplResult[]> {
3016 if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) {
3017 return []
3018 }
3019
3020 const hookEvent = hookInput.hook_event_name
3021 const hookName = matchQuery ? `${hookEvent}:${matchQuery}` : hookEvent
3022 if (shouldDisableAllHooksIncludingManaged()) {
3023 logForDebugging(
3024 `Skipping hooks for ${hookName} due to 'disableAllHooks' managed setting`,
3025 )
3026 return []
3027 }
3028
3029 // SECURITY: ALL hooks require workspace trust in interactive mode
3030 // This centralized check prevents RCE vulnerabilities for all current and future hooks
3031 if (shouldSkipHookDueToTrust()) {
3032 logForDebugging(
3033 `Skipping ${hookName} hook execution - workspace trust not accepted`,
3034 )
3035 return []
3036 }
3037
3038 const appState = getAppState ? getAppState() : undefined
3039 // Use main session ID for outside-REPL hooks
3040 const sessionId = getSessionId()
3041 const matchingHooks = await getMatchingHooks(
3042 appState,
3043 sessionId,
3044 hookEvent,
3045 hookInput,
3046 )
3047 if (matchingHooks.length === 0) {
3048 return []
3049 }
3050
3051 if (signal?.aborted) {
3052 return []
3053 }
3054
3055 const userHooks = matchingHooks.filter(h => !isInternalHook(h))
3056 if (userHooks.length > 0) {
3057 const pluginHookCounts = getPluginHookCounts(userHooks)
3058 const hookTypeCounts = getHookTypeCounts(userHooks)
3059 logEvent(`tengu_run_hook`, {
3060 hookName:

Callers 12

executeNotificationHooksFunction · 0.85
executeStopFailureHooksFunction · 0.85
executePreCompactHooksFunction · 0.85
executePostCompactHooksFunction · 0.85
executeSessionEndHooksFunction · 0.85
executeConfigChangeHooksFunction · 0.85
executeEnvHooksFunction · 0.85
executeElicitationHooksFunction · 0.85

Calls 15

isEnvTruthyFunction · 0.85
logForDebuggingFunction · 0.85
shouldSkipHookDueToTrustFunction · 0.85
getSessionIdFunction · 0.85
getMatchingHooksFunction · 0.85
isInternalHookFunction · 0.85
getPluginHookCountsFunction · 0.85
getHookTypeCountsFunction · 0.85
logEventFunction · 0.85
jsonStringifyFunction · 0.85

Tested by

no test coverage detected