- one shared exec-bit predicate (Language-recognized extensions => 0755) used by
every hook/agent installer; non-script files in hooks dirs stay non-executable
- mixin discovery scans the global hooks dir and each agent's hooks dir;
.builtin-manifest is never scanned
- NTFS 8.3 short-name aliases rejected as builtin-manifest entries
- hook-script install announcements restricted to real hook locations
- COYOTE_HOOKS_DIR override warning compares canonicalized paths
- embedded assets decode via checked from_utf8 instead of from_utf8_unchecked
- log-events.sh defaults under ${XDG_STATE_HOME:-$HOME/.local/state}/coyote/hooks.log
keeping 0600/symlink-refusal/secret-filter hardening; notify.sh tty fallback strips
control bytes; both use UTC ISO-8601 timestamps
- payload files orphaned by a write failure are unlinked; stale coyote-hook-*.json
payloads swept best-effort at startup
- sweep_removed_agent_hooks never follows symlinked agent dirs
- usage-probe-hooks.sh replaces bare sleeps with a bounded poll, re-verifies 0755 on
restored scripts, and covers roles/agent hook locations
- TestConfigDirGuard hoisted into crate::testing
- .gitattributes pins LF line endings for bundled scripts
hooks is now a reserved bundle name.
46 lines
2.0 KiB
Bash
Executable File
46 lines
2.0 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.
|
|
# $body carries model-influenced values: strip control bytes (including
|
|
# ESC, so ANSI/OSC sequences cannot drive the terminal) before echoing.
|
|
safe_line="$(printf '%s' "[$title] $body" | tr -d '\000-\010\013\014\016-\037\177')"
|
|
{ echo "$safe_line" > /dev/tty; } 2> /dev/null || echo "$safe_line"
|
|
fi
|