#!/usr/bin/env bash # SessionStart digest: fetch remote, report incoming commits + open Forgejo # issues/PRs. Emits a Claude hook JSON blob on stdout (additionalContext) so # Claude can surface anything actionable at the top of the session. # Always exits 0 and always prints valid JSON — must never block a session. set -o pipefail cd "$(dirname "$0")/.." 2>/dev/null || exit 0 digest="" add() { digest+="$1"$'\n'; } # --- Remote fetch + incoming/outgoing commit comparison ------------------ if git rev-parse --git-dir >/dev/null 2>&1; then git fetch --all --quiet 2>/dev/null upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null) if [ -n "$upstream" ]; then incoming=$(git log --oneline "HEAD..$upstream" 2>/dev/null) outgoing=$(git log --oneline "$upstream..HEAD" 2>/dev/null) if [ -n "$incoming" ]; then add "INCOMING commits on $upstream (you are behind — pull to get them):" while IFS= read -r l; do add " $l"; done <<< "$incoming" # Flag incoming edits to Unity scene/prefab/asset files — risky to pull # while the Editor is open (it may overwrite them or hold a stale copy). scenefiles=$(git diff --name-only "HEAD..$upstream" 2>/dev/null | grep -Ei '\.(unity|prefab|asset|mat|controller)$') if [ -n "$scenefiles" ]; then add " *** WARNING: incoming commits change Unity scene/asset files:" while IFS= read -r f; do add " $f"; done <<< "$scenefiles" add " *** CLOSE or save the Unity Editor before pulling to avoid clobbering scene state." fi else add "Up to date with $upstream (no incoming commits)." fi [ -n "$outgoing" ] && add "You have $(wc -l <<< "$outgoing") local commit(s) not yet pushed." fi fi # --- Forgejo open issues + PRs ------------------------------------------- remote_url=$(git remote get-url origin 2>/dev/null) if [[ "$remote_url" =~ ^https?://([^/]+)/([^/]+)/([^/.]+) ]]; then host="${BASH_REMATCH[1]}"; owner="${BASH_REMATCH[2]}"; repo="${BASH_REMATCH[3]}" cred=$(grep -m1 "$host" "$HOME/.git-credentials" 2>/dev/null) tok=$(sed -E 's#https?://([^@]+)@.*#\1#' <<< "$cred") api="https://$host/api/v1/repos/$owner/$repo/issues" parse='import sys,json try: d=json.load(sys.stdin) except: sys.exit(0) for i in d: print(" #%d %s (by %s)"%(i["number"],i["title"],i["user"]["login"]))' if [ -n "$tok" ]; then issues=$(curl -sf --max-time 8 -u "$tok" "$api?state=open&type=issues" 2>/dev/null | python3 -c "$parse" 2>/dev/null) prs=$(curl -sf --max-time 8 -u "$tok" "$api?state=open&type=pulls" 2>/dev/null | python3 -c "$parse" 2>/dev/null) if [ -n "$issues" ]; then add "OPEN ISSUES:"; add "$issues"; else add "No open issues."; fi if [ -n "$prs" ]; then add "OPEN PULL REQUESTS:"; add "$prs"; else add "No open PRs."; fi fi fi # --- Emit hook JSON ------------------------------------------------------ ctx="[Session start — repo/remote status] $digest If there are INCOMING commits or any open issues/PRs, briefly tell the user at the start of your first reply. If everything is up to date with no open items, do not mention this." python3 - "$ctx" <<'PY' import json,sys print(json.dumps({"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":sys.argv[1]},"suppressOutput":True})) PY exit 0