AI Newsletter Digest improvements: fixed QP soft line break decoding, URL extraction, and content cleaning

This commit is contained in:
Krilly
2026-03-04 13:29:22 +00:00
parent 29a98137a7
commit 57dd294675
13706 changed files with 2114953 additions and 237629 deletions

View File

@@ -0,0 +1,170 @@
#!/bin/bash
set -euo pipefail
# Emergency Recovery Monitor - Discord 알림
# emergency-recovery 로그에서 실패 케이스 감지 → Discord 알림
# ============================================
# Configuration (Override via environment)
# ============================================
LOG_DIR="${OPENCLAW_MEMORY_DIR:-$HOME/openclaw/memory}"
ALERT_SENT_FILE="$LOG_DIR/.emergency-alert-sent"
ALERT_WINDOW_MINUTES="${EMERGENCY_ALERT_WINDOW:-30}"
# Create log directory if not exists
mkdir -p "$LOG_DIR"
# Load environment variables
if [ -f "$HOME/openclaw/.env" ]; then
# shellcheck source=/dev/null
source "$HOME/openclaw/.env"
elif [ -f "$HOME/.openclaw/.env" ]; then
# shellcheck source=/dev/null
source "$HOME/.openclaw/.env"
fi
# Discord webhook from environment variable (optional)
DISCORD_WEBHOOK="${DISCORD_WEBHOOK_URL:-}"
# Cleanup on exit
trap 'rm -f /tmp/emergency-alert.txt' EXIT
# ============================================
# Functions
# ============================================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
get_latest_recovery_log() {
# Use find instead of ls (ShellCheck SC2012)
find "$LOG_DIR" -name "emergency-recovery-*.log" -type f -print0 2>/dev/null | \
xargs -0 ls -t 2>/dev/null | head -1
}
is_alert_already_sent() {
local latest_log="$1"
if [ ! -f "$ALERT_SENT_FILE" ]; then
return 1
fi
local sent_log
sent_log=$(cat "$ALERT_SENT_FILE" 2>/dev/null || echo "")
[ "$sent_log" = "$latest_log" ]
}
mark_alert_sent() {
local latest_log="$1"
# Atomic write
echo "$latest_log" > "$ALERT_SENT_FILE.tmp"
mv "$ALERT_SENT_FILE.tmp" "$ALERT_SENT_FILE"
}
send_alert() {
local latest_log="$1"
local timestamp
timestamp=$(basename "$latest_log" | sed 's/emergency-recovery-//;s/.log//')
# Discord 알림 메시지 생성
cat > /tmp/emergency-alert.txt << EOF
🚨 **긴급: OpenClaw 자가복구 실패**
**시간:** $timestamp
**상태:**
- Level 1 (Watchdog) ❌
- Level 2 (Health Check) ❌
- Level 3 (Claude Recovery) ❌
**수동 개입 필요합니다.**
**로그:**
- \`$latest_log\`
- \`$LOG_DIR/claude-session-$timestamp.log\`
- \`$LOG_DIR/emergency-recovery-report-$timestamp.md\` (Claude가 생성했을 경우)
**복구 시도:**
1. \`openclaw status\` 확인
2. \`~/.openclaw/logs/*.log\` 에러 확인
3. \`openclaw gateway restart\` 시도
4. 필요 시 \`openclaw gateway stop && sleep 5 && openclaw gateway start\`
EOF
local alert_msg
alert_msg=$(cat /tmp/emergency-alert.txt)
# Discord 직접 호출 (webhook 있을 경우)
if [ -n "$DISCORD_WEBHOOK" ]; then
local response_code
response_code=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "$DISCORD_WEBHOOK" \
-H "Content-Type: application/json" \
-d "{\"content\": \"$alert_msg\"}" \
2>&1 || echo "000")
if [ "$response_code" = "200" ] || [ "$response_code" = "204" ]; then
log "✅ Discord notification sent (HTTP $response_code)"
else
log "⚠️ Discord notification failed (HTTP $response_code), falling back to stdout"
cat /tmp/emergency-alert.txt
fi
else
# Webhook 없으면 stdout 출력 (크론이 message tool로 전달)
log "INFO: DISCORD_WEBHOOK_URL not set, printing to stdout"
cat /tmp/emergency-alert.txt
fi
}
# ============================================
# Main Logic
# ============================================
main() {
# 최근 N분 내 emergency-recovery 로그 찾기
local recent_logs
recent_logs=$(find "$LOG_DIR" -name "emergency-recovery-*.log" -type f -mmin -"$ALERT_WINDOW_MINUTES" 2>/dev/null)
if [ -z "$recent_logs" ]; then
# 최근 emergency recovery 없음
log "No recent emergency recovery logs found (last ${ALERT_WINDOW_MINUTES} minutes)"
exit 0
fi
# 가장 최근 로그 확인
local latest_log
latest_log=$(get_latest_recovery_log)
if [ -z "$latest_log" ] || [ ! -f "$latest_log" ]; then
log "No valid emergency recovery logs found"
exit 0
fi
# 이미 알림 보낸 로그인지 체크
if is_alert_already_sent "$latest_log"; then
log "Alert already sent for: $latest_log"
exit 0
fi
# "MANUAL INTERVENTION REQUIRED" 패턴 검색
if grep -q "MANUAL INTERVENTION REQUIRED" "$latest_log"; then
log "Found failed recovery in: $latest_log"
# 알림 전송
send_alert "$latest_log"
# 알림 보냄 기록
mark_alert_sent "$latest_log"
exit 0
else
log "No manual intervention required in: $latest_log"
fi
exit 0
}
# Run main function
main