MCPcopy Index your code
hub / github.com/codeaashu/claude-code / executeInBackground

Function executeInBackground

src/utils/hooks.ts:184–265  ·  view source on GitHub ↗
({
  processId,
  hookId,
  shellCommand,
  asyncResponse,
  hookEvent,
  hookName,
  command,
  asyncRewake,
  pluginId,
}: {
  processId: string
  hookId: string
  shellCommand: ShellCommand
  asyncResponse: AsyncHookJSONOutput
  hookEvent: HookEvent | 'StatusLine' | 'FileSuggestion'
  hookName: string
  command: string
  asyncRewake?: boolean
  pluginId?: string
})

Source from the content-addressed store, hash-verified

182}
183
184function executeInBackground({
185 processId,
186 hookId,
187 shellCommand,
188 asyncResponse,
189 hookEvent,
190 hookName,
191 command,
192 asyncRewake,
193 pluginId,
194}: {
195 processId: string
196 hookId: string
197 shellCommand: ShellCommand
198 asyncResponse: AsyncHookJSONOutput
199 hookEvent: HookEvent | 'StatusLine' | 'FileSuggestion'
200 hookName: string
201 command: string
202 asyncRewake?: boolean
203 pluginId?: string
204}): boolean {
205 if (asyncRewake) {
206 // asyncRewake hooks bypass the registry entirely. On completion, if exit
207 // code 2 (blocking error), enqueue as a task-notification so it wakes the
208 // model via useQueueProcessor (idle) or gets injected mid-query via
209 // queued_command attachments (busy).
210 //
211 // NOTE: We deliberately do NOT call shellCommand.background() here, because
212 // it calls taskOutput.spillToDisk() which breaks in-memory stdout/stderr
213 // capture (getStderr() returns '' in disk mode). The StreamWrappers stay
214 // attached and pipe data into the in-memory TaskOutput buffers. The abort
215 // handler already no-ops on 'interrupt' reason (user submitted a new
216 // message), so the hook survives new prompts. A hard cancel (Escape) WILL
217 // kill the hook via the abort handler, which is the desired behavior.
218 void shellCommand.result.then(async result => {
219 // result resolves on 'exit', but stdio 'data' events may still be
220 // pending. Yield to I/O so the StreamWrapper data handlers drain into
221 // TaskOutput before we read it.
222 await new Promise(resolve => setImmediate(resolve))
223 const stdout = await shellCommand.taskOutput.getStdout()
224 const stderr = shellCommand.taskOutput.getStderr()
225 shellCommand.cleanup()
226 emitHookResponse({
227 hookId,
228 hookName,
229 hookEvent,
230 output: stdout + stderr,
231 stdout,
232 stderr,
233 exitCode: result.code,
234 outcome: result.code === 0 ? 'success' : 'error',
235 })
236 if (result.code === 2) {
237 enqueuePendingNotification({
238 value: wrapInSystemReminder(
239 `Stop hook blocking error from command "${hookName}": ${stderr || stdout}`,
240 ),
241 mode: 'task-notification',

Callers 1

execCommandHookFunction · 0.85

Calls 8

emitHookResponseFunction · 0.85
wrapInSystemReminderFunction · 0.85
registerPendingAsyncHookFunction · 0.85
getStdoutMethod · 0.80
getStderrMethod · 0.80
cleanupMethod · 0.45
backgroundMethod · 0.45

Tested by

no test coverage detected