Files
coyote/assets/hooks/notify.sh
T
Dark-Alex-17 fc3bb259cb feat(TASK-038): add hooks builtin-asset category with example scripts and roles mixin scanning
- AssetCategory::Hooks + InstallFilter::Hooks (NAMES/parse/clap), reserving
  the 'hooks' bundle name via the existing AssetCategory::parse check
- HookAssets embed + install_builtin_hooks(force): installs the bundled
  example scripts 0755 into paths::hooks_dir() via write_file_atomic, wired
  into install_builtins() and install_assets(); warns once when
  COYOTE_HOOKS_DIR diverges from the config-dir default
- assets/hooks/notify.sh: notify-send -> osascript -> terminal fallback,
  with AppleScript-literal sanitization of model-influenced values
- assets/hooks/log-events.sh: appends a COYOTE_* env snapshot (secrets
  excluded, 0600 log, symlink-refusing) to ${COYOTE_HOOK_LOG:-/tmp/coyote-hooks.log}
- sbx-mixin discovery now scans roles/*.sbx-mixin.yaml and
  roles/hooks/*.sbx-mixin.yaml (mirroring the role-hook cwd)
- tests: install+0755+force, install_assets(Hooks) end-to-end, discover()
  roles scanning, reserved bundle name, no-ARGC-BUILD embed content, script
  content order + real execution (secret exclusion, tty-less fallback),
  CLI parser round-trips; hooks_dir env test made #[serial]
2026-09-16 13:44:35 -06:00

43 lines
1.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Desktop-notification hook: posts a notification describing the event that
# fired, falling back to a message on the controlling terminal when no
# notifier is present.
#
# Env vars read (set by coyote when the hook fires):
# COYOTE_EVENT dotted event name, e.g. turn.completed
# COYOTE_AGENT_NAME agent name, when the event carries one
# COYOTE_TOOL_NAME tool name, when the event carries one
#
# Wire it up under `hooks:` in your config.yaml:
# hooks:
# turn.completed:
# - name: notify
# command: ./hooks/notify.sh
#
# A relative command path like ./hooks/notify.sh resolves against the coyote
# config directory for global hooks, so this works with the default hooks dir.
#
# See https://github.com/Dark-Alex-17/coyote/wiki/Hooks for the full list of
# events and env vars. Hooks are fire-and-forget: this script never fails
# loudly, and coyote ignores its exit code either way.
set -u
title="coyote"
body="${COYOTE_EVENT:-event}"
[ -n "${COYOTE_AGENT_NAME:-}" ] && body="$body agent=$COYOTE_AGENT_NAME"
[ -n "${COYOTE_TOOL_NAME:-}" ] && body="$body tool=$COYOTE_TOOL_NAME"
if command -v notify-send > /dev/null 2>&1; then
notify-send "$title" "$body" 2> /dev/null || true
elif command -v osascript > /dev/null 2>&1; then
# $body carries model-influenced values (e.g. tool names); strip quotes and
# backslashes so it cannot escape the AppleScript string literal.
safe_body=${body//[\"\\]/}
osascript -e "display notification \"$safe_body\" with title \"$title\"" 2> /dev/null || true
else
# coyote discards hook stdout, so aim the fallback at the controlling
# terminal when one exists; plain stdout keeps direct/manual runs working.
{ echo "[$title] $body" > /dev/tty; } 2> /dev/null || echo "[$title] $body"
fi