Initial commit
This commit is contained in:
143
hooks/handlers/on-session-end.py
Executable file
143
hooks/handlers/on-session-end.py
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Hook handler for SessionEnd event.
|
||||
Sends macOS notification and logs when a worktree session ends.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def send_macos_notification(title: str, message: str, sound: str = "default"):
|
||||
"""Send a macOS notification using osascript."""
|
||||
script = f'''
|
||||
display notification "{message}" with title "{title}" sound name "{sound}"
|
||||
'''
|
||||
subprocess.run(["osascript", "-e", script], capture_output=True)
|
||||
|
||||
|
||||
def send_terminal_notifier(title: str, message: str, subtitle: str = None):
|
||||
"""Send notification via terminal-notifier if available."""
|
||||
try:
|
||||
cmd = [
|
||||
"terminal-notifier",
|
||||
"-title", title,
|
||||
"-message", message,
|
||||
"-sound", "default",
|
||||
"-group", "worktree-task"
|
||||
]
|
||||
if subtitle:
|
||||
cmd.extend(["-subtitle", subtitle])
|
||||
subprocess.run(cmd, capture_output=True, check=True)
|
||||
return True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
return False
|
||||
|
||||
|
||||
def log_session_end(session_id: str, reason: str, cwd: str):
|
||||
"""Log session end to a file for history tracking."""
|
||||
log_dir = Path.home() / ".claude" / "plugins" / "worktree-task" / "logs"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
log_file = log_dir / "session-history.log"
|
||||
|
||||
entry = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"session_id": session_id,
|
||||
"reason": reason,
|
||||
"cwd": cwd
|
||||
}
|
||||
|
||||
with open(log_file, "a") as f:
|
||||
f.write(json.dumps(entry) + "\n")
|
||||
|
||||
|
||||
def get_session_info() -> dict:
|
||||
"""Try to determine session context."""
|
||||
cwd = os.getcwd()
|
||||
|
||||
info = {
|
||||
"cwd": cwd,
|
||||
"is_worktree": False,
|
||||
"branch": None,
|
||||
"project": None
|
||||
}
|
||||
|
||||
# Get current branch
|
||||
try:
|
||||
branch_result = subprocess.run(
|
||||
["git", "branch", "--show-current"],
|
||||
capture_output=True, text=True, cwd=cwd
|
||||
)
|
||||
if branch_result.returncode == 0:
|
||||
info["branch"] = branch_result.stdout.strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Check if worktree by path pattern
|
||||
if "-" in os.path.basename(cwd) and "worktree" not in cwd.lower():
|
||||
# Might be a worktree like "project-feature-branch"
|
||||
info["is_worktree"] = True
|
||||
|
||||
# Also check git worktree list
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--git-common-dir"],
|
||||
capture_output=True, text=True, cwd=cwd
|
||||
)
|
||||
git_common = result.stdout.strip()
|
||||
git_dir_result = subprocess.run(
|
||||
["git", "rev-parse", "--git-dir"],
|
||||
capture_output=True, text=True, cwd=cwd
|
||||
)
|
||||
git_dir = git_dir_result.stdout.strip()
|
||||
|
||||
# If git-dir != git-common-dir, we're in a worktree
|
||||
if git_common != git_dir and ".git/worktrees" in git_dir:
|
||||
info["is_worktree"] = True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Extract project name
|
||||
info["project"] = os.path.basename(cwd)
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def main():
|
||||
# Read hook input from stdin
|
||||
try:
|
||||
hook_input = json.load(sys.stdin)
|
||||
except json.JSONDecodeError:
|
||||
hook_input = {}
|
||||
|
||||
session_id = hook_input.get("session_id", "unknown")
|
||||
reason = hook_input.get("reason", "unknown") # e.g., "clear", "logout", "exit"
|
||||
|
||||
session_info = get_session_info()
|
||||
|
||||
# Log all worktree session ends
|
||||
if session_info.get("is_worktree"):
|
||||
log_session_end(session_id, reason, session_info.get("cwd", ""))
|
||||
|
||||
branch = session_info.get("branch", "unknown")
|
||||
project = session_info.get("project", "unknown")
|
||||
|
||||
title = "Worktree Session Ended"
|
||||
message = f"Branch: {branch}"
|
||||
subtitle = f"Reason: {reason}"
|
||||
|
||||
# Try terminal-notifier first, fallback to osascript
|
||||
if not send_terminal_notifier(title, message, subtitle):
|
||||
send_macos_notification(title, f"{message} ({reason})")
|
||||
|
||||
# Always exit 0 to not block Claude
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user