|
| 1 | +#!/usr/bin/env bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +# Usage: ./summarize-group.sh <group-name> [week] [post-count] |
| 5 | +# week: "current" (default), "previous", or "weekXX" (e.g. week03, week52) |
| 6 | +# Examples: |
| 7 | +# ./summarize-group.sh skjs |
| 8 | +# ./summarize-group.sh skjs previous |
| 9 | +# ./summarize-group.sh skjs week12 |
| 10 | +# ./summarize-group.sh skjs current 100 |
| 11 | + |
| 12 | +GROUP_NAME="${1:?Usage: ./summarize-group.sh <group-name> [current|previous|weekXX] [post-count]}" |
| 13 | +WEEK_ARG="${2:-current}" |
| 14 | +POST_COUNT="${3:-100}" |
| 15 | + |
| 16 | +# Compute week start (Monday) and end (Sunday 23:59:59) as ISO timestamps |
| 17 | +compute_week_range() { |
| 18 | + local week_arg="$1" |
| 19 | + local year week_num monday_date sunday_date |
| 20 | + |
| 21 | + year=$(date +%Y) |
| 22 | + |
| 23 | + case "$week_arg" in |
| 24 | + current) |
| 25 | + # Current ISO week number |
| 26 | + week_num=$(date +%V) |
| 27 | + ;; |
| 28 | + previous) |
| 29 | + # Go back 7 days, get that week number |
| 30 | + week_num=$(date -v-7d +%V 2>/dev/null || date -d "7 days ago" +%V) |
| 31 | + # Handle year boundary (if previous week is in last year) |
| 32 | + local prev_year |
| 33 | + prev_year=$(date -v-7d +%Y 2>/dev/null || date -d "7 days ago" +%Y) |
| 34 | + year="$prev_year" |
| 35 | + ;; |
| 36 | + week[0-9][0-9]) |
| 37 | + week_num="${week_arg#week}" |
| 38 | + ;; |
| 39 | + *) |
| 40 | + echo "Error: invalid week argument '$week_arg'" >&2 |
| 41 | + echo "Use 'current', 'previous', or 'weekXX' (e.g. week03, week52)" >&2 |
| 42 | + exit 1 |
| 43 | + ;; |
| 44 | + esac |
| 45 | + |
| 46 | + # Strip leading zero for arithmetic |
| 47 | + local wn=$((10#$week_num)) |
| 48 | + if [ "$wn" -lt 1 ] || [ "$wn" -gt 53 ]; then |
| 49 | + echo "Error: week number must be between 01 and 53, got '$week_num'" >&2 |
| 50 | + exit 1 |
| 51 | + fi |
| 52 | + |
| 53 | + # macOS date: compute Monday of ISO week |
| 54 | + # Jan 4 is always in ISO week 1. Find Monday of week 1, then offset. |
| 55 | + local jan4_dow |
| 56 | + jan4_dow=$(date -j -f "%Y-%m-%d" "${year}-01-04" +%u 2>/dev/null) |
| 57 | + if [ -n "$jan4_dow" ]; then |
| 58 | + # macOS date |
| 59 | + local jan4_epoch |
| 60 | + jan4_epoch=$(date -j -f "%Y-%m-%d" "${year}-01-04" +%s) |
| 61 | + local week1_monday_epoch=$(( jan4_epoch - (jan4_dow - 1) * 86400 )) |
| 62 | + local target_monday_epoch=$(( week1_monday_epoch + (wn - 1) * 7 * 86400 )) |
| 63 | + local target_sunday_epoch=$(( target_monday_epoch + 6 * 86400 )) |
| 64 | + monday_date=$(date -r "$target_monday_epoch" +%Y-%m-%d) |
| 65 | + sunday_date=$(date -r "$target_sunday_epoch" +%Y-%m-%d) |
| 66 | + else |
| 67 | + # GNU date fallback |
| 68 | + monday_date=$(date -d "${year}-01-04 -$(date -d "${year}-01-04" +%u) days + 1 day + $((wn - 1)) weeks" +%Y-%m-%d) |
| 69 | + sunday_date=$(date -d "$monday_date + 6 days" +%Y-%m-%d) |
| 70 | + fi |
| 71 | + |
| 72 | + WEEK_START="${monday_date}T00:00:00Z" |
| 73 | + WEEK_END="${sunday_date}T23:59:59Z" |
| 74 | + WEEK_LABEL="week ${week_num} ${year} (${monday_date} → ${sunday_date})" |
| 75 | +} |
| 76 | + |
| 77 | +compute_week_range "$WEEK_ARG" |
| 78 | + |
| 79 | +# Load .env |
| 80 | +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| 81 | +if [ -f "$SCRIPT_DIR/.env" ]; then |
| 82 | + set -a |
| 83 | + source "$SCRIPT_DIR/.env" |
| 84 | + set +a |
| 85 | +fi |
| 86 | + |
| 87 | +DB_URL="${POSTGRESQL_ADDON_URI:?Missing POSTGRESQL_ADDON_URI in .env}" |
| 88 | +GRAPHQL_URL="${SLASHWORK_GRAPHQL_URL:?Missing SLASHWORK_GRAPHQL_URL in .env}" |
| 89 | + |
| 90 | +# Fetch group ID and auth token from the prod DB |
| 91 | +DB_ROW=$(psql "$DB_URL" -t -A -F '|' -c " |
| 92 | + SELECT g.slashwork_id, at.token |
| 93 | + FROM groups g |
| 94 | + JOIN auth_tokens at ON g.auth_token = at.name |
| 95 | + WHERE g.name = '$GROUP_NAME' |
| 96 | +") |
| 97 | + |
| 98 | +if [ -z "$DB_ROW" ]; then |
| 99 | + echo "Error: group '$GROUP_NAME' not found in database" >&2 |
| 100 | + echo "Available groups:" >&2 |
| 101 | + psql "$DB_URL" -t -A -c "SELECT name FROM groups ORDER BY name" >&2 |
| 102 | + exit 1 |
| 103 | +fi |
| 104 | + |
| 105 | +GROUP_ID=$(echo "$DB_ROW" | cut -d'|' -f1) |
| 106 | +AUTH_TOKEN=$(echo "$DB_ROW" | cut -d'|' -f2) |
| 107 | + |
| 108 | +echo "Fetching posts from '$GROUP_NAME' for $WEEK_LABEL..." >&2 |
| 109 | + |
| 110 | +QUERY='query FetchGroupPosts($groupId: ID!, $first: Int!) { |
| 111 | + fetch__Group(id: $groupId) { |
| 112 | + name |
| 113 | + posts(first: $first) { |
| 114 | + edges { |
| 115 | + node { |
| 116 | + id |
| 117 | + markdown |
| 118 | + created |
| 119 | + author { id name } |
| 120 | + comments(first: 100) { |
| 121 | + edges { |
| 122 | + node { |
| 123 | + markdown |
| 124 | + created |
| 125 | + author { name } |
| 126 | + replies(first: 100) { |
| 127 | + edges { |
| 128 | + node { |
| 129 | + markdown |
| 130 | + created |
| 131 | + author { name } |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | + } |
| 142 | +}' |
| 143 | + |
| 144 | +PAYLOAD=$(jq -n \ |
| 145 | + --arg query "$QUERY" \ |
| 146 | + --arg groupId "$GROUP_ID" \ |
| 147 | + --argjson first "$POST_COUNT" \ |
| 148 | + '{query: $query, variables: {groupId: $groupId, first: $first}}') |
| 149 | + |
| 150 | +RESPONSE=$(curl -s -f "$GRAPHQL_URL" \ |
| 151 | + -H "Content-Type: application/json" \ |
| 152 | + -H "Authorization: Bearer $AUTH_TOKEN" \ |
| 153 | + -d "$PAYLOAD") |
| 154 | + |
| 155 | +# Check for API errors |
| 156 | +API_ERRORS=$(echo "$RESPONSE" | jq -r '.errors // [] | .[].message' 2>/dev/null) |
| 157 | +if [ -n "$API_ERRORS" ]; then |
| 158 | + echo "GraphQL error: $API_ERRORS" >&2 |
| 159 | + exit 1 |
| 160 | +fi |
| 161 | + |
| 162 | +# Extract and format messages, filtering by week date range |
| 163 | +MESSAGES=$(echo "$RESPONSE" | jq -r --arg start "$WEEK_START" --arg end "$WEEK_END" ' |
| 164 | + [(.data.fetch__Group.posts // {edges:[]}).edges[].node |
| 165 | + | select(.created >= $start and .created <= $end)] |
| 166 | + | if length == 0 then empty else |
| 167 | + .[] | |
| 168 | + "--- \(.author.name) [\(.created)] ---\n\(.markdown)\n" + |
| 169 | + ([(.comments // {edges:[]}).edges[].node | |
| 170 | + " > \(.author.name) [\(.created)]:\n \(.markdown)\n" + |
| 171 | + ([(.replies // {edges:[]}).edges[].node | |
| 172 | + " >> \(.author.name) [\(.created)]:\n \(.markdown)" |
| 173 | + ] | join("\n")) |
| 174 | + ] | join("\n")) |
| 175 | + end |
| 176 | +') |
| 177 | + |
| 178 | +if [ -z "$MESSAGES" ]; then |
| 179 | + echo "No messages found in group '$GROUP_NAME' for $WEEK_LABEL" |
| 180 | + exit 0 |
| 181 | +fi |
| 182 | + |
| 183 | +POST_TOTAL=$(echo "$RESPONSE" | jq --arg start "$WEEK_START" --arg end "$WEEK_END" ' |
| 184 | + [(.data.fetch__Group.posts // {edges:[]}).edges[].node | select(.created >= $start and .created <= $end)] | length |
| 185 | +') |
| 186 | +echo "Found $POST_TOTAL posts for $WEEK_LABEL" >&2 |
| 187 | + |
| 188 | +SUMMARY=$(echo "$MESSAGES" | claude -p "Summarize the following messages from the '$GROUP_NAME' group for $WEEK_LABEL. Give a concise overview of the key topics, decisions, and action items discussed:") |
| 189 | + |
| 190 | +echo "$SUMMARY" |
0 commit comments