MCPcopy Create free account
hub / github.com/WJX20/claude-code / executeHooksOutsideREPL

Function executeHooksOutsideREPL

src/utils/hooks.ts:3086–3467  ·  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

3084 * @returns Array of HookOutsideReplResult objects containing command, succeeded, and output
3085 */
3086async function executeHooksOutsideREPL({
3087 getAppState,
3088 hookInput,
3089 matchQuery,
3090 signal,
3091 timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS,
3092}: {
3093 getAppState?: () => AppState
3094 hookInput: HookInput
3095 matchQuery?: string
3096 signal?: AbortSignal
3097 timeoutMs: number
3098}): Promise<HookOutsideReplResult[]> {
3099 if (isEnvTruthy(process.env.CLAUDE_CODE_SIMPLE)) {
3100 return []
3101 }
3102
3103 const hookEvent = hookInput.hook_event_name
3104 const hookName = matchQuery ? `${hookEvent}:${matchQuery}` : hookEvent
3105 if (shouldDisableAllHooksIncludingManaged()) {
3106 logForDebugging(
3107 `Skipping hooks for ${hookName} due to 'disableAllHooks' managed setting`,
3108 )
3109 return []
3110 }
3111
3112 // SECURITY: ALL hooks require workspace trust in interactive mode
3113 // This centralized check prevents RCE vulnerabilities for all current and future hooks
3114 if (shouldSkipHookDueToTrust()) {
3115 logForDebugging(
3116 `Skipping ${hookName} hook execution - workspace trust not accepted`,
3117 )
3118 return []
3119 }
3120
3121 const appState = getAppState ? getAppState() : undefined
3122 // Use main session ID for outside-REPL hooks
3123 const sessionId = getSessionId()
3124 const matchingHooks = await getMatchingHooks(
3125 appState,
3126 sessionId,
3127 hookEvent,
3128 hookInput,
3129 )
3130 if (matchingHooks.length === 0) {
3131 return []
3132 }
3133
3134 if (signal?.aborted) {
3135 return []
3136 }
3137
3138 const userHooks = matchingHooks.filter(h => !isInternalHook(h))
3139 if (userHooks.length > 0) {
3140 const pluginHookCounts = getPluginHookCounts(userHooks)
3141 const hookTypeCounts = getHookTypeCounts(userHooks)
3142 logEvent(`tengu_run_hook`, {
3143 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