From 4ec9db8c38d3a7aebfa02d7d109aa8c976b58ae1 Mon Sep 17 00:00:00 2001 From: Hunter Luisi <319161+hluisi@users.noreply.github.com> Date: Sat, 3 Jan 2026 12:45:18 -0800 Subject: [PATCH] fix: security hook cwd extraction and PATH issues (#555, #556) (#587) * fix(security): extract cwd from input_data instead of context The bash_security_hook was checking context.cwd, but the Claude Agent SDK passes cwd in input_data dict, not context object. This caused the hook to always fall back to os.getcwd() which returns the runner directory (apps/backend/) instead of the project directory. According to Claude Agent SDK docs, PreToolUse hooks receive cwd in input_data, not context. The context parameter is reserved for future use in the Python SDK. Fixes #555 Signed-off-by: Hunter Luisi * fix(frontend): use getAugmentedEnv for PATH in agent processes When Electron launches from Finder/Dock on macOS, process.env.PATH is minimal and doesn't include user shell paths. This caused tools like dotnet, cargo, etc. to fail with 'command not found'. Solution: 1. Use getAugmentedEnv() in agent-process.ts instead of raw process.env 2. Add /usr/local/share/dotnet and ~/.dotnet/tools to COMMON_BIN_PATHS getAugmentedEnv() already exists and is used throughout the frontend for Git/GitHub/GitLab operations. It adds common tool directories to PATH based on platform. Fixes #556 Signed-off-by: Hunter Luisi * chore: pin electron version to 39.2.7 Pinning electron version (removing caret) so electron-builder can compute the version from installed modules in monorepo setup. Signed-off-by: Hunter Luisi * fix: handle empty cwd fallback and add Linux .NET paths - Use 'or' pattern for cwd fallback to handle empty string case - Add ~/.dotnet/tools to Linux COMMON_BIN_PATHS for parity with macOS Addresses review suggestions from Auto Claude PR Review. --------- Signed-off-by: Hunter Luisi Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> --- apps/backend/security/hooks.py | 7 ++----- apps/frontend/src/main/agent/agent-process.ts | 6 +++++- apps/frontend/src/main/env-utils.ts | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/backend/security/hooks.py b/apps/backend/security/hooks.py index 35152d44..b606c17c 100644 --- a/apps/backend/security/hooks.py +++ b/apps/backend/security/hooks.py @@ -65,11 +65,8 @@ async def bash_security_hook( if not command: return {} - # Get the working directory from context or use current directory - # In the actual client, this would be set by the ClaudeSDKClient - cwd = os.getcwd() - if context and hasattr(context, "cwd"): - cwd = context.cwd + # Get the working directory from input_data (SDK passes it there, not in context) + cwd = input_data.get("cwd") or os.getcwd() # Get or create security profile # Note: In actual use, spec_dir would be passed through context diff --git a/apps/frontend/src/main/agent/agent-process.ts b/apps/frontend/src/main/agent/agent-process.ts index 8f6b9a77..e96cb5c8 100644 --- a/apps/frontend/src/main/agent/agent-process.ts +++ b/apps/frontend/src/main/agent/agent-process.ts @@ -16,6 +16,7 @@ import { buildMemoryEnvVars } from '../memory-env-builder'; import { readSettingsFile } from '../settings-utils'; import type { AppSettings } from '../../shared/types/settings'; import { getOAuthModeClearVars } from './env-utils'; +import { getAugmentedEnv } from '../env-utils'; /** * Process spawning and lifecycle management @@ -55,8 +56,11 @@ export class AgentProcessManager { extraEnv: Record ): NodeJS.ProcessEnv { const profileEnv = getProfileEnv(); + // Use getAugmentedEnv() to ensure common tool paths (dotnet, homebrew, etc.) + // are available even when app is launched from Finder/Dock + const augmentedEnv = getAugmentedEnv(); return { - ...process.env, + ...augmentedEnv, ...extraEnv, ...profileEnv, PYTHONUNBUFFERED: '1', diff --git a/apps/frontend/src/main/env-utils.ts b/apps/frontend/src/main/env-utils.ts index 9a1325ce..c4d01ec0 100644 --- a/apps/frontend/src/main/env-utils.ts +++ b/apps/frontend/src/main/env-utils.ts @@ -64,15 +64,18 @@ const COMMON_BIN_PATHS: Record = { darwin: [ '/opt/homebrew/bin', // Apple Silicon Homebrew '/usr/local/bin', // Intel Homebrew / system + '/usr/local/share/dotnet', // .NET SDK '/opt/homebrew/sbin', // Apple Silicon Homebrew sbin '/usr/local/sbin', // Intel Homebrew sbin '~/.local/bin', // User-local binaries (Claude CLI) + '~/.dotnet/tools', // .NET global tools ], linux: [ '/usr/local/bin', '/usr/bin', // System binaries (Python, etc.) '/snap/bin', // Snap packages '~/.local/bin', // User-local binaries + '~/.dotnet/tools', // .NET global tools '/usr/sbin', // System admin binaries ], win32: [