|
#!/bin/bash |
|
|
|
# Stop Slack DM Sender Script |
|
# Extract last assistant message content text and send to Slack |
|
# |
|
# Usage: |
|
# ./stop-slack-dm.sh -t TOKEN -u USER_ID -m "Your message" |
|
# ./stop-slack-dm.sh -t TOKEN -e [email protected] -m "Your message" |
|
# echo '{"transcript_path": "path/to/file.jsonl", "session_id": "session123"}' | ./stop-slack-dm.sh -t TOKEN -u USER_ID |
|
|
|
set -euo pipefail |
|
|
|
# Read stdin with timeout to avoid hanging |
|
INPUT="" |
|
if read -t 1 -N 1 first_char 2>/dev/null; then |
|
INPUT="${first_char}$(cat)" |
|
fi |
|
|
|
# Colors for output |
|
RED='\033[0;31m' |
|
GREEN='\033[0;32m' |
|
YELLOW='\033[1;33m' |
|
NC='\033[0m' # No Color |
|
|
|
# Default values |
|
TOKEN="" |
|
USER_ID="" |
|
EMAIL="" |
|
MESSAGE="" |
|
|
|
# Function to display usage |
|
usage() { |
|
cat <<EOF |
|
Usage: $0 [OPTIONS] |
|
|
|
OPTIONS: |
|
-t TOKEN Slack Bot User OAuth Token (or set SLACK_TOKEN env var) |
|
-u USER_ID Slack User ID (e.g., U1234567890) |
|
-e EMAIL User email address (alternative to user ID) |
|
-m MESSAGE Message to send |
|
-h Show this help message |
|
|
|
Note: If no -m option is provided, the script will extract text from the transcript file. |
|
|
|
Examples: |
|
$0 -t xoxb-your-token -u U1234567890 -m "Hello!" |
|
echo '{"transcript_path": "path/to/file.jsonl", "session_id": "session123"}' | $0 -t xoxb-your-token -u U1234567890 |
|
EOF |
|
exit 1 |
|
} |
|
|
|
# Function to extract content text from transcript |
|
extract_content_text() { |
|
local input_data="$1" |
|
|
|
# Extract transcript_path and session_id from INPUT |
|
local transcript_path=$(echo "$input_data" | grep -o '"transcript_path":"[^"]*"' | cut -d'"' -f4) |
|
local session_id=$(echo "$input_data" | grep -o '"session_id":"[^"]*"' | cut -d'"' -f4) |
|
|
|
if [ -n "$transcript_path" ] && [ -f "$transcript_path" ] && [ -n "$session_id" ] && command -v jq >/dev/null 2>&1; then |
|
echo -e "${YELLOW}Extracting content text from: $transcript_path (session: $session_id)${NC}" >&2 |
|
|
|
# Get last assistant message and extract content[].text |
|
local content_text=$(jq -s --arg sid "$session_id" ' |
|
map(select(.sessionId == $sid and .type == "assistant")) |
|
| last |
|
| .message.content[]?.text // empty |
|
' "$transcript_path" 2>/dev/null | jq -r '. // empty' | tr '\n' ' ') |
|
|
|
if [ -n "$content_text" ] && [ "$content_text" != "empty" ]; then |
|
echo -e "${GREEN}Successfully extracted content text${NC}" >&2 |
|
echo "$content_text" |
|
else |
|
echo -e "${YELLOW}No content text found${NC}" >&2 |
|
echo "" |
|
fi |
|
else |
|
echo -e "${YELLOW}Cannot extract content text (missing file/session/jq)${NC}" >&2 |
|
echo "" |
|
fi |
|
} |
|
|
|
# Function to find user by email |
|
find_user_by_email() { |
|
local email=$1 |
|
local response=$(curl -s -X GET \ |
|
-H "Authorization: Bearer $TOKEN" \ |
|
-H "Content-type: application/json" \ |
|
"https://slack.com/api/users.lookupByEmail?email=$email") |
|
|
|
local ok=$(echo "$response" | grep -o '"ok":[^,}]*' | cut -d: -f2) |
|
|
|
if [ "$ok" = "true" ]; then |
|
echo "$response" | grep -o '"id":"[^"]*' | cut -d'"' -f4 |
|
else |
|
local error=$(echo "$response" | grep -o '"error":"[^"]*' | cut -d'"' -f4) |
|
echo -e "${RED}❌ Error finding user by email: $error${NC}" >&2 |
|
return 1 |
|
fi |
|
} |
|
|
|
# Function to open conversation and get channel ID |
|
open_conversation() { |
|
local user_id=$1 |
|
local response=$(curl -s -X POST \ |
|
-H "Authorization: Bearer $TOKEN" \ |
|
-H "Content-type: application/json" \ |
|
-d "{\"users\": \"$user_id\"}" \ |
|
https://slack.com/api/conversations.open) |
|
|
|
local ok=$(echo "$response" | grep -o '"ok":[^,}]*' | cut -d: -f2) |
|
|
|
if [ "$ok" = "true" ]; then |
|
echo "$response" | grep -o '"id":"[^"]*' | head -1 | cut -d'"' -f4 |
|
else |
|
local error=$(echo "$response" | grep -o '"error":"[^"]*' | cut -d'"' -f4) |
|
echo -e "${RED}❌ Error opening conversation: $error${NC}" >&2 |
|
return 1 |
|
fi |
|
} |
|
|
|
# Function to send message |
|
send_message() { |
|
local channel_id=$1 |
|
local message=$2 |
|
|
|
# Create JSON payload with jq if available |
|
if command -v jq >/dev/null 2>&1; then |
|
local json_payload=$(jq -n --arg channel "$channel_id" --arg text "$message" '{channel: $channel, text: $text}') |
|
else |
|
local escaped_message=$(echo "$message" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g; s/\r/\\r/g; s/$/\\n/g' | tr -d '\n' | sed 's/\\n$//') |
|
local json_payload="{\"channel\": \"$channel_id\", \"text\": \"$escaped_message\"}" |
|
fi |
|
|
|
local response=$(curl -s -X POST \ |
|
-H "Authorization: Bearer $TOKEN" \ |
|
-H "Content-type: application/json" \ |
|
-d "$json_payload" \ |
|
https://slack.com/api/chat.postMessage) |
|
|
|
local ok=$(echo "$response" | grep -o '"ok":[^,}]*' | cut -d: -f2) |
|
|
|
if [ "$ok" = "true" ]; then |
|
echo -e "${GREEN}✅ Message sent successfully!${NC}" |
|
return 0 |
|
else |
|
local error=$(echo "$response" | grep -o '"error":"[^"]*' | cut -d'"' -f4) |
|
echo -e "${RED}❌ Error sending message: $error${NC}" >&2 |
|
return 1 |
|
fi |
|
} |
|
|
|
# Parse command line arguments |
|
while getopts "t:u:e:m:h" opt; do |
|
case $opt in |
|
t) |
|
TOKEN="$OPTARG" |
|
;; |
|
u) |
|
USER_ID="$OPTARG" |
|
;; |
|
e) |
|
EMAIL="$OPTARG" |
|
;; |
|
m) |
|
MESSAGE="$OPTARG" |
|
;; |
|
h) |
|
usage |
|
;; |
|
\?) |
|
echo "Invalid option: -$OPTARG" >&2 |
|
usage |
|
;; |
|
esac |
|
done |
|
|
|
# Check for token (from argument or environment variable) |
|
if [ -z "$TOKEN" ]; then |
|
if [ -n "${SLACK_TOKEN:-}" ]; then |
|
TOKEN="$SLACK_TOKEN" |
|
else |
|
echo -e "${RED}Error: Slack token not provided. Use -t option or set SLACK_TOKEN environment variable${NC}" >&2 |
|
usage |
|
fi |
|
fi |
|
|
|
# Check for user identification |
|
if [ -z "$USER_ID" ] && [ -z "$EMAIL" ]; then |
|
echo -e "${RED}Error: Either user ID (-u) or email (-e) must be provided${NC}" >&2 |
|
usage |
|
fi |
|
|
|
# Get message - if no -m provided, extract from transcript |
|
if [ -z "$MESSAGE" ]; then |
|
if [ -n "$INPUT" ]; then |
|
MESSAGE=$(extract_content_text "$INPUT") |
|
if [ -z "$MESSAGE" ]; then |
|
echo -e "${RED}Error: No content text extracted and no message provided${NC}" >&2 |
|
exit 1 |
|
fi |
|
else |
|
echo -e "${RED}Error: Message not provided and no input available${NC}" >&2 |
|
usage |
|
fi |
|
fi |
|
|
|
# If email provided, convert to user ID |
|
if [ -n "$EMAIL" ]; then |
|
echo -e "${YELLOW}Finding user by email: $EMAIL${NC}" |
|
if USER_ID=$(find_user_by_email "$EMAIL"); then |
|
echo -e "${GREEN}Found user ID: $USER_ID${NC}" |
|
else |
|
echo "Error: Failed to find user by email" >&2 |
|
exit 1 |
|
fi |
|
fi |
|
|
|
# Open conversation with user |
|
echo -e "${YELLOW}Opening conversation with user: $USER_ID${NC}" |
|
if CHANNEL_ID=$(open_conversation "$USER_ID"); then |
|
echo -e "${GREEN}Successfully opened conversation${NC}" >&2 |
|
else |
|
echo "Error: Failed to open conversation" >&2 |
|
exit 1 |
|
fi |
|
|
|
# Send the message |
|
echo -e "${YELLOW}Sending message...${NC}" |
|
if send_message "$CHANNEL_ID" "$MESSAGE"; then |
|
echo -e "${GREEN}Script completed successfully${NC}" >&2 |
|
exit 0 |
|
else |
|
echo "Error: Failed to send message" >&2 |
|
exit 1 |
|
fi |