Add tab re-ordering.
This commit is contained in:
+59
-16
@@ -26,6 +26,59 @@ set -u
|
||||
|
||||
state=${1:-idle}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Read the event.
|
||||
#
|
||||
# Claude Code hands the hook its event as JSON on stdin. Both of the states
|
||||
# that care about it read it here, before anything has been written, because
|
||||
# the payload decides what — if anything — this call should report at all.
|
||||
#
|
||||
# Guarded on a tty so that running this by hand still works: stdin is then the
|
||||
# keyboard, and `cat` would sit there waiting for a payload nobody is going to
|
||||
# type.
|
||||
payload=""
|
||||
if [ "$state" = busy ] || [ "$state" = input ]; then
|
||||
[ -t 0 ] || payload=$(cat 2>/dev/null) || payload=""
|
||||
fi
|
||||
|
||||
# Pull a string field out of the payload. jq when it is there, and otherwise a
|
||||
# sed fallback that gives up on a value containing an escaped quote — the
|
||||
# common case handled badly rather than the rare case handled wrongly. Both
|
||||
# callers have a safe default for the empty answer.
|
||||
json_str() {
|
||||
[ -n "$payload" ] || return 0
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
printf '%s' "$payload" | jq -r --arg k "$1" '.[$k] // ""' 2>/dev/null
|
||||
else
|
||||
printf '%s' "$payload" \
|
||||
| sed -n 's/.*"'"$1"'"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p'
|
||||
fi
|
||||
}
|
||||
|
||||
# The Notification event is not one event. Claude Code raises it for permission
|
||||
# prompts, for elicitations, for auth results, for a subagent finishing — and
|
||||
# for `idle_prompt`, a 60-second timer that fires whenever a session has been
|
||||
# sitting with nothing running. Reporting every one of them as "blocked on
|
||||
# you" is what makes a finished, cleared session light up amber a minute after
|
||||
# you have walked away from it.
|
||||
#
|
||||
# So report the kind, not the event. An absent field means a caller that isn't
|
||||
# Claude Code, which keeps the argument's plain meaning.
|
||||
if [ "$state" = input ]; then
|
||||
case $(json_str notification_type) in
|
||||
permission_prompt | elicitation_dialog | agent_needs_input | "") ;;
|
||||
|
||||
# The opposite claim: the session is sitting idle. Worth saying, because it
|
||||
# clears a stale amber left by a prompt that was answered somewhere else.
|
||||
idle_prompt) state=idle ;;
|
||||
|
||||
# Informational — auth results, a completed elicitation, a subagent
|
||||
# finishing while the session itself is still working. None of them change
|
||||
# whether the pane wants you, so leave it showing whatever it shows.
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Find the pty to write to.
|
||||
#
|
||||
@@ -114,25 +167,15 @@ printf '\033]9;4;%s\007' "$code" > "$tty_target" 2>/dev/null || true
|
||||
# Only a starting turn carries a task worth naming. The other states leave the
|
||||
# title alone so the shell's own title comes back when the session ends.
|
||||
[ "$state" = busy ] || exit 0
|
||||
|
||||
payload=$(cat 2>/dev/null) || exit 0
|
||||
[ -n "$payload" ] || exit 0
|
||||
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
title=$(printf '%s' "$payload" | jq -r '.prompt // ""' 2>/dev/null) || title=""
|
||||
else
|
||||
# No jq — pull the field out directly. This gives up on a prompt whose first
|
||||
# line contains an escaped quote, which is the common case handled badly
|
||||
# rather than the rare case handled wrongly: a missed title costs nothing
|
||||
# because the tab just keeps the name it already had.
|
||||
title=$(printf '%s' "$payload" \
|
||||
| sed -n 's/.*"prompt"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
|
||||
title=$(json_str prompt)
|
||||
|
||||
# Still JSON at this point, so a newline is the two characters \ and n
|
||||
# rather than an actual line break. `head` below would not split on it and
|
||||
# the whole prompt would arrive as one long title with \n sitting in it.
|
||||
title=${title%%\\n*}
|
||||
fi
|
||||
# Without jq the title is still JSON at this point, so a newline is the two
|
||||
# characters \ and n rather than an actual line break. `head` below would not
|
||||
# split on it and the whole prompt would arrive as one long title with \n
|
||||
# sitting in it. Harmless on the jq path, which has already unescaped them.
|
||||
title=${title%%\\n*}
|
||||
|
||||
# First line only, and no control characters: an OSC string ends at the first
|
||||
# BEL or ESC, so anything of that sort in a prompt would truncate the sequence
|
||||
|
||||
Reference in New Issue
Block a user