From ea9e5c1dab86c36c68738786ae73d4221f2039fb Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 3 Sep 2026 00:28:40 +0200 Subject: [PATCH] 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. --- hooks/notify-attention.sh | 28 +++++++++++++++++++++------- settings.json | 12 ++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/hooks/notify-attention.sh b/hooks/notify-attention.sh index b7a3ef7..4e6cf84 100755 --- a/hooks/notify-attention.sh +++ b/hooks/notify-attention.sh @@ -1,21 +1,35 @@ #!/usr/bin/env bash -# Notification hook — signal the user through the terminal when Claude -# needs input (permission prompt, question, idle wait). +# Notification + Stop hook — signal the user through the terminal when +# 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 # VS Code client is the terminal stream. Hooks have no controlling TTY, # so the sequence goes through the supported `terminalSequence` JSON # output field and Claude Code writes it to the terminal: # - 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 -# "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. set -u -msg=$(jq -r '.message // .notification_type // empty' 2>/dev/null \ - | tr -d '\000-\037' | cut -c1-200) -[ -n "$msg" ] || msg="Claude Code needs your input" +payload=$(cat 2>/dev/null) +read_field() { + 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') esc=$(printf '\033') diff --git a/settings.json b/settings.json index e366d8b..46505b3 100644 --- a/settings.json +++ b/settings.json @@ -286,6 +286,18 @@ ] } ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "bash ~/.claude/hooks/notify-attention.sh", + "timeout": 5, + "statusMessage": "Ringing terminal bell..." + } + ] + } + ], "UserPromptSubmit": [ { "hooks": [