MCPcopy Create free account
hub / github.com/Noumena-Network/code / execCommandHook

Function execCommandHook

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

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

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
getCachedPowerShellPathFunction · 0.85
spawnFunction · 0.85

Tested by

no test coverage detected