Initial commit
This commit is contained in:
207
hooks/session_start.py
Executable file
207
hooks/session_start.py
Executable file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
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(".claude/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, 'r') 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, 'r') 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(
|
||||
["python3", 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()
|
||||
Reference in New Issue
Block a user