Created
April 13, 2026 05:12
-
-
Save halu0915/7233888888eea4c676f495b2bdb2c54a to your computer and use it in GitHub Desktop.
Claude Code Telegram Daemon — 繞過入站 bug (GitHub #37933)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Claude Code Telegram Daemon — 繞過壞掉的插件,直接 Bot API 輪詢 + claude -p 自動回覆 | |
| # macOS 版,適用於 Claude Code Telegram 入站 bug (GitHub #37933) | |
| # | |
| # 用法: | |
| # ./claude-telegram-daemon.sh | |
| # 或背景運行:nohup ./claude-telegram-daemon.sh > ~/claude-telegram.log 2>&1 & | |
| # | |
| # 需要:curl, jq, claude CLI | |
| set -euo pipefail | |
| # ===== 設定區 ===== | |
| BOT_TOKEN="${CLAUDE_TELEGRAM_BOT_TOKEN:-}" | |
| ALLOWED_USERS="${CLAUDE_TELEGRAM_ALLOWED_USERS:-}" | |
| API="https://api.telegram.org/bot${BOT_TOKEN}" | |
| INBOX="$HOME/.claude/channels/telegram/inbox" | |
| OFFSET_FILE="$HOME/.claude/channels/telegram/.poll_offset" | |
| POLL_INTERVAL=3 | |
| if [ -z "$BOT_TOKEN" ]; then | |
| echo "❌ 請設定環境變數 CLAUDE_TELEGRAM_BOT_TOKEN" | |
| echo " export CLAUDE_TELEGRAM_BOT_TOKEN='your-bot-token'" | |
| exit 1 | |
| fi | |
| if [ -z "$ALLOWED_USERS" ]; then | |
| echo "❌ 請設定環境變數 CLAUDE_TELEGRAM_ALLOWED_USERS(用戶 ID)" | |
| echo " export CLAUDE_TELEGRAM_ALLOWED_USERS='1234567890'" | |
| echo " 查詢方式:Telegram 搜尋 @userinfobot 取得你的 ID" | |
| exit 1 | |
| fi | |
| mkdir -p "$INBOX" | |
| offset=0 | |
| [[ -f "$OFFSET_FILE" ]] && offset=$(<"$OFFSET_FILE") | |
| log() { echo "[$(date '+%H:%M:%S')] $*"; } | |
| cleanup() { log "停止 Telegram Daemon"; exit 0; } | |
| trap cleanup SIGTERM SIGINT | |
| log "🤖 Claude Telegram Daemon 啟動(offset=$offset)" | |
| log " Bot Token: ...${BOT_TOKEN: -6}" | |
| log " 允許用戶: $ALLOWED_USERS" | |
| log " Inbox: $INBOX" | |
| while true; do | |
| response=$(curl -sf --max-time 10 \ | |
| "${API}/getUpdates?offset=${offset}&timeout=2&allowed_updates=%5B%22message%22%5D" 2>/dev/null) || { | |
| log "⚠️ API 請求失敗,重試..." | |
| sleep "$POLL_INTERVAL" | |
| continue | |
| } | |
| count=$(echo "$response" | jq '.result | length') | |
| for ((i = 0; i < count; i++)); do | |
| update=$(echo "$response" | jq ".result[$i]") | |
| update_id=$(echo "$update" | jq '.update_id') | |
| sender_id=$(echo "$update" | jq -r '.message.from.id // empty') | |
| # 允許清單檢查 | |
| if [[ "$sender_id" != "$ALLOWED_USERS" ]]; then | |
| log "⏭️ 忽略來自 $sender_id 的訊息" | |
| offset=$((update_id + 1)) | |
| echo "$offset" > "$OFFSET_FILE" | |
| continue | |
| fi | |
| msg=$(echo "$update" | jq '.message') | |
| msg_id=$(echo "$msg" | jq '.message_id') | |
| timestamp=$(date '+%Y%m%d-%H%M%S') | |
| text=$(echo "$msg" | jq -r '.text // .caption // empty') | |
| sender_name=$(echo "$msg" | jq -r '.from.first_name // "User"') | |
| # 處理照片 | |
| photo_file=$(echo "$msg" | jq -r '.photo[-1].file_id // empty') | |
| if [[ -n "$photo_file" ]]; then | |
| file_info=$(curl -sf "${API}/getFile?file_id=${photo_file}" 2>/dev/null) | |
| file_path=$(echo "$file_info" | jq -r '.result.file_path // empty') | |
| if [[ -n "$file_path" ]]; then | |
| photo_out="${INBOX}/${timestamp}_${msg_id}.jpg" | |
| curl -sf "https://api.telegram.org/file/bot${BOT_TOKEN}/${file_path}" \ | |
| -o "$photo_out" 2>/dev/null | |
| log "📷 照片已存:$photo_out" | |
| fi | |
| fi | |
| # 處理文件 | |
| doc_file=$(echo "$msg" | jq -r '.document.file_id // empty') | |
| if [[ -n "$doc_file" ]]; then | |
| doc_name=$(echo "$msg" | jq -r '.document.file_name // "document"') | |
| file_info=$(curl -sf "${API}/getFile?file_id=${doc_file}" 2>/dev/null) | |
| file_path=$(echo "$file_info" | jq -r '.result.file_path // empty') | |
| if [[ -n "$file_path" ]]; then | |
| doc_out="${INBOX}/${timestamp}_${msg_id}_${doc_name}" | |
| curl -sf "https://api.telegram.org/file/bot${BOT_TOKEN}/${file_path}" \ | |
| -o "$doc_out" 2>/dev/null | |
| log "📎 文件已存:$doc_out" | |
| fi | |
| fi | |
| # 存文字到 inbox | |
| if [[ -n "$text" ]]; then | |
| echo "$text" > "${INBOX}/${timestamp}_${msg_id}.txt" | |
| log "💬 ${sender_name}:${text:0:50}" | |
| fi | |
| # 用 Claude 自動回覆 | |
| if [[ -n "$text" ]]; then | |
| # 顯示打字中 | |
| curl -sf -X POST "${API}/sendChatAction" \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"chat_id\":${sender_id},\"action\":\"typing\"}" \ | |
| >/dev/null 2>&1 || true | |
| # 呼叫 claude -p 取得回覆 | |
| reply=$(claude -p "你是 AI 助理,用繁體中文回覆。 | |
| 用戶訊息:${text}" 2>/dev/null) || reply="" | |
| if [[ -n "$reply" ]]; then | |
| # 截斷到 Telegram 限制 | |
| reply="${reply:0:4096}" | |
| curl -sf -X POST "${API}/sendMessage" \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"chat_id\":${sender_id},\"text\":$(echo "$reply" | jq -Rs .),\"reply_to_message_id\":${msg_id}}" \ | |
| >/dev/null 2>&1 || true | |
| log "✅ 已回覆 msg $msg_id" | |
| else | |
| # Claude 失敗,發送 👀 表示已收到 | |
| curl -sf -X POST "${API}/setMessageReaction" \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"chat_id\":${sender_id},\"message_id\":${msg_id},\"reaction\":[{\"type\":\"emoji\",\"emoji\":\"👀\"}]}" \ | |
| >/dev/null 2>&1 || true | |
| log "⚠️ Claude 回覆失敗,已標記 👀" | |
| fi | |
| else | |
| # 非文字訊息(照片/文件),標記已收到 | |
| curl -sf -X POST "${API}/setMessageReaction" \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"chat_id\":${sender_id},\"message_id\":${msg_id},\"reaction\":[{\"type\":\"emoji\",\"emoji\":\"👀\"}]}" \ | |
| >/dev/null 2>&1 || true | |
| fi | |
| offset=$((update_id + 1)) | |
| echo "$offset" > "$OFFSET_FILE" | |
| done | |
| sleep "$POLL_INTERVAL" | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment