Files
2025-11-30 08:36:20 +08:00

100 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# session-start.sh - SessionStart hook for claude-handoff plugin
#
# PURPOSE:
# Injects pre-generated handoff content after `/compact handoff:<goal>`
# completes. Content was generated by PreCompact hook using --fork-session.
#
# HOOK EVENT: SessionStart (matcher: "compact")
# - Fires when sessions continue after compact operations (NOT new sessions!)
# - Receives: session_id, transcript_path, cwd, source ("compact")
#
# BEHAVIOR:
# - Checks for handoff content saved by pre-compact.sh
# - Injects handoff_content as systemMessage
# - Cleans up state file after successful injection
#
# TESTING:
# 1. Enable debug logging in hooks/lib/logging.sh (set LOGGING_ENABLED=true)
# 2. Run: /compact handoff:implement feature X
# 3. Compact completes, session continues
# 4. Check logs:
# tail -f /tmp/handoff-sessionstart.log
# 5. Verify handoff appears as system message in continuing session
# 6. Check state file cleaned up on success:
# ls -la .git/handoff-pending/ # should not exist after successful handoff
#
# MANUAL TESTING WITH FAKE STATE:
# # Create fake state with pre-generated content
# mkdir -p .git/handoff-pending
# echo '{"handoff_content":"## Goal\nTest\n## Context\n- Item 1","goal":"test","trigger":"manual","type":"compact"}' > .git/handoff-pending/handoff-context.json
#
# # Run hook
# echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"compact"}' | bash session-start.sh
#
# # Check output contains systemMessage with handoff content
# # Cleanup
# rm -rf .git/handoff-pending
#
# EXIT BEHAVIOR:
# - Returns JSON with systemMessage if handoff content exists
# - Exits silently (exit 0, no output) if no handoff state found
#
set -euo pipefail
# Load logging module
source "${BASH_SOURCE%/*}/../lib/logging.sh"
init_logging "sessionstart"
# Read hook input
input=$(cat)
session_id=$(echo "$input" | jq -r '.session_id // ""')
cwd=$(echo "$input" | jq -r '.cwd // "."')
source=$(echo "$input" | jq -r '.source // "unknown"')
log "Received input: session_id=$session_id cwd=$cwd source=$source"
# Only proceed if this is a compact-triggered session continuation
if [[ "$source" != "compact" ]]; then
log "Source is '$source', not 'compact'. Exiting."
exit 0
fi
# Change to project directory
cd "$cwd" || exit 0
# Check for pending handoff state
state_file=".git/handoff-pending/handoff-context.json"
if [[ ! -f "$state_file" ]]; then
log "No state file found, exiting"
exit 0
fi
log "Found state file: $state_file"
# Read pre-generated handoff content
handoff_content=$(cat "$state_file" | jq -r '.handoff_content // ""')
goal=$(cat "$state_file" | jq -r '.goal // ""')
log "State: goal='$goal' content_length=${#handoff_content} chars"
# If no handoff content, exit without cleanup (might be old state format)
if [[ -z "$handoff_content" ]]; then
log "No handoff_content in state file, exiting"
exit 0
fi
# Cleanup: remove both file and directory
rm -f "$state_file"
rmdir .git/handoff-pending 2>/dev/null || true
log "Injecting handoff content as systemMessage"
# Return JSON with systemMessage to inject into session
jq -n --arg context "$handoff_content" '{
systemMessage: $context
}'
exit 0