Files
claude-telegram-live-feed/hooks/bash-heartbeat-pre.sh

58 lines
1.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# PreToolUse hook on the Bash tool — fire a Telegram heartbeat *before* the
# command runs, so the user sees "I'm doing X" within ~1 second of any Bash
# call, no matter what command Claude is running.
#
# Also records the start time at /tmp/.bash-hb-<pid> so the matching
# PostToolUse hook can compute duration and decide whether to send a
# completion ping.
#
# Skips heartbeats for certain noisy / tg-stream-itself commands so we don't
# loop. Skips when the description doesn't carry useful info.
#
# Input: JSON {"tool_name":"Bash","tool_input":{"command":"...","description":"..."}}
# Output: always exit 0 (advisory hook, never blocks).
set -u
INPUT=$(cat)
PARSED=$(node -e '
let raw = "";
process.stdin.on("data", c => raw += c);
process.stdin.on("end", () => {
try {
const j = JSON.parse(raw);
const cmd = (j.tool_input && j.tool_input.command) || "";
const desc = (j.tool_input && j.tool_input.description) || "";
// Skip if this Bash call is itself a Telegram stream/task (avoid loops)
if (/tg-stream|tg-task|telegram\.org\/bot/.test(cmd)) {
console.log("SKIP");
return;
}
// Skip trivial reads (ls, cat, echo on their own)
if (/^(ls|pwd|whoami|date|echo)( |$)/.test(cmd.trim())) {
console.log("SKIP");
return;
}
console.log("FIRE\t" + (desc || cmd.slice(0, 80)).replace(/\t/g, " "));
} catch (e) {
console.log("SKIP");
}
});
' <<<"$INPUT")
ACTION=$(echo "$PARSED" | cut -f1)
LABEL=$(echo "$PARSED" | cut -f2-)
if [[ "$ACTION" != "FIRE" ]]; then
exit 0
fi
# Record start time keyed by parent shell PID so PostToolUse can pair it
echo "$(date +%s)|$LABEL" > "/tmp/.bash-hb-$PPID" 2>/dev/null || true
# Fire the heartbeat (no-stream so it lands instantly without typing animation)
/host/root/openclaw/tg-stream --no-stream "🔧 $LABEL" >/dev/null 2>&1 &
exit 0