#!/usr/bin/env -S uv run --script # /// script # requires-python = ">=3.11" # dependencies = [ # "python-dotenv", # ] # /// import argparse import json import subprocess import sys from datetime import datetime from pathlib import Path try: from dotenv import load_dotenv load_dotenv() except ImportError: pass # dotenv is optional def log_session_start(input_data): """Log session start event to logs directory.""" # Ensure logs directory exists log_dir = Path("logs") log_dir.mkdir(parents=True, exist_ok=True) log_file = log_dir / "session_start.json" # Read existing log data or initialize empty list if log_file.exists(): with open(log_file) as f: try: log_data = json.load(f) except (json.JSONDecodeError, ValueError): log_data = [] else: log_data = [] # Append the entire input data log_data.append(input_data) # Write back to file with formatting with open(log_file, "w") as f: json.dump(log_data, f, indent=2) def get_git_status(): """Get current git status information.""" try: # Get current branch branch_result = subprocess.run( ["git", "rev-parse", "--abbrev-ref", "HEAD"], capture_output=True, text=True, timeout=5, ) current_branch = ( branch_result.stdout.strip() if branch_result.returncode == 0 else "unknown" ) # Get uncommitted changes count status_result = subprocess.run( ["git", "status", "--porcelain"], capture_output=True, text=True, timeout=5 ) if status_result.returncode == 0: changes = ( status_result.stdout.strip().split("\n") if status_result.stdout.strip() else [] ) uncommitted_count = len(changes) else: uncommitted_count = 0 return current_branch, uncommitted_count except Exception: return None, None def get_recent_issues(): """Get recent GitHub issues if gh CLI is available.""" try: # Check if gh is available gh_check = subprocess.run(["which", "gh"], capture_output=True) if gh_check.returncode != 0: return None # Get recent open issues result = subprocess.run( ["gh", "issue", "list", "--limit", "5", "--state", "open"], capture_output=True, text=True, timeout=10, ) if result.returncode == 0 and result.stdout.strip(): return result.stdout.strip() except Exception: pass return None def load_development_context(source): """Load relevant development context based on session source.""" context_parts = [] # Add timestamp context_parts.append( f"Session started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" ) context_parts.append(f"Session source: {source}") # Add git information branch, changes = get_git_status() if branch: context_parts.append(f"Git branch: {branch}") if changes > 0: context_parts.append(f"Uncommitted changes: {changes} files") # Load project-specific context files if they exist context_files = [ ".claude/CONTEXT.md", ".claude/TODO.md", "TODO.md", ".github/ISSUE_TEMPLATE.md", ] for file_path in context_files: if Path(file_path).exists(): try: with open(file_path) as f: content = f.read().strip() if content: context_parts.append(f"\n--- Content from {file_path} ---") context_parts.append( content[:1000] ) # Limit to first 1000 chars except Exception: pass # Add recent issues if available issues = get_recent_issues() if issues: context_parts.append("\n--- Recent GitHub Issues ---") context_parts.append(issues) return "\n".join(context_parts) def main(): try: # Parse command line arguments parser = argparse.ArgumentParser() parser.add_argument( "--load-context", action="store_true", help="Load development context at session start", ) parser.add_argument( "--announce", action="store_true", help="Announce session start via TTS" ) args = parser.parse_args() # Read JSON input from stdin input_data = json.loads(sys.stdin.read()) # Extract fields session_id = input_data.get("session_id", "unknown") source = input_data.get("source", "unknown") # "startup", "resume", or "clear" # Log the session start event log_session_start(input_data) # Load development context if requested if args.load_context: context = load_development_context(source) if context: # Using JSON output to add context output = { "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": context, } } print(json.dumps(output)) sys.exit(0) # Announce session start if requested if args.announce: try: # Try to use TTS to announce session start script_dir = Path(__file__).parent tts_script = script_dir / "utils" / "tts" / "pyttsx3_tts.py" if tts_script.exists(): messages = { "startup": "Claude Code session started", "resume": "Resuming previous session", "clear": "Starting fresh session", } message = messages.get(source, "Session started") subprocess.run( ["uv", "run", str(tts_script), message], capture_output=True, timeout=5, ) except Exception: pass # Success sys.exit(0) except json.JSONDecodeError: # Handle JSON decode errors gracefully sys.exit(0) except Exception: # Handle any other errors gracefully sys.exit(0) if __name__ == "__main__": main()