37 lines
1.2 KiB
Bash
Executable File
37 lines
1.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# hooklib dispatcher — routes one Claude Code hook event to every drop-in
|
|
# script under hooks/<event>.d/, in lexical order.
|
|
#
|
|
# Usage (from hooks.json): dispatch.sh <EventName>
|
|
#
|
|
# The event JSON is read once from stdin and replayed to each sub-hook on
|
|
# its own stdin. A sub-hook that wants to act prints a hook JSON response
|
|
# (e.g. a PreToolUse permissionDecision) to stdout and exits 0. The FIRST
|
|
# sub-hook to emit non-empty stdout wins: the dispatcher forwards that
|
|
# response verbatim and stops. If no sub-hook emits anything, the dispatcher
|
|
# stays silent and exits 0, which Claude Code treats as "no opinion / allow".
|
|
#
|
|
# Adding a hook is just dropping an executable script into the matching
|
|
# hooks/<event>.d/ directory — no wiring changes required.
|
|
|
|
set -euo pipefail
|
|
|
|
event="${1:?dispatch.sh needs an event name}"
|
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
dir="${here}/$(printf '%s' "$event" | tr '[:upper:]' '[:lower:]').d"
|
|
|
|
payload="$(cat)"
|
|
|
|
[ -d "$dir" ] || exit 0
|
|
|
|
for hook in "$dir"/*.sh; do
|
|
[ -e "$hook" ] || continue
|
|
out="$(printf '%s' "$payload" | bash "$hook" || true)"
|
|
if [ -n "$out" ]; then
|
|
printf '%s\n' "$out"
|
|
exit 0
|
|
fi
|
|
done
|
|
|
|
exit 0
|