11#!/usr/bin/env python3
2+ __version__ = "0.1.10"
3+
24# /// script
35# requires-python = ">=3.9"
46# dependencies = [
@@ -485,7 +487,8 @@ def _get_fallback_sound(self, event_type: str) -> Optional[Path]:
485487
486488 def handle_hook (self , hook_data : Dict [str , Any ]):
487489 """Process hook data and generate appropriate notification"""
488- hook_type = hook_data .get ("hook_event_name" , "unknown" )
490+ # Claude Code uses "event" field, not "hook_event_name"
491+ hook_type = hook_data .get ("event" , hook_data .get ("hook_event_name" , "unknown" ))
489492 logger .info (f"Processing hook type: { hook_type } " )
490493
491494 # Log all available fields for this hook type
@@ -498,23 +501,43 @@ def handle_hook(self, hook_data: Dict[str, Any]):
498501 # Load replacements configuration
499502 replacements = load_replacements ()
500503
501- # Extract session context
502- session_id = hook_data .get ("session_id" , "unknown" )
503- cwd = hook_data .get ("cwd" , "" )
504- project_name = resolve_project_name (session_id , cwd )
504+ # Extract session context - Claude Code uses camelCase "sessionId"
505+ session_id = hook_data .get ("sessionId" , hook_data .get ("session_id" , "unknown" ))
506+ cwd = hook_data .get ("cwd" , os .getcwd ()) # Fall back to current working directory
507+
508+ # If no session ID but we have cwd, try to extract project name from path
509+ if session_id == "unknown" and cwd :
510+ # Try to extract project name from cwd
511+ path_parts = Path (cwd ).parts
512+ # Look for common project directories
513+ if "code" in path_parts :
514+ idx = path_parts .index ("code" )
515+ if idx + 1 < len (path_parts ):
516+ project_name = path_parts [idx + 1 ]
517+ else :
518+ project_name = Path (cwd ).name
519+ else :
520+ project_name = Path (cwd ).name
521+
522+ logger .info (f"No session ID, extracted project from cwd: { project_name } " )
523+ else :
524+ project_name = resolve_project_name (session_id , cwd )
525+ logger .info (f"Resolved project name from session: { project_name } " )
505526
506527 # Apply project name replacement
507528 display_project_name = apply_project_name_replacement (project_name , replacements )
508529
509530 cwd_name = Path (cwd ).name if cwd else "unknown"
510531
511532 if hook_type == "PreToolUse" :
512- tool_name = hook_data .get ("tool_name" , "unknown" )
533+ # Claude Code sends "tool" not "tool_name"
534+ tool_name = hook_data .get ("tool" , hook_data .get ("tool_name" , "unknown" ))
513535
514536 # Only notify for truly dangerous operations
515537 # Skip notifications for common safe operations
516538 if tool_name == "Bash" :
517- command = hook_data .get ("tool_input" , {}).get ("command" , "" )
539+ # Claude Code sends "parameters" not "tool_input"
540+ command = hook_data .get ("parameters" , hook_data .get ("tool_input" , {})).get ("command" , "" )
518541 # Skip common safe commands
519542 safe_prefixes = ["echo" , "pwd" , "ls" , "cat" , "head" , "tail" , "grep" , "find" , "which" ]
520543 if any (command .strip ().startswith (prefix ) for prefix in safe_prefixes ):
@@ -540,7 +563,8 @@ def handle_hook(self, hook_data: Dict[str, Any]):
540563
541564 # Skip most file edits unless they're system files
542565 elif tool_name in ["Write" , "MultiEdit" , "Edit" ]:
543- file_path = hook_data .get ("tool_input" , {}).get ("file_path" , "" )
566+ # Claude Code sends "parameters" not "tool_input"
567+ file_path = hook_data .get ("parameters" , hook_data .get ("tool_input" , {})).get ("file_path" , "" )
544568 # Only notify for system/config files
545569 if any (x in file_path for x in ["/etc/" , "/usr/" , ".env" , "config" , "secret" ]):
546570 event_type = "tool_activity"
@@ -550,8 +574,10 @@ def handle_hook(self, hook_data: Dict[str, Any]):
550574
551575 elif hook_type == "PostToolUse" :
552576 # Check for errors in tool response
553- tool_response = hook_data .get ("tool_response" , {})
554- tool_name = hook_data .get ("tool_name" , "unknown" )
577+ # Claude Code might send "response" or "tool_response"
578+ tool_response = hook_data .get ("response" , hook_data .get ("tool_response" , {}))
579+ # Claude Code sends "tool" not "tool_name"
580+ tool_name = hook_data .get ("tool" , hook_data .get ("tool_name" , "unknown" ))
555581
556582 # Debug log the tool response structure
557583 logger .debug (f"PostToolUse response for { tool_name } : { json .dumps (tool_response , indent = 2 ) if isinstance (tool_response , dict ) else tool_response } " )
0 commit comments