#!/bin/bash # Daily Digest Generator - v4 (matches Feb 28 format) # Each article: Title + Summary + [Read more](URL) set -euo pipefail BLOG_API_URL="https://blog.twisteddevices.com/api" BLOG_MACHINE_TOKEN="21719c689a355e40b427a35c548b28699bd7c014aac4d23f5c1bbb122bbb9878" DATE="${1:-$(date +%Y-%m-%d)}" echo "=== Daily Digest Generator v4 ===" echo "Date: $DATE" echo "" # Step 1: Check if digest already exists echo "[1/5] Checking if digest exists for $DATE..." ALL_MESSAGES=$(curl -s "${BLOG_API_URL}/messages?limit=100" \ -H "x-api-key: ${BLOG_MACHINE_TOKEN}") if echo "$ALL_MESSAGES" | jq -e --arg date "$DATE" '.[] | select(.date == $date)' >/dev/null 2>&1; then echo "Digest already exists for $DATE. Skipping." exit 0 fi echo "No digest found. Proceeding..." # Step 2: Research echo "[2/5] Loading API key and researching..." source ~/.openclaw/workspace/.env.tavily export TAVILY_API_KEY echo " - iOS/Apple news..." IOS_RAW=$(node ~/.agents/skills/tavily/scripts/search.mjs "Apple iOS AI development news" -n 5 --topic news 2>/dev/null || echo "") echo " - AI news..." AI_RAW=$(node ~/.agents/skills/tavily/scripts/search.mjs "AI models news March 2026" -n 5 --topic news 2>/dev/null || echo "") echo " - Coding assistants..." CODING_RAW=$(node ~/.agents/skills/tavily/scripts/search.mjs "AI coding assistants Claude Cursor news" -n 5 --topic news 2>/dev/null || echo "") echo " - OpenClaw/agents..." AGENTS_RAW=$(node ~/.agents/skills/tavily/scripts/search.mjs "OpenClaw AI agents autonomous development" -n 5 --topic news 2>/dev/null || echo "") echo " - Entrepreneurship..." ENTRE_RAW=$(node ~/.agents/skills/tavily/scripts/search.mjs "indie hackers SaaS app development" -n 5 --topic news 2>/dev/null || echo "") # Step 3: Format content - matches Feb 28 format exactly echo "[3/5] Formatting content..." # Function to parse each article: **Title** + summary + [Read more](url) format_articles() { local raw="$1" # Get the Sources section local sources=$(echo "$raw" | sed -n '/## Sources/,$p' | tail -n +2) if [[ -z "$sources" ]]; then echo "*No recent news found*" return fi # Split by source blocks using perl echo "$sources" | perl -00 -ne ' my $block = $_; chomp $block; # Skip if empty return if $block !~ /\w/; # Extract title: **Title - Source** (relevance: XX%) my $title = ""; if ($block =~ /\*\*([^-]+)/) { $title = $1; $title =~ s/^\s+|\s+$//g; $title =~ s/\s*\(relevance.*$//; } # Extract URL - first URL in block my $url = ""; if ($block =~ /(https:\/\/[^\s\)\"]+)/) { $url = $1; } # Extract description - text between URL and end of block (or next -) my $desc = ""; if ($url && $block =~ /\Q$url\E\s*\n\s*(#.+)/) { $desc = $1; $desc =~ s/^#\s+//; $desc =~ s/^\s+|\s+$//g; $desc =~ s/\s+/ /g; $desc =~ s/##.*$//; $desc = substr($desc, 0, 200); $desc =~ s/\s+\S*$//; } if ($title && $url) { print "**$title**\n\n"; print "$desc\n\n" if $desc; print "[Read more]($url)\n\n---\n\n"; } ' | head -50 } IOS_CONTENT=$(format_articles "$IOS_RAW") AI_CONTENT=$(format_articles "$AI_RAW") CODING_CONTENT=$(format_articles "$CODING_RAW") AGENTS_CONTENT=$(format_articles "$AGENTS_RAW") ENTRE_CONTENT=$(format_articles "$ENTRE_RAW") # Build content - match Feb 28 format exactly DAY_NAME=$(date +%A) MONTH_NAME=$(date +%B) DAY_NUM=$(date +%-d) YEAR=$(date +%Y) CONTENT="# Daily Digest - $DAY_NAME, $MONTH_NAME $DAY_NUM, $YEAR ### 🍎 iOS AI Development News $IOS_CONTENT --- ### 🤖 AI Coding Assistants $CODING_CONTENT --- ### 🦞 OpenClaw & AI Agents $AGENTS_CONTENT --- ### 🚀 Entrepreneurship $ENTRE_CONTENT --- *Generated by OpenClaw*" # Step 4: Post to blog echo "[4/5] Posting to blog..." RESULT=$(curl -s -X POST "${BLOG_API_URL}/messages" \ -H "x-api-key: ${BLOG_MACHINE_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"date\":\"$DATE\",\"content\":$(echo "$CONTENT" | jq -Rs .),\"tags\":[\"daily-digest\",\"iOS\",\"AI\",\"Apple\",\"OpenClaw\"]}" 2>&1) if echo "$RESULT" | jq -e '.id' >/dev/null 2>&1; then ID=$(echo "$RESULT" | jq -r '.id') echo "[5/5] ✅ Success!" echo "Digest ID: $ID" exit 0 else echo "[5/5] ❌ Failed to post" echo "$RESULT" exit 1 fi