|
1 | 1 | #!/bin/bash |
2 | 2 | # Hook script for Claude Code Stop event |
3 | | -# Sends a Warp notification when Claude completes a task |
| 3 | +# Sends a structured Warp notification when Claude completes a task |
4 | 4 |
|
5 | 5 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
6 | 6 |
|
7 | 7 | # Read hook input from stdin |
8 | 8 | INPUT=$(cat) |
9 | 9 |
|
10 | | -# Extract transcript path from the hook input |
11 | | -TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null) |
| 10 | +# Skip if a stop hook is already active (prevents double-notification) |
| 11 | +STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null) |
| 12 | +if [ "$STOP_HOOK_ACTIVE" = "true" ]; then |
| 13 | + exit 0 |
| 14 | +fi |
12 | 15 |
|
13 | | -# Default message |
14 | | -MSG="Task completed" |
| 16 | +# Extract metadata from the hook input |
| 17 | +SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty' 2>/dev/null) |
| 18 | +TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null) |
| 19 | +CWD=$(echo "$INPUT" | jq -r '.cwd // empty' 2>/dev/null) |
| 20 | +PROJECT="" |
| 21 | +if [ -n "$CWD" ]; then |
| 22 | + PROJECT=$(basename "$CWD") |
| 23 | +fi |
15 | 24 |
|
16 | | -# Try to extract prompt and response from the transcript (JSONL format) |
| 25 | +# Extract the last user prompt and assistant response from the transcript. |
| 26 | +# Small delay to allow Claude Code to flush the current turn to the transcript file. |
| 27 | +# The Stop hook fires before the transcript is fully written. |
| 28 | +sleep 0.3 |
| 29 | +QUERY="" |
| 30 | +RESPONSE="" |
17 | 31 | if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then |
18 | | - # Get the first user prompt |
19 | | - PROMPT=$(jq -rs ' |
20 | | - [.[] | select(.type == "user")] | first | .message.content // empty |
| 32 | + # Get the last user prompt (most recent turn, not the first in the session) |
| 33 | + # .message.content can be a string or an array of {type, text} objects |
| 34 | + QUERY=$(jq -rs ' |
| 35 | + [.[] | select(.type == "user")] | last | |
| 36 | + if .message.content | type == "array" |
| 37 | + then [.message.content[] | select(.type == "text") | .text] | join(" ") |
| 38 | + else .message.content // empty |
| 39 | + end |
21 | 40 | ' "$TRANSCRIPT_PATH" 2>/dev/null) |
22 | | - |
| 41 | + |
23 | 42 | # Get the last assistant response |
24 | 43 | RESPONSE=$(jq -rs ' |
25 | 44 | [.[] | select(.type == "assistant" and .message.content)] | last | |
26 | 45 | [.message.content[] | select(.type == "text") | .text] | join(" ") |
27 | 46 | ' "$TRANSCRIPT_PATH" 2>/dev/null) |
28 | | - |
29 | | - if [ -n "$PROMPT" ] && [ -n "$RESPONSE" ]; then |
30 | | - # Truncate prompt to 50 chars |
31 | | - if [ ${#PROMPT} -gt 50 ]; then |
32 | | - PROMPT="${PROMPT:0:47}..." |
33 | | - fi |
34 | | - # Truncate response to 120 chars |
35 | | - if [ ${#RESPONSE} -gt 120 ]; then |
36 | | - RESPONSE="${RESPONSE:0:117}..." |
37 | | - fi |
38 | | - MSG="\"${PROMPT}\" → ${RESPONSE}" |
39 | | - elif [ -n "$RESPONSE" ]; then |
40 | | - # Fallback to just response if no prompt found |
41 | | - if [ ${#RESPONSE} -gt 175 ]; then |
42 | | - RESPONSE="${RESPONSE:0:172}..." |
43 | | - fi |
44 | | - MSG="$RESPONSE" |
| 47 | + |
| 48 | + # Truncate for notification display |
| 49 | + if [ -n "$QUERY" ] && [ ${#QUERY} -gt 200 ]; then |
| 50 | + QUERY="${QUERY:0:197}..." |
| 51 | + fi |
| 52 | + if [ -n "$RESPONSE" ] && [ ${#RESPONSE} -gt 200 ]; then |
| 53 | + RESPONSE="${RESPONSE:0:197}..." |
45 | 54 | fi |
46 | 55 | fi |
47 | 56 |
|
48 | | -"$SCRIPT_DIR/warp-notify.sh" "Claude Code" "$MSG" |
| 57 | +# Build structured JSON payload |
| 58 | +BODY=$(jq -nc \ |
| 59 | + --arg agent "claude" \ |
| 60 | + --arg event "stop" \ |
| 61 | + --arg session_id "$SESSION_ID" \ |
| 62 | + --arg cwd "$CWD" \ |
| 63 | + --arg project "$PROJECT" \ |
| 64 | + --arg query "$QUERY" \ |
| 65 | + --arg response "$RESPONSE" \ |
| 66 | + --arg transcript_path "$TRANSCRIPT_PATH" \ |
| 67 | + '{v:1, agent:$agent, event:$event, session_id:$session_id, cwd:$cwd, project:$project, query:$query, response:$response, transcript_path:$transcript_path}') |
| 68 | + |
| 69 | +"$SCRIPT_DIR/warp-notify.sh" "warp://cli-agent" "$BODY" |
0 commit comments