check-mail.sh 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #!/bin/bash
  2. # hooks/check-mail.sh
  3. # PreToolUse hook - checks for unread inter-session mail
  4. # Runs on every tool call. Silent when inbox is empty.
  5. # Uses hash-based project identity (resolves case sensitivity).
  6. MAIL_DB="$HOME/.claude/mail.db"
  7. COOLDOWN_SECONDS=10
  8. # Skip if disabled for this project
  9. [ -f ".claude/agentmail.disable" ] && exit 0
  10. # Skip if no database exists yet
  11. [ -f "$MAIL_DB" ] || exit 0
  12. # Project identity: git root commit hash, fallback to path hash
  13. ROOT_COMMIT=$(git rev-list --max-parents=0 HEAD 2>/dev/null | head -1)
  14. if [ -n "$ROOT_COMMIT" ]; then
  15. PROJECT_HASH="${ROOT_COMMIT:0:6}"
  16. else
  17. CANONICAL=$(cd "$PWD" && pwd -P)
  18. PROJECT_HASH=$(printf '%s' "$CANONICAL" | shasum -a 256 | cut -c1-6)
  19. fi
  20. COOLDOWN_FILE="/tmp/agentmail_${PROJECT_HASH}"
  21. # Cooldown: skip if checked recently (within COOLDOWN_SECONDS)
  22. if [ -f "$COOLDOWN_FILE" ]; then
  23. last_check=$(stat -c %Y "$COOLDOWN_FILE" 2>/dev/null || stat -f %m "$COOLDOWN_FILE" 2>/dev/null || echo 0)
  24. now=$(date +%s)
  25. if [ $((now - last_check)) -lt $COOLDOWN_SECONDS ]; then
  26. exit 0
  27. fi
  28. fi
  29. touch "$COOLDOWN_FILE"
  30. # Single fast query - count unread
  31. UNREAD=$(sqlite3 "$MAIL_DB" "SELECT COUNT(*) FROM messages WHERE to_project='${PROJECT_HASH}' AND read=0;" 2>/dev/null)
  32. # Silent exit if no mail
  33. [ "${UNREAD:-0}" -eq 0 ] && exit 0
  34. # Check for urgent messages
  35. URGENT=$(sqlite3 "$MAIL_DB" "SELECT COUNT(*) FROM messages WHERE to_project='${PROJECT_HASH}' AND read=0 AND priority='urgent';" 2>/dev/null)
  36. # Resolve display names for preview
  37. show_from() {
  38. local hash="$1"
  39. local name
  40. name=$(sqlite3 "$MAIL_DB" "SELECT name FROM projects WHERE hash='${hash}';" 2>/dev/null)
  41. [ -n "$name" ] && echo "$name" || echo "$hash"
  42. }
  43. # Show notification with preview of first 3 messages
  44. echo ""
  45. if [ "${URGENT:-0}" -gt 0 ]; then
  46. echo "=== URGENT MAIL: ${UNREAD} unread (${URGENT} urgent) ==="
  47. else
  48. echo "=== MAIL: ${UNREAD} unread message(s) ==="
  49. fi
  50. # Preview messages with resolved names
  51. while IFS='|' read -r from_hash priority subject; do
  52. from_name=$(show_from "$from_hash")
  53. prefix=""
  54. [ "$priority" = "urgent" ] && prefix="[!] "
  55. echo " ${prefix}From: ${from_name} | ${subject}"
  56. done < <(sqlite3 -separator '|' "$MAIL_DB" \
  57. "SELECT from_project, priority, subject FROM messages WHERE to_project='${PROJECT_HASH}' AND read=0 ORDER BY priority DESC, timestamp DESC LIMIT 3;" 2>/dev/null)
  58. if [ "$UNREAD" -gt 3 ]; then
  59. echo " ... and $((UNREAD - 3)) more"
  60. fi
  61. echo "Use agentmail read to read messages."
  62. echo "==="