ScuttleBot

scuttlebot / skills / gemini-relay / hooks / scuttlebot-post.sh
Source Blame History 148 lines
016a29f… lmata 1 #!/bin/bash
016a29f… lmata 2 # AfterTool hook for Gemini agents. Posts activity to scuttlebot IRC.
016a29f… lmata 3
016a29f… lmata 4 SCUTTLEBOT_CONFIG_FILE="${SCUTTLEBOT_CONFIG_FILE:-$HOME/.config/scuttlebot-relay.env}"
016a29f… lmata 5 if [ -f "$SCUTTLEBOT_CONFIG_FILE" ]; then
016a29f… lmata 6 set -a
016a29f… lmata 7 . "$SCUTTLEBOT_CONFIG_FILE"
016a29f… lmata 8 set +a
016a29f… lmata 9 fi
1d3caa2… lmata 10 if [ -n "${SCUTTLEBOT_CHANNEL_STATE_FILE:-}" ] && [ -f "$SCUTTLEBOT_CHANNEL_STATE_FILE" ]; then
1d3caa2… lmata 11 set -a
1d3caa2… lmata 12 . "$SCUTTLEBOT_CHANNEL_STATE_FILE"
1d3caa2… lmata 13 set +a
1d3caa2… lmata 14 fi
016a29f… lmata 15
016a29f… lmata 16 SCUTTLEBOT_URL="${SCUTTLEBOT_URL:-http://localhost:8080}"
016a29f… lmata 17 SCUTTLEBOT_TOKEN="${SCUTTLEBOT_TOKEN}"
016a29f… lmata 18 SCUTTLEBOT_CHANNEL="${SCUTTLEBOT_CHANNEL:-general}"
016a29f… lmata 19 SCUTTLEBOT_HOOKS_ENABLED="${SCUTTLEBOT_HOOKS_ENABLED:-1}"
1d3caa2… lmata 20
1d3caa2… lmata 21 normalize_channel() {
1d3caa2… lmata 22 local channel="$1"
1d3caa2… lmata 23 channel="${channel//[$' \t\r\n']/}"
1d3caa2… lmata 24 channel="${channel#\#}"
1d3caa2… lmata 25 printf '%s' "$channel"
1d3caa2… lmata 26 }
1d3caa2… lmata 27
1d3caa2… lmata 28 relay_channels() {
1d3caa2… lmata 29 local raw="${SCUTTLEBOT_CHANNELS:-$SCUTTLEBOT_CHANNEL}"
1d3caa2… lmata 30 local IFS=','
1d3caa2… lmata 31 local item channel seen=""
1d3caa2… lmata 32 read -r -a items <<< "$raw"
1d3caa2… lmata 33 for item in "${items[@]}"; do
1d3caa2… lmata 34 channel=$(normalize_channel "$item")
1d3caa2… lmata 35 [ -n "$channel" ] || continue
1d3caa2… lmata 36 case ",$seen," in
1d3caa2… lmata 37 *,"$channel",*) ;;
1d3caa2… lmata 38 *)
1d3caa2… lmata 39 seen="${seen:+$seen,}$channel"
1d3caa2… lmata 40 printf '%s\n' "$channel"
1d3caa2… lmata 41 ;;
1d3caa2… lmata 42 esac
1d3caa2… lmata 43 done
1d3caa2… lmata 44 }
1d3caa2… lmata 45
1d3caa2… lmata 46 post_message() {
1d3caa2… lmata 47 local text="$1"
1d3caa2… lmata 48 local payload
1d3caa2… lmata 49 payload="{\"text\": $(printf '%s' "$text" | jq -Rs .), \"nick\": \"$SCUTTLEBOT_NICK\"}"
1d3caa2… lmata 50 for channel in $(relay_channels); do
1d3caa2… lmata 51 curl -sf -X POST "$SCUTTLEBOT_URL/v1/channels/$channel/messages" \
1d3caa2… lmata 52 --connect-timeout 1 \
1d3caa2… lmata 53 --max-time 2 \
1d3caa2… lmata 54 -H "Authorization: Bearer $SCUTTLEBOT_TOKEN" \
1d3caa2… lmata 55 -H "Content-Type: application/json" \
1d3caa2… lmata 56 -d "$payload" \
1d3caa2… lmata 57 > /dev/null || true
1d3caa2… lmata 58 done
1d3caa2… lmata 59 }
016a29f… lmata 60
016a29f… lmata 61 sanitize() {
016a29f… lmata 62 local input="$1"
016a29f… lmata 63 if [ -z "$input" ]; then
016a29f… lmata 64 input=$(cat)
016a29f… lmata 65 fi
016a29f… lmata 66 printf '%s' "$input" | tr -cs '[:alnum:]_-' '-'
016a29f… lmata 67 }
016a29f… lmata 68
016a29f… lmata 69 input=$(cat)
016a29f… lmata 70
016a29f… lmata 71 tool=$(echo "$input" | jq -r '.tool_name // empty')
016a29f… lmata 72 cwd=$(echo "$input" | jq -r '.cwd // empty')
016a29f… lmata 73
016a29f… lmata 74 if [ -z "$cwd" ]; then
016a29f… lmata 75 cwd=$(pwd)
016a29f… lmata 76 fi
016a29f… lmata 77 base_name=$(sanitize "$(basename "$cwd")")
016a29f… lmata 78 session_raw="${SCUTTLEBOT_SESSION_ID:-${GEMINI_SESSION_ID:-$PPID}}"
016a29f… lmata 79 if [ -z "$session_raw" ] || [ "$session_raw" = "0" ]; then
016a29f… lmata 80 session_raw=$(date +%s)
016a29f… lmata 81 fi
016a29f… lmata 82 session_suffix=$(printf '%s' "$session_raw" | sanitize | cut -c 1-8)
016a29f… lmata 83 default_nick="gemini-${base_name}-${session_suffix}"
016a29f… lmata 84 SCUTTLEBOT_NICK="${SCUTTLEBOT_NICK:-$default_nick}"
016a29f… lmata 85
016a29f… lmata 86 [ "$SCUTTLEBOT_HOOKS_ENABLED" = "0" ] && { echo '{}'; exit 0; }
016a29f… lmata 87 [ "$SCUTTLEBOT_HOOKS_ENABLED" = "false" ] && { echo '{}'; exit 0; }
016a29f… lmata 88 [ -z "$SCUTTLEBOT_TOKEN" ] && { echo '{}'; exit 0; }
016a29f… lmata 89
016a29f… lmata 90 case "$tool" in
016a29f… lmata 91 run_shell_command|Bash)
016a29f… lmata 92 cmd=$(echo "$input" | jq -r '.tool_input.command // empty' | head -c 120)
016a29f… lmata 93 msg="› $cmd"
016a29f… lmata 94 ;;
016a29f… lmata 95 read_file|Read)
016a29f… lmata 96 file=$(echo "$input" | jq -r '.tool_input.file_path // empty' | sed "s|$cwd/||")
016a29f… lmata 97 msg="read $file"
016a29f… lmata 98 ;;
016a29f… lmata 99 edit|Edit)
016a29f… lmata 100 file=$(echo "$input" | jq -r '.tool_input.file_path // empty' | sed "s|$cwd/||")
016a29f… lmata 101 msg="edit $file"
016a29f… lmata 102 ;;
016a29f… lmata 103 write_file|Write)
016a29f… lmata 104 file=$(echo "$input" | jq -r '.tool_input.file_path // empty' | sed "s|$cwd/||")
016a29f… lmata 105 msg="write $file"
016a29f… lmata 106 ;;
016a29f… lmata 107 Glob)
016a29f… lmata 108 pattern=$(echo "$input" | jq -r '.tool_input.pattern // empty')
016a29f… lmata 109 msg="glob $pattern"
016a29f… lmata 110 ;;
016a29f… lmata 111 read_many_files)
016a29f… lmata 112 paths=$(echo "$input" | jq -r '.tool_input.paths[]? // empty' 2>/dev/null | head -n 3 | paste -sd ", " -)
016a29f… lmata 113 [ -z "$paths" ] && paths=$(echo "$input" | jq -r '.tool_input.path // empty')
016a29f… lmata 114 msg="read many ${paths:-files}"
016a29f… lmata 115 ;;
016a29f… lmata 116 grep|search_file_content|Grep)
016a29f… lmata 117 pattern=$(echo "$input" | jq -r '.tool_input.pattern // empty')
016a29f… lmata 118 msg="grep \"$pattern\""
016a29f… lmata 119 ;;
016a29f… lmata 120 list_directory)
016a29f… lmata 121 path=$(echo "$input" | jq -r '.tool_input.path // empty')
016a29f… lmata 122 msg="list ${path:-.}"
016a29f… lmata 123 ;;
016a29f… lmata 124 write_todos)
016a29f… lmata 125 msg="update todos"
016a29f… lmata 126 ;;
016a29f… lmata 127 activate_skill)
016a29f… lmata 128 skill=$(echo "$input" | jq -r '.tool_input.name // empty')
016a29f… lmata 129 msg="activate skill ${skill:-unknown}"
016a29f… lmata 130 ;;
016a29f… lmata 131 ask_user)
016a29f… lmata 132 msg="ask user"
016a29f… lmata 133 ;;
016a29f… lmata 134 Agent)
016a29f… lmata 135 desc=$(echo "$input" | jq -r '.tool_input.description // empty' | head -c 80)
016a29f… lmata 136 msg="spawn agent: $desc"
016a29f… lmata 137 ;;
016a29f… lmata 138 *)
016a29f… lmata 139 msg="$tool"
016a29f… lmata 140 ;;
016a29f… lmata 141 esac
016a29f… lmata 142
016a29f… lmata 143 [ -z "$msg" ] && { echo '{}'; exit 0; }
016a29f… lmata 144
1d3caa2… lmata 145 post_message "$msg"
016a29f… lmata 146
016a29f… lmata 147 echo '{}'
016a29f… lmata 148 exit 0

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button