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

Function execCommandHook

src/utils/hooks.ts:747–1335  ·  view source on GitHub ↗

* Execute a command-based hook using bash or PowerShell. * * Shell resolution: hook.shell → 'bash'. PowerShell hooks spawn pwsh * with -NoProfile -NonInteractive -Command and skip bash-specific prep * (POSIX path conversion, .sh auto-prepend, CLAUDE_CODE_SHELL_PREFIX). * See docs/design/ps-shel

(
  hook: HookCommand & { type: 'command' },
  hookEvent: HookEvent | 'StatusLine' | 'FileSuggestion',
  hookName: string,
  jsonInput: string,
  signal: AbortSignal,
  hookId: string,
  hookIndex?: number,
  pluginRoot?: string,
  pluginId?: string,
  skillRoot?: string,
  forceSyncExecution?: boolean,
  requestPrompt?: (request: PromptRequest) => Promise<PromptResponse>,
)

Source from the content-addressed store, hash-verified

745 * See docs/design/ps-shell-selection.md §5.1.
746 */
747async function execCommandHook(
748 hook: HookCommand & { type: 'command' },
749 hookEvent: HookEvent | 'StatusLine' | 'FileSuggestion',
750 hookName: string,
751 jsonInput: string,
752 signal: AbortSignal,
753 hookId: string,
754 hookIndex?: number,
755 pluginRoot?: string,
756 pluginId?: string,
757 skillRoot?: string,
758 forceSyncExecution?: boolean,
759 requestPrompt?: (request: PromptRequest) => Promise<PromptResponse>,
760): Promise<{
761 stdout: string
762 stderr: string
763 output: string
764 status: number
765 aborted?: boolean
766 backgrounded?: boolean
767}> {
768 // Gated to once-per-session events to keep diag_log volume bounded.
769 // started/completed live inside the try/finally so setup-path throws
770 // don't orphan a started marker — that'd be indistinguishable from a hang.
771 const shouldEmitDiag =
772 hookEvent === 'SessionStart' ||
773 hookEvent === 'Setup' ||
774 hookEvent === 'SessionEnd'
775 const diagStartMs = Date.now()
776 let diagExitCode: number | undefined
777 let diagAborted = false
778
779 const isWindows = getPlatform() === 'windows'
780
781 // --
782 // Per-hook shell selection (phase 1 of docs/design/ps-shell-selection.md).
783 // Resolution order: hook.shell → DEFAULT_HOOK_SHELL. The defaultShell
784 // fallback (settings.defaultShell) is phase 2 — not wired yet.
785 //
786 // The bash path is the historical default and stays unchanged. The
787 // PowerShell path deliberately skips the Windows-specific bash
788 // accommodations (cygpath conversion, .sh auto-prepend, POSIX-quoted
789 // SHELL_PREFIX).
790 const shellType = hook.shell ?? DEFAULT_HOOK_SHELL
791
792 const isPowerShell = shellType === 'powershell'
793
794 // --
795 // Windows bash path: hooks run via Git Bash (Cygwin), NOT cmd.exe.
796 //
797 // This means every path we put into env vars or substitute into the command
798 // string MUST be a POSIX path (/c/Users/foo), not a Windows path
799 // (C:\Users\foo or C:/Users/foo). Git Bash cannot resolve Windows paths.
800 //
801 // windowsPathToPosixPath() is pure-JS regex conversion (no cygpath shell-out):
802 // C:\Users\foo -> /c/Users/foo, UNC preserved, slashes flipped. Memoized
803 // (LRU-500) so repeated calls are cheap.
804 //

Callers 4

executeHooksFunction · 0.85
executeHooksOutsideREPLFunction · 0.85
executeStatusLineCommandFunction · 0.85

Calls 15

getPlatformFunction · 0.85
getProjectRootFunction · 0.85
pathExistsFunction · 0.85
getPluginDataDirFunction · 0.85
formatShellPrefixCommandFunction · 0.85
subprocessEnvFunction · 0.85
getHookEnvFilePathFunction · 0.85
getCwdFunction · 0.85
getOriginalCwdFunction · 0.85
logForDebuggingFunction · 0.85
getCachedPowerShellPathFunction · 0.85

Tested by

no test coverage detected