📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-10 16:04:20 +00:00
parent 2bb0dc8c1d
commit 92c0c3f687
594 changed files with 55224 additions and 19038 deletions
@@ -0,0 +1,178 @@
# Telegram Skill
An AI agent skill for sending Telegram messages, files, and alerts via the Bot API - send updates, ask-and-wait for approval with inline buttons, and read replies. Works with Claude Code, Gemini CLI, Cursor, OpenAI Codex, Goose, and other AI clients supporting the [Agent Skills Standard](https://agentskills.io).
## Features
- **Send** - Plain text, MarkdownV2, or HTML messages (auto-splits over 4096 chars, auto-falls back to plain text if formatting is rejected)
- **File** - Send documents; images (png/jpg/jpeg/gif/webp) are automatically sent as photos
- **Ask** - Ask a question with inline buttons and wait for a tap or free-text reply (approve-from-phone)
- **Read** - Print new incoming messages since the last read
- **Multi-bot** - Register additional named bots alongside the default
- **Multi-target** - Route messages to named chats, groups, or channels
- **Hook integration** - Wire into Claude Code hooks, cron jobs, or CI for notifications
Pure bash + curl + jq — no install beyond a bot token.
## Requirements
- `bash`
- `curl`
- `jq` (`brew install jq` on macOS, `apt install jq` on Debian/Ubuntu)
macOS ships bash and curl out of the box; only `jq` typically needs installing.
## Quick Start
### 1. Create a bot
1. Open [@BotFather](https://t.me/BotFather) in Telegram
2. Send `/newbot` and follow the prompts (display name, then a username ending in "bot")
3. BotFather replies with an HTTP API token
### 2. Run setup
```bash
scripts/telegram.sh setup
```
This walks you through pasting the token, validates it via `getMe`, and asks you to send a message to your new bot so it can discover your chat ID. Config is written to `~/.config/telegram/config` (mode 600), and a confirmation message is sent to confirm everything works.
### 3. Add more bots (optional)
```bash
scripts/telegram.sh setup --bot alerts
```
Repeat with a different `--bot NAME` for each additional bot. Named bots share the default chat ID unless you configure a different target for them.
### 4. Find group/channel IDs (optional)
To send to a group or channel instead of your personal chat:
1. Add your bot to the group/channel
2. Send any message in that group/channel
3. Run `scripts/telegram.sh read --all` to see the chat ID printed alongside the message
4. Add `TARGET_<NAME>=<chat_id>` to `~/.config/telegram/config`, then use `--to <name>`
## Usage Examples
### Send Messages
```bash
# Basic alert
scripts/telegram.sh send "Deploy finished ✅"
# No notification sound
scripts/telegram.sh send "low priority update" --silent
# MarkdownV2 formatting (falls back to plain text if rejected)
scripts/telegram.sh send "*bold* alert" --format md
# HTML formatting
scripts/telegram.sh send "<b>bold</b> alert" --format html
# Named target and named bot
scripts/telegram.sh send "hi" --to alerts --bot work
```
### Send Files
```bash
# Send a document
scripts/telegram.sh file report.pdf "Q3 report"
# Images are auto-detected and sent as photos
scripts/telegram.sh file screenshot.png "Build output"
# To a named target, silently
scripts/telegram.sh file backup.zip --to alerts --silent
```
### Ask and Wait for an Answer
```bash
# Default Yes/No options, 5-minute timeout
ANSWER=$(scripts/telegram.sh ask "Deploy to prod?" --options "Yes,No" --timeout 300)
echo "$ANSWER"
# Custom options
scripts/telegram.sh ask "Which environment?" --options "Staging,Prod,Cancel"
```
Exit code `0` means answered (the answer is printed to stdout); exit code `2` means the timeout was reached with no reply.
### Read Incoming Messages
```bash
# New messages since the last read (advances the offset)
scripts/telegram.sh read
# Limit the number of messages
scripts/telegram.sh read --limit 5
# Ignore the saved offset and show everything available
scripts/telegram.sh read --all
```
Note: `ask` and `read` share the same per-bot cursor, so an `ask` consumes incoming messages that a later `read` would otherwise show.
## Command Reference
| Command | Description | Arguments | Exit codes |
|---------|-------------|-----------|------------|
| `setup` | Guided bot registration + chat-ID discovery | `--bot NAME` | 0 success, 1 error |
| `send MESSAGE` | Send a text message | `--to TARGET`, `--bot NAME`, `--silent`, `--format md\|html` | 0 success, 1 error |
| `file PATH [CAPTION]` | Send a document (or photo for images) | `--to TARGET`, `--bot NAME`, `--silent` | 0 success, 1 error |
| `ask QUESTION` | Ask with inline buttons, wait for reply | `--options "Yes,No"`, `--timeout SECS`, `--to TARGET`, `--bot NAME` | 0 answered, 2 timeout, 1 error |
| `read` | Print new incoming messages since last read | `--limit N`, `--bot NAME`, `--all` | 0 success, 1 error |
## Config Reference
Environment variables take precedence; anything not set in the environment falls back to `~/.config/telegram/config` (created with mode 600):
```
TELEGRAM_BOT_TOKEN=123:ABC... # default bot token
TELEGRAM_CHAT_ID=987654321 # default chat/target
BOT_ALERTS_TOKEN=456:DEF... # named bot: --bot alerts (add via: setup --bot alerts)
TARGET_FAMILY=-100987... # named target: --to family (any chat/group/channel id)
```
- `TELEGRAM_BOT_TOKEN` / `TELEGRAM_CHAT_ID` — default bot token and default send target.
- `BOT_<NAME>_TOKEN` — a named bot's token, selected with `--bot <name>` (uppercased key, e.g. `--bot alerts``BOT_ALERTS_TOKEN`).
- `TARGET_<NAME>=<chat_id>` — a named send target, selected with `--to <name>` (uppercased key, e.g. `--to family``TARGET_FAMILY`). A numeric `--to` value is used directly as a chat ID without a lookup.
- `TELEGRAM_CONFIG_DIR` — overrides the config directory (default `~/.config/telegram`).
## Claude Code hooks (settings.json)
Ping your phone when Claude needs input, and when it finishes:
```json
{
"hooks": {
"Notification": [{"hooks": [{"type": "command",
"command": "~/.claude/skills/telegram/scripts/telegram.sh send \"🔔 Claude needs input in $(basename \\\"$PWD\\\")\""}]}],
"Stop": [{"hooks": [{"type": "command",
"command": "~/.claude/skills/telegram/scripts/telegram.sh send \"✅ Claude finished in $(basename \\\"$PWD\\\")\" --silent"}]}]
}
}
```
Approval gate in any script/automation:
```bash
if [ "$(scripts/telegram.sh ask 'Deploy to prod?' --options 'Yes,No')" = "Yes" ]; then
./deploy.sh
fi
```
## Security Notes
- The bot token grants full control of the bot — anyone with it can send/receive as your bot. Treat it like a password.
- `~/.config/telegram/config` is created with mode 600 (owner read/write only).
- Replies and answers to `ask` are only honored from configured chat IDs — messages from strangers who find a public bot are ignored.
- By default, bots in group chats only see messages that mention them or are replies to them. To read all group messages, either make the bot an admin or disable privacy mode for it via @BotFather (`/setprivacy`).
## License
Apache 2.0
@@ -0,0 +1,95 @@
---
name: telegram-bot-messaging
description: "Send Telegram messages, files, and alerts via bot API; ask questions with inline buttons and wait for the answer. Supports multiple bots, named chat targets, and CI/cron/hook notifications."
category: productivity
risk: critical
source: https://github.com/sanjay3290/ai-skills/tree/main/skills/telegram
source_repo: sanjay3290/ai-skills
source_type: community
date_added: "2026-07-09"
author: sanjay3290
tags: [telegram, notifications, bots, approvals]
tools: [claude, cursor, gemini]
license: "Apache-2.0"
license_source: "https://github.com/sanjay3290/ai-skills/blob/main/LICENSE"
---
# Telegram
## When to Use
- Use when you need to send a Telegram message, file, or alert from a workflow, hook, cron job, or CI pipeline
- Use when a long-running task should notify you or ask for approval on your phone (inline-button questions that wait for the answer)
- Use when wiring "notify me when done" or "ask me before proceeding" behavior into automated sessions
Send updates, alerts, and files to Telegram; read replies; run ask-and-wait
approval flows. Pure bash + curl + jq — no install beyond a bot token.
First run: `scripts/telegram.sh setup` (guided BotFather walkthrough).
## Safety Gate
Before setup, sending a message or file, reading replies, or enabling a hook, obtain the
user's explicit approval for the target chat, bot account, and exact content or file. Never
send workspace, customer, credential, or secret data automatically. Treat a token as a secret:
do not echo it, commit it, or place it in shell history.
## Commands
```bash
scripts/telegram.sh send "Deploy finished ✅" # basic alert
scripts/telegram.sh send "low priority" --silent # no notification sound
scripts/telegram.sh send "*bold* alert" --format md # MarkdownV2 (falls back to plain)
scripts/telegram.sh send "hi" --to alerts --bot work # named target + named bot
scripts/telegram.sh file report.pdf "Q3 report" # document (photos auto-detected)
scripts/telegram.sh read # new incoming messages since last read
ANSWER=$(scripts/telegram.sh ask "Deploy to prod?" --options "Yes,No" --timeout 300)
# exit 0 = answered (stdout = answer), 2 = timeout
```
## Config
Env vars win, then `~/.config/telegram/config` (mode 600):
```
TELEGRAM_BOT_TOKEN=123:ABC... # default bot
TELEGRAM_CHAT_ID=987654321 # default target
BOT_ALERTS_TOKEN=456:DEF... # --bot alerts (add via: setup --bot alerts)
TARGET_FAMILY=-100987... # --to family (any chat/group/channel id)
```
Replies and answers are only accepted from configured chat IDs.
## Claude Code hooks (settings.json)
Ping your phone when Claude needs input, and when it finishes:
```json
{
"hooks": {
"Notification": [{"hooks": [{"type": "command",
"command": "~/.claude/skills/telegram/scripts/telegram.sh send \"🔔 Claude needs input in $(basename \\\"$PWD\\\")\""}]}],
"Stop": [{"hooks": [{"type": "command",
"command": "~/.claude/skills/telegram/scripts/telegram.sh send \"✅ Claude finished in $(basename \\\"$PWD\\\")\" --silent"}]}]
}
}
```
Approval gate in any script/automation:
```bash
if [ "$(scripts/telegram.sh ask 'Deploy to prod?' --options 'Yes,No')" = "Yes" ]; then
./deploy.sh
fi
```
## Limitations
- Telegram is a third-party service: message and file contents leave the local machine and may
be retained under Telegram's policies.
- This skill cannot verify that a chat ID belongs to the intended recipient; confirm the target
before every new destination or automation.
- Bot tokens grant control of the bot. Store them only in a protected local secret store or
mode-600 configuration file, and rotate a token if exposure is suspected.
- Do not use the examples to create unattended notifications or approval flows without the
user's explicit, current authorization.
@@ -0,0 +1,379 @@
#!/usr/bin/env bash
# telegram.sh — send/receive Telegram messages via the Bot API.
# Deps: bash, curl, jq. Config: env vars or ~/.config/telegram/config.
set -euo pipefail
API_BASE="https://api.telegram.org"
CONFIG_DIR="${TELEGRAM_CONFIG_DIR:-$HOME/.config/telegram}"
CONFIG_FILE="$CONFIG_DIR/config"
usage() {
cat >&2 <<'EOF'
Usage: telegram.sh <command> [args]
Commands:
setup [--bot NAME]
Guided bot registration (BotFather walkthrough + chat-ID discovery)
send MESSAGE [--to TARGET] [--bot NAME] [--silent] [--format md|html]
Send a text message (auto-splits over 4096 chars)
file PATH [CAPTION] [--to TARGET] [--bot NAME] [--silent]
Send a document (photos for png/jpg/jpeg/gif/webp)
ask QUESTION [--options "Yes,No"] [--timeout SECS] [--to TARGET] [--bot NAME]
Ask with inline buttons, wait for tap or text reply; prints answer.
Exit 0 = answered, 2 = timeout
read [--limit N] [--bot NAME] [--all]
Print new incoming messages since last read
Config: TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID env vars, or ~/.config/telegram/config
Named bots: BOT_<NAME>_TOKEN Named targets: TARGET_<NAME>=<chat_id>
EOF
exit 1
}
die() { printf 'telegram.sh: %s\n' "$*" >&2; exit 1; }
check_deps() {
command -v curl >/dev/null 2>&1 || die "curl is required but not found"
command -v jq >/dev/null 2>&1 || die "jq is required but not found (brew install jq / apt install jq)"
}
# Env vars win; config file fills in whatever the environment didn't set.
load_config() {
[ -f "$CONFIG_FILE" ] || return 0
local key val
while IFS='=' read -r key val; do
case "$key" in ''|\#*) continue ;; esac
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
if [ -z "${!key:-}" ]; then export "$key=$val"; fi
done < "$CONFIG_FILE"
}
upper_key() { printf '%s' "$1" | tr '[:lower:]-' '[:upper:]_'; }
resolve_bot() {
local name="${1:-}"
if [ -z "$name" ]; then
BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
BOT_KEY="default"
[ -n "$BOT_TOKEN" ] || die "no bot token — run 'telegram.sh setup' or set TELEGRAM_BOT_TOKEN"
else
local var
var="BOT_$(upper_key "$name")_TOKEN"
BOT_TOKEN="${!var:-}"
BOT_KEY="$name"
[ -n "$BOT_TOKEN" ] || die "no token for bot '$name' — run 'telegram.sh setup --bot $name' or set $var"
fi
}
resolve_target() {
local t="${1:-}"
if [ -z "$t" ]; then
CHAT_ID="${TELEGRAM_CHAT_ID:-}"
[ -n "$CHAT_ID" ] || die "no default chat — run 'telegram.sh setup' or set TELEGRAM_CHAT_ID"
elif [[ "$t" =~ ^-?[0-9]+$ ]]; then
CHAT_ID="$t"
else
local var
var="TARGET_$(upper_key "$t")"
CHAT_ID="${!var:-}"
[ -n "$CHAT_ID" ] || die "unknown target '$t' — add $var=<chat_id> to $CONFIG_FILE"
fi
}
# api METHOD [curl args...] — prints the JSON response, dies if .ok != true
api() {
local method="$1" resp
shift
resp=$(curl -sS --max-time "${TELEGRAM_CURL_TIMEOUT:-35}" \
"$API_BASE/bot$BOT_TOKEN/$method" "$@") || die "network error calling $method"
[ "$(jq -r '.ok' <<<"$resp")" = "true" ] \
|| die "$method failed: $(jq -r '.description // "unknown error"' <<<"$resp")"
printf '%s' "$resp"
}
cmd_send() {
local msg="" to="" bot="" silent="false" format=""
while [ $# -gt 0 ]; do
case "$1" in
--to) to="$2"; shift 2 ;;
--bot) bot="$2"; shift 2 ;;
--silent) silent="true"; shift ;;
--format) format="$2"; shift 2 ;;
-*) die "unknown flag for send: $1" ;;
*) if [ -z "$msg" ]; then msg="$1"; else die "unexpected argument: $1"; fi; shift ;;
esac
done
[ -n "$msg" ] || die "send needs a message (telegram.sh help)"
resolve_bot "$bot"
resolve_target "$to"
local parse_mode=""
case "$format" in
'') ;;
md) parse_mode="MarkdownV2" ;;
html) parse_mode="HTML" ;;
*) die "--format must be md or html" ;;
esac
local chunk
while [ -n "$msg" ]; do
chunk="${msg:0:4096}"
msg="${msg:4096}"
send_chunk "$chunk" "$parse_mode" "$silent"
done
}
# send_chunk TEXT PARSE_MODE SILENT — one sendMessage; formatted sends fall
# back to plain text if Telegram rejects the markup, so alerts never get lost.
send_chunk() {
local text="$1" parse_mode="$2" silent="$3" resp
if [ -n "$parse_mode" ]; then
resp=$(curl -sS --max-time "${TELEGRAM_CURL_TIMEOUT:-35}" \
"$API_BASE/bot$BOT_TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID" --data-urlencode "text=$text" \
-d "disable_notification=$silent" -d "parse_mode=$parse_mode") \
|| die "network error calling sendMessage"
if [ "$(jq -r '.ok' <<<"$resp")" = "true" ]; then return 0; fi
fi
api sendMessage -d "chat_id=$CHAT_ID" --data-urlencode "text=$text" \
-d "disable_notification=$silent" >/dev/null
}
cmd_file() {
local path="" caption="" to="" bot="" silent="false"
while [ $# -gt 0 ]; do
case "$1" in
--to) to="$2"; shift 2 ;;
--bot) bot="$2"; shift 2 ;;
--silent) silent="true"; shift ;;
-*) die "unknown flag for file: $1" ;;
*)
if [ -z "$path" ]; then path="$1"
elif [ -z "$caption" ]; then caption="$1"
else die "unexpected argument: $1"; fi
shift ;;
esac
done
[ -n "$path" ] || die "file needs a path (telegram.sh help)"
[ -f "$path" ] || die "file not found: $path"
resolve_bot "$bot"
resolve_target "$to"
local ext method="sendDocument" field="document"
ext=$(printf '%s' "${path##*.}" | tr '[:upper:]' '[:lower:]')
case "$ext" in
png|jpg|jpeg|gif|webp) method="sendPhoto" field="photo" ;;
esac
api "$method" -F "chat_id=$CHAT_ID" -F "$field=@$path" \
-F "caption=$caption" -F "disable_notification=$silent" >/dev/null
}
offset_file() { printf '%s/offset.%s' "$CONFIG_DIR" "$BOT_KEY"; }
get_offset() { cat "$(offset_file)" 2>/dev/null || printf '0'; }
save_offset() {
( umask 077; mkdir -p "$CONFIG_DIR"; printf '%s' "$1" > "$(offset_file)" )
}
# Chat IDs we accept incoming messages from: the default chat plus every
# TARGET_* value in the config file and the environment. Strangers who
# message a public bot never match.
allowed_chats() {
{
printf '%s\n' "${TELEGRAM_CHAT_ID:-}"
if [ -f "$CONFIG_FILE" ]; then
grep -E '^TARGET_[A-Za-z0-9_]+=' "$CONFIG_FILE" | cut -d= -f2 || true
fi
env | grep -E '^TARGET_[A-Za-z0-9_]+=' | cut -d= -f2 || true
} | grep -E '^-?[0-9]+$' | sort -u || true
}
cmd_read() {
local limit=20 bot="" all="false"
while [ $# -gt 0 ]; do
case "$1" in
--limit) limit="$2"; shift 2 ;;
--bot) bot="$2"; shift 2 ;;
--all) all="true"; shift ;;
*) die "unknown flag for read: $1" ;;
esac
done
[[ "$limit" =~ ^[0-9]+$ ]] || die "--limit must be a whole number"
resolve_bot "$bot"
local offset=0 resp
if [ "$all" != "true" ]; then offset=$(get_offset); fi
resp=$(api getUpdates -d "offset=$offset" -d "limit=$limit")
jq -r --arg allowed "$(allowed_chats)" '
($allowed | split("\n")) as $ok
| .result[]
| select(.message.text != null)
| select((.message.chat.id | tostring) as $c | $ok | index($c) != null)
| "[\(.message.chat.id)] \(.message.from.first_name // "?"): \(.message.text)"
' <<<"$resp"
local last
last=$(jq -r '.result | if length > 0 then (.[-1].update_id + 1 | tostring) else "" end' <<<"$resp")
if [ -n "$last" ] && [ "$all" != "true" ]; then
save_offset "$last"
fi
}
cmd_ask() {
local question="" options="Yes,No" timeout=300 to="" bot=""
while [ $# -gt 0 ]; do
case "$1" in
--options) options="$2"; shift 2 ;;
--timeout) timeout="$2"; shift 2 ;;
--to) to="$2"; shift 2 ;;
--bot) bot="$2"; shift 2 ;;
-*) die "unknown flag for ask: $1" ;;
*) if [ -z "$question" ]; then question="$1"; else die "unexpected argument: $1"; fi; shift ;;
esac
done
[ -n "$question" ] || die "ask needs a question (telegram.sh help)"
[[ "$timeout" =~ ^[0-9]+$ ]] || die "--timeout must be a whole number of seconds"
resolve_bot "$bot"
resolve_target "$to"
# Flush pending updates so stale messages can't answer the question.
local offset resp last
offset=$(get_offset)
resp=$(api getUpdates -d "offset=$offset" -d "timeout=0" -d "limit=100")
last=$(jq -r '.result | if length > 0 then (.[-1].update_id + 1 | tostring) else "" end' <<<"$resp")
if [ -n "$last" ]; then offset="$last"; save_offset "$offset"; fi
local keyboard msg_id
keyboard=$(jq -cn --arg opts "$options" \
'{inline_keyboard: [[$opts | split(",")[] | {text: ., callback_data: .}]]}')
resp=$(api sendMessage -d "chat_id=$CHAT_ID" \
--data-urlencode "text=$question" --data-urlencode "reply_markup=$keyboard")
msg_id=$(jq -r '.result.message_id' <<<"$resp")
local deadline now remain answer cb
deadline=$(( $(date +%s) + timeout ))
while :; do
now=$(date +%s)
remain=$(( deadline - now ))
if [ "$remain" -le 0 ]; then break; fi
if [ "$remain" -gt 25 ]; then remain=25; fi
resp=$(api getUpdates -d "offset=$offset" -d "timeout=$remain")
last=$(jq -r '.result | if length > 0 then (.[-1].update_id + 1 | tostring) else "" end' <<<"$resp")
if [ -n "$last" ]; then offset="$last"; save_offset "$offset"; fi
# Button tap on our question message?
cb=$(jq -r --argjson mid "$msg_id" --argjson chat "$CHAT_ID" '
[.result[]
| select(.callback_query.message.message_id == $mid)
| select(.callback_query.message.chat.id == $chat)
| .callback_query]
| if length > 0 then "\(.[0].data)\t\(.[0].id)" else "" end' <<<"$resp")
if [ -n "$cb" ]; then
answer="${cb%%$'\t'*}"
api answerCallbackQuery -d "callback_query_id=${cb##*$'\t'}" >/dev/null
api editMessageText -d "chat_id=$CHAT_ID" -d "message_id=$msg_id" \
--data-urlencode "text=$question
$answer" >/dev/null
printf '%s\n' "$answer"
return 0
fi
# Free-text reply from the asked chat?
answer=$(jq -r --argjson chat "$CHAT_ID" '
[.result[]
| select(.message.chat.id == $chat)
| select(.message.text != null)
| .message.text]
| if length > 0 then .[0] else "" end' <<<"$resp")
if [ -n "$answer" ]; then
api editMessageText -d "chat_id=$CHAT_ID" -d "message_id=$msg_id" \
--data-urlencode "text=$question
💬 $answer" >/dev/null
printf '%s\n' "$answer"
return 0
fi
done
api editMessageText -d "chat_id=$CHAT_ID" -d "message_id=$msg_id" \
--data-urlencode "text=$question
⏰ timed out" >/dev/null || true
return 2
}
set_config_key() {
local key="$1" val="$2" tmp
( umask 077; mkdir -p "$CONFIG_DIR"; touch "$CONFIG_FILE" )
tmp=$(mktemp "$CONFIG_DIR/.config.XXXXXX")
grep -v "^$key=" "$CONFIG_FILE" > "$tmp" || true
printf '%s=%s\n' "$key" "$val" >> "$tmp"
mv "$tmp" "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
}
cmd_setup() {
local bot=""
while [ $# -gt 0 ]; do
case "$1" in
--bot) bot="$2"; shift 2 ;;
*) die "unknown flag for setup: $1" ;;
esac
done
printf 'Telegram bot setup%s\n\n' "${bot:+ (named bot: $bot)}" >&2
printf ' 1. Open https://t.me/BotFather in Telegram\n' >&2
printf ' 2. Send /newbot and follow the prompts (display name, then a username ending in "bot")\n' >&2
printf ' 3. BotFather replies with an HTTP API token\n\n' >&2
printf 'Paste the token here: ' >&2
local token
read -r token
[ -n "$token" ] || die "no token entered"
BOT_TOKEN="$token"
local username
username=$(api getMe | jq -r '.result.username')
printf 'Token valid — bot is @%s\n\n' "$username" >&2
printf 'Now send any message to https://t.me/%s then press Enter... ' "$username" >&2
read -r _ || true
local chat_id
chat_id=$(api getUpdates | jq -r \
'[.result[] | .message.chat.id | select(. != null)] | if length > 0 then (.[-1] | tostring) else "" end')
[ -n "$chat_id" ] || die "no message found — send a message to @$username and rerun setup"
if [ -z "$bot" ]; then
set_config_key TELEGRAM_BOT_TOKEN "$token"
set_config_key TELEGRAM_CHAT_ID "$chat_id"
else
set_config_key "BOT_$(upper_key "$bot")_TOKEN" "$token"
if ! grep -q '^TELEGRAM_CHAT_ID=' "$CONFIG_FILE" 2>/dev/null; then
set_config_key TELEGRAM_CHAT_ID "$chat_id"
fi
fi
CHAT_ID="$chat_id"
api sendMessage -d "chat_id=$chat_id" \
--data-urlencode "text=✅ telegram.sh setup complete for @$username" >/dev/null
printf 'Config written to %s (chat %s) — confirmation sent.\n' "$CONFIG_FILE" "$chat_id" >&2
}
main() {
check_deps
load_config
[ $# -ge 1 ] || usage
local cmd="$1"
shift
case "$cmd" in
setup) cmd_setup "$@" ;;
send) cmd_send "$@" ;;
file) cmd_file "$@" ;;
ask) cmd_ask "$@" ;;
read) cmd_read "$@" ;;
-h|--help|help) usage ;;
*) die "unknown command: $cmd (telegram.sh help)" ;;
esac
}
main "$@"