diff --git a/src/hooks/claude-code-hooks/config.test.ts b/src/hooks/claude-code-hooks/config.test.ts index ba6220a0c..5de403701 100644 --- a/src/hooks/claude-code-hooks/config.test.ts +++ b/src/hooks/claude-code-hooks/config.test.ts @@ -94,11 +94,12 @@ function getStopCommands(config: Awaited { - const { mergePluginHooksConfigs, setPluginHooksConfigs, clearClaudeHooksConfigCache: _clearCache } = require("./config") + const { mergePluginHooksConfigs, setPluginHooksConfigs, clearClaudeHooksConfigCache: _clearCache, resetPluginHooksState } = require("./config") const { setAdditionalAllowedMcpEnvVars, resetAdditionalAllowedMcpEnvVars } = require("../../features/claude-code-mcp-loader/configure-allowed-env-vars") afterEach(() => { resetAdditionalAllowedMcpEnvVars() + resetPluginHooksState() }) test("#given empty plugin hooks #when merged #then returns base unchanged", () => { @@ -246,7 +247,7 @@ describe("mergePluginHooksConfigs", () => { }) describe("setPluginHooksConfigs", () => { - const { setPluginHooksConfigs, loadClaudeHooksConfig, clearClaudeHooksConfigCache: _clearCache } = require("./config") + const { setPluginHooksConfigs, loadClaudeHooksConfig, clearClaudeHooksConfigCache: _clearCache, resetPluginHooksState } = require("./config") const { resetAdditionalAllowedMcpEnvVars } = require("../../features/claude-code-mcp-loader/configure-allowed-env-vars") let originalWorkingDirectory = "" @@ -258,6 +259,7 @@ describe("setPluginHooksConfigs", () => { afterEach(() => { _clearCache() resetAdditionalAllowedMcpEnvVars() + resetPluginHooksState() process.chdir(originalWorkingDirectory) }) diff --git a/src/hooks/claude-code-hooks/config.ts b/src/hooks/claude-code-hooks/config.ts index 2b9fc99fe..362a2d021 100644 --- a/src/hooks/claude-code-hooks/config.ts +++ b/src/hooks/claude-code-hooks/config.ts @@ -108,6 +108,10 @@ export function clearClaudeHooksConfigCache(): void { configCache.clear() } +export function resetPluginHooksState(): void { + pluginHooksState.clear() +} + function mergeHooksConfig( base: ClaudeHooksConfig, override: ClaudeHooksConfig diff --git a/src/shared/command-executor/execute-hook-command.ts b/src/shared/command-executor/execute-hook-command.ts index d4bd41c39..43c628f2f 100644 --- a/src/shared/command-executor/execute-hook-command.ts +++ b/src/shared/command-executor/execute-hook-command.ts @@ -56,12 +56,20 @@ export async function executeHookCommand( const isWin32 = process.platform === "win32"; + // Keys that are always set from normalized sources and must not be + // overwritten by ambient process.env values during the allowlist merge. + const PROTECTED_ENV_KEYS = new Set(["HOME", "CLAUDE_PROJECT_DIR"]); + let env: Record; if (options?.allowedEnvVars) { const allowedSet = new Set(options.allowedEnvVars); - env = { HOME: home, CLAUDE_PROJECT_DIR: cwd }; + env = { + HOME: home, + CLAUDE_PROJECT_DIR: cwd, + PATH: process.env.PATH, + }; for (const key of Object.keys(process.env)) { - if (allowedSet.has(key)) { + if (allowedSet.has(key) && !PROTECTED_ENV_KEYS.has(key)) { env[key] = process.env[key]; } }