2026-10-07 19:26:06 -04:00
|
|
|
#!/bin/bash
|
|
|
|
|
# Claude Code hook (wired in via claude-settings.json) that tracks what Claude is
|
|
|
|
|
# doing in each DevDesk session, for the sidebar's at-a-glance status:
|
|
|
|
|
# UserPromptSubmit, PostToolUse -> working
|
|
|
|
|
# Notification -> waiting (Claude needs input or a permission)
|
|
|
|
|
# Stop, SessionStart -> idle
|
|
|
|
|
# SessionEnd -> exited
|
|
|
|
|
# Fires on every tool call, so it stays tiny and only writes when the state changes.
|
2026-10-07 23:34:59 -04:00
|
|
|
# Entering "waiting" also starts devdesk-notify-matrix, which posts to Matrix if
|
|
|
|
|
# the wait lasts and nobody is attached (devdesk#28).
|
2026-10-07 19:26:06 -04:00
|
|
|
|
|
|
|
|
input=$(cat)
|
|
|
|
|
|
|
|
|
|
outer=${TMUX:-}
|
|
|
|
|
[ "${outer%%,*}" = "${DEVDESK_SOCKET:-/run/devdesk/tmux.sock}" ] && [ -n "${TMUX_PANE:-}" ] || exit 0
|
|
|
|
|
session=$(tmux display-message -p -t "$TMUX_PANE" '#S' 2>/dev/null)
|
|
|
|
|
[[ $session =~ ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$ ]] || exit 0
|
|
|
|
|
|
|
|
|
|
IFS=$'\t' read -r event message < <(jq -rM '[.hook_event_name // "", (.message // "" | gsub("[\t\n]"; " "))] | @tsv' <<<"$input" 2>/dev/null)
|
|
|
|
|
case $event in
|
|
|
|
|
UserPromptSubmit | PostToolUse) state=working ;;
|
|
|
|
|
Notification) state=waiting ;;
|
|
|
|
|
Stop | SessionStart) state=idle ;;
|
|
|
|
|
SessionEnd) state=exited ;;
|
|
|
|
|
*) exit 0 ;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
dir="${DEVDESK_STATE_DIR:-/var/lib/devdesk}/state"
|
|
|
|
|
file="$dir/$session.json"
|
|
|
|
|
# Unchanged state (the common case during tool runs): nothing to write.
|
|
|
|
|
if [ "$state" != waiting ] && [ -f "$file" ] && grep -q "\"state\":\"$state\"" "$file"; then
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|
2026-10-07 23:34:59 -04:00
|
|
|
# A second Notification during the same wait updates the message but keeps
|
|
|
|
|
# `since`, so the wait stays one wait (one Matrix message at most).
|
|
|
|
|
since=$(date +%s)
|
|
|
|
|
was_waiting=0
|
|
|
|
|
if [ "$state" = waiting ] && grep -q '"state":"waiting"' "$file" 2>/dev/null; then
|
|
|
|
|
was_waiting=1
|
|
|
|
|
since=$(jq -rM '.since // empty' "$file" 2>/dev/null) || since=$(date +%s)
|
|
|
|
|
[[ $since =~ ^[0-9]+$ ]] || since=$(date +%s)
|
|
|
|
|
fi
|
2026-10-07 19:26:06 -04:00
|
|
|
mkdir -p "$dir" 2>/dev/null || exit 0
|
|
|
|
|
tmp=$(mktemp "$dir/.$session.XXXXXX" 2>/dev/null) || exit 0
|
2026-10-07 23:34:59 -04:00
|
|
|
if jq -cMn --arg s "$state" --arg m "$message" --arg e "$event" --argjson t "$since" \
|
|
|
|
|
'{state: $s, since: $t, event: $e, message: (if $m == "" then null else $m end)}' >"$tmp"; then
|
2026-10-07 19:26:06 -04:00
|
|
|
mv -f "$tmp" "$file"
|
|
|
|
|
else
|
|
|
|
|
rm -f "$tmp"
|
2026-10-07 23:34:59 -04:00
|
|
|
exit 0
|
|
|
|
|
fi
|
|
|
|
|
if [ "$state" = waiting ] && [ "$was_waiting" = 0 ]; then
|
|
|
|
|
setsid -f "${DEVDESK_LIBEXEC:-/usr/lib/devdesk}/devdesk-notify-matrix" "$session" "$since" \
|
|
|
|
|
</dev/null >/dev/null 2>&1 || true
|
2026-10-07 19:26:06 -04:00
|
|
|
fi
|
|
|
|
|
exit 0
|