forked from bchanot/claude
feat(hooks): ring terminal on turn end via Stop hook
Notification matcher covers input-needed events only; end of turn had no signal but idle_prompt, ~60s late. Wire notify-attention.sh on Stop too, branching on hook_event_name for the message. Signal only: returns terminalSequence + suppressOutput, never blocks (guard vs BDR-083). Header documents both client-side prerequisites found in BLK-020.
This commit is contained in:
@@ -1,21 +1,35 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Notification hook — signal the user through the terminal when Claude
|
# Notification + Stop hook — signal the user through the terminal when
|
||||||
# needs input (permission prompt, question, idle wait).
|
# Claude needs input (permission prompt, question, idle wait) or has
|
||||||
|
# finished responding.
|
||||||
#
|
#
|
||||||
# Runs on the remote (Linux); the only channel that crosses SSH into the
|
# Runs on the remote (Linux); the only channel that crosses SSH into the
|
||||||
# VS Code client is the terminal stream. Hooks have no controlling TTY,
|
# VS Code client is the terminal stream. Hooks have no controlling TTY,
|
||||||
# so the sequence goes through the supported `terminalSequence` JSON
|
# so the sequence goes through the supported `terminalSequence` JSON
|
||||||
# output field and Claude Code writes it to the terminal:
|
# output field and Claude Code writes it to the terminal:
|
||||||
# - BEL x2 (double beep) -> sound, needs VS Code setting
|
# - BEL x2 (double beep) -> sound, needs VS Code setting
|
||||||
# accessibility.signals.terminalBell { "sound": "on" }
|
# accessibility.signals.terminalBell { "sound": "on" } AND a non-zero
|
||||||
|
# volume for Code in the Windows volume mixer (BLK-020).
|
||||||
# - OSC 777 notify -> Windows toast via the client-side extension
|
# - OSC 777 notify -> Windows toast via the client-side extension
|
||||||
# "Terminal Notification" (wenbopan.vscode-terminal-osc-notifier)
|
# "Terminal Notification" (wenbopan.vscode-terminal-osc-notifier).
|
||||||
|
# The extension only instruments terminals created AFTER it is
|
||||||
|
# active: install it first, then start or re-attach the session.
|
||||||
# Both are invisible no-ops in terminals that ignore them.
|
# Both are invisible no-ops in terminals that ignore them.
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
msg=$(jq -r '.message // .notification_type // empty' 2>/dev/null \
|
payload=$(cat 2>/dev/null)
|
||||||
| tr -d '\000-\037' | cut -c1-200)
|
read_field() {
|
||||||
[ -n "$msg" ] || msg="Claude Code needs your input"
|
printf '%s' "$payload" | jq -r "$1 // empty" 2>/dev/null \
|
||||||
|
| tr -d '\000-\037' | cut -c1-200
|
||||||
|
}
|
||||||
|
|
||||||
|
msg=$(read_field '.message // .notification_type')
|
||||||
|
if [ -z "$msg" ]; then
|
||||||
|
case "$(read_field '.hook_event_name')" in
|
||||||
|
Stop) msg="Claude has finished responding" ;;
|
||||||
|
*) msg="Claude Code needs your input" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
bell=$(printf '\a')
|
bell=$(printf '\a')
|
||||||
esc=$(printf '\033')
|
esc=$(printf '\033')
|
||||||
|
|||||||
@@ -286,6 +286,18 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"Stop": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash ~/.claude/hooks/notify-attention.sh",
|
||||||
|
"timeout": 5,
|
||||||
|
"statusMessage": "Ringing terminal bell..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"UserPromptSubmit": [
|
"UserPromptSubmit": [
|
||||||
{
|
{
|
||||||
"hooks": [
|
"hooks": [
|
||||||
|
|||||||
Reference in New Issue
Block a user