📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-18 00:02:59 +00:00
parent 82f7c6e56a
commit 47ce7f78dc
1446 changed files with 141041 additions and 6442 deletions
@@ -33,7 +33,7 @@ macOS ships bash and curl out of the box; only `jq` typically needs installing.
### 2. Run setup
```bash
scripts/telegram.sh 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.
@@ -41,7 +41,7 @@ This walks you through pasting the token, validates it via `getMe`, and asks you
### 3. Add more bots (optional)
```bash
scripts/telegram.sh setup --bot alerts
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.
@@ -52,7 +52,7 @@ 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
3. Run `bash 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
@@ -61,43 +61,43 @@ To send to a group or channel instead of your personal chat:
```bash
# Basic alert
scripts/telegram.sh send "Deploy finished ✅"
bash scripts/telegram.sh send "Deploy finished ✅"
# No notification sound
scripts/telegram.sh send "low priority update" --silent
bash 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
bash scripts/telegram.sh send "*bold* alert" --format md
# HTML formatting
scripts/telegram.sh send "<b>bold</b> alert" --format html
bash scripts/telegram.sh send "<b>bold</b> alert" --format html
# Named target and named bot
scripts/telegram.sh send "hi" --to alerts --bot work
bash scripts/telegram.sh send "hi" --to alerts --bot work
```
### Send Files
```bash
# Send a document
scripts/telegram.sh file report.pdf "Q3 report"
bash scripts/telegram.sh file report.pdf "Q3 report"
# Images are auto-detected and sent as photos
scripts/telegram.sh file screenshot.png "Build output"
bash scripts/telegram.sh file screenshot.png "Build output"
# To a named target, silently
scripts/telegram.sh file backup.zip --to alerts --silent
bash 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)
ANSWER=$(bash 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"
bash 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.
@@ -106,13 +106,13 @@ Exit code `0` means answered (the answer is printed to stdout); exit code `2` me
```bash
# New messages since the last read (advances the offset)
scripts/telegram.sh read
bash scripts/telegram.sh read
# Limit the number of messages
scripts/telegram.sh read --limit 5
bash scripts/telegram.sh read --limit 5
# Ignore the saved offset and show everything available
scripts/telegram.sh read --all
bash 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.
@@ -136,11 +136,15 @@ 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_APPROVER_IDS=123456789 # default group approver user IDs (comma-separated)
APPROVERS_FAMILY=123456789,987654321 # approvers for --to family (overrides default)
```
- `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_APPROVER_IDS` — Telegram user IDs allowed to answer `ask` in a group target.
- `APPROVERS_<NAME>` — target-specific group approvers (for example, `APPROVERS_FAMILY`); overrides the global allowlist for that named target.
- `TELEGRAM_CONFIG_DIR` — overrides the config directory (default `~/.config/telegram`).
## Claude Code hooks (settings.json)
@@ -151,9 +155,9 @@ Ping your phone when Claude needs input, and when it finishes:
{
"hooks": {
"Notification": [{"hooks": [{"type": "command",
"command": "~/.claude/skills/telegram/scripts/telegram.sh send \"🔔 Claude needs input in $(basename \\\"$PWD\\\")\""}]}],
"command": "bash ~/.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"}]}]
"command": "bash ~/.claude/skills/telegram/scripts/telegram.sh send \"✅ Claude finished in $(basename \\\"$PWD\\\")\" --silent"}]}]
}
}
```
@@ -161,7 +165,7 @@ Ping your phone when Claude needs input, and when it finishes:
Approval gate in any script/automation:
```bash
if [ "$(scripts/telegram.sh ask 'Deploy to prod?' --options 'Yes,No')" = "Yes" ]; then
if [ "$(bash scripts/telegram.sh ask 'Deploy to prod?' --options 'Yes,No')" = "Yes" ]; then
./deploy.sh
fi
```
@@ -169,8 +173,11 @@ 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.
- Token-bearing API URLs are passed to curl through stdin, not exposed in curl process arguments.
- `~/.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.
- Private-chat answers are accepted only when the sender user ID equals the chat ID. Group
targets require an explicit `TELEGRAM_APPROVER_IDS` or target-specific `APPROVERS_<NAME>`
allowlist, and `ask` accepts button taps and text only from those user IDs.
- 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
@@ -25,7 +25,7 @@ license_source: "https://github.com/sanjay3290/ai-skills/blob/main/LICENSE"
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).
First run: `bash scripts/telegram.sh setup` (guided BotFather walkthrough).
## Safety Gate
@@ -37,13 +37,13 @@ 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)
bash scripts/telegram.sh send "Deploy finished ✅" # basic alert
bash scripts/telegram.sh send "low priority" --silent # no notification sound
bash scripts/telegram.sh send "*bold* alert" --format md # MarkdownV2 (falls back to plain)
bash scripts/telegram.sh send "hi" --to alerts --bot work # named target + named bot
bash scripts/telegram.sh file report.pdf "Q3 report" # document (photos auto-detected)
bash scripts/telegram.sh read # new incoming messages since last read
ANSWER=$(bash scripts/telegram.sh ask "Deploy to prod?" --options "Yes,No" --timeout 300)
# exit 0 = answered (stdout = answer), 2 = timeout
```
@@ -56,9 +56,14 @@ 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)
TELEGRAM_APPROVER_IDS=123456789 # default group approver user IDs (comma-separated)
APPROVERS_FAMILY=123456789,987654321 # approvers for --to family (overrides default)
```
Replies and answers are only accepted from configured chat IDs.
Replies and answers are only accepted from configured chat IDs. Private chats preserve the
direct-chat behavior (the sender user ID must equal the chat ID). Because a group chat ID is
shared by every member, `ask` fails closed for groups unless `TELEGRAM_APPROVER_IDS` or the
target-specific `APPROVERS_<NAME>` explicitly lists the Telegram user IDs allowed to answer.
## Claude Code hooks (settings.json)
@@ -68,9 +73,9 @@ Ping your phone when Claude needs input, and when it finishes:
{
"hooks": {
"Notification": [{"hooks": [{"type": "command",
"command": "~/.claude/skills/telegram/scripts/telegram.sh send \"🔔 Claude needs input in $(basename \\\"$PWD\\\")\""}]}],
"command": "bash ~/.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"}]}]
"command": "bash ~/.claude/skills/telegram/scripts/telegram.sh send \"✅ Claude finished in $(basename \\\"$PWD\\\")\" --silent"}]}]
}
}
```
@@ -78,7 +83,7 @@ Ping your phone when Claude needs input, and when it finishes:
Approval gate in any script/automation:
```bash
if [ "$(scripts/telegram.sh ask 'Deploy to prod?' --options 'Yes,No')" = "Yes" ]; then
if [ "$(bash scripts/telegram.sh ask 'Deploy to prod?' --options 'Yes,No')" = "Yes" ]; then
./deploy.sh
fi
```
@@ -90,6 +95,7 @@ fi
- 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.
mode-600 configuration file. The script supplies token-bearing API URLs to curl through
stdin rather than process arguments; 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.
+50 -9
View File
@@ -26,6 +26,7 @@ Commands:
Config: TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID env vars, or ~/.config/telegram/config
Named bots: BOT_<NAME>_TOKEN Named targets: TARGET_<NAME>=<chat_id>
Group approvals: TELEGRAM_APPROVER_IDS or APPROVERS_<TARGET>=<user_id,...>
EOF
exit 1
}
@@ -63,29 +64,65 @@ resolve_bot() {
BOT_KEY="$name"
[ -n "$BOT_TOKEN" ] || die "no token for bot '$name' — run 'telegram.sh setup --bot $name' or set $var"
fi
[[ "$BOT_TOKEN" =~ ^[0-9]+:[A-Za-z0-9_-]+$ ]] \
|| die "invalid bot token format"
}
resolve_target() {
local t="${1:-}"
APPROVER_IDS_RAW="${TELEGRAM_APPROVER_IDS:-}"
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
local var approver_var
var="TARGET_$(upper_key "$t")"
CHAT_ID="${!var:-}"
[ -n "$CHAT_ID" ] || die "unknown target '$t' — add $var=<chat_id> to $CONFIG_FILE"
approver_var="APPROVERS_$(upper_key "$t")"
APPROVER_IDS_RAW="${!approver_var:-${TELEGRAM_APPROVER_IDS:-}}"
fi
}
# Private chat IDs identify the sender, so existing private-chat approval flows
# need no extra configuration. Group chat IDs are shared: fail closed unless an
# explicit sender-user allowlist is configured for that target (or globally).
resolve_approvers() {
if [[ "$CHAT_ID" != -* ]]; then
APPROVER_IDS="$CHAT_ID"
return 0
fi
[ -n "$APPROVER_IDS_RAW" ] \
|| die "group ask requires TELEGRAM_APPROVER_IDS or APPROVERS_<TARGET>"
local raw id normalized=""
raw="${APPROVER_IDS_RAW//,/ }"
for id in $raw; do
[[ "$id" =~ ^[0-9]+$ ]] \
|| die "approver IDs must be comma-separated Telegram user IDs"
normalized="${normalized}${normalized:+$'\n'}${id}"
done
[ -n "$normalized" ] || die "group ask requires at least one approver user ID"
APPROVER_IDS="$normalized"
}
# Keep the token-bearing URL out of curl's argv. The URL is supplied through a
# one-shot config on stdin; all other request arguments remain ordinary argv.
curl_telegram() {
local method="$1"
shift
printf 'url = "%s/bot%s/%s"\n' "$API_BASE" "$BOT_TOKEN" "$method" \
| curl -sS --max-time "${TELEGRAM_CURL_TIMEOUT:-35}" --config - "$@"
}
# 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"
resp=$(curl_telegram "$method" "$@") || die "network error calling $method"
[ "$(jq -r '.ok' <<<"$resp")" = "true" ] \
|| die "$method failed: $(jq -r '.description // "unknown error"' <<<"$resp")"
printf '%s' "$resp"
@@ -128,8 +165,7 @@ cmd_send() {
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" \
resp=$(curl_telegram sendMessage \
-d "chat_id=$CHAT_ID" --data-urlencode "text=$text" \
-d "disable_notification=$silent" -d "parse_mode=$parse_mode") \
|| die "network error calling sendMessage"
@@ -237,6 +273,7 @@ cmd_ask() {
[[ "$timeout" =~ ^[0-9]+$ ]] || die "--timeout must be a whole number of seconds"
resolve_bot "$bot"
resolve_target "$to"
resolve_approvers
# Flush pending updates so stale messages can't answer the question.
local offset resp last
@@ -265,10 +302,12 @@ cmd_ask() {
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[]
cb=$(jq -r --argjson mid "$msg_id" --argjson chat "$CHAT_ID" --arg allowed "$APPROVER_IDS" '
($allowed | split("\n")) as $ok
| [.result[]
| select(.callback_query.message.message_id == $mid)
| select(.callback_query.message.chat.id == $chat)
| select((.callback_query.from.id | tostring) as $u | $ok | index($u) != null)
| .callback_query]
| if length > 0 then "\(.[0].data)\t\(.[0].id)" else "" end' <<<"$resp")
if [ -n "$cb" ]; then
@@ -282,9 +321,11 @@ cmd_ask() {
fi
# Free-text reply from the asked chat?
answer=$(jq -r --argjson chat "$CHAT_ID" '
[.result[]
answer=$(jq -r --argjson chat "$CHAT_ID" --arg allowed "$APPROVER_IDS" '
($allowed | split("\n")) as $ok
| [.result[]
| select(.message.chat.id == $chat)
| select((.message.from.id | tostring) as $u | $ok | index($u) != null)
| select(.message.text != null)
| .message.text]
| if length > 0 then .[0] else "" end' <<<"$resp")