Skill: itstauq/telegram-auto-topic (version 0.1.8)

--- name: telegram-auto-topic description: > Add `/topic` to the start of any message in a Telegram forum group to auto-create a new topic from it. A title is generated automatically from the message content. Github: https://github.com/itstauq/telegram-auto-topic metadata: openclaw: requires: config: - ~/.openclaw/openclaw.json env: - OPENCLAW_CONFIG bins: - curl - jq --- # Telegram Auto-Topic Add `/topic` to the start of any message in a Telegram forum group → a new topic is created from it. The title is figured out from your message automatically — no need to think of one yourself. ### Example **1.** You send a message starting with `/topic`: > /topic @your_bot I need to look into renewing my passport before March **2.** A new forum topic **"Passport Renewal Before March"** is created with your message quoted inside it. You get a reply linking directly to the new topic. ## Prerequisites - The group must be configured in OpenClaw (`channels.telegram.groups.<CHAT_ID>`) — this is how OpenClaw knows to process messages from it. - The group must have **forum/topics** enabled. - Your bot must be an admin in the group with **Manage Topics** permission. ## Handling /topic When a message starts with `/topic`: 1. Generate a concise 3-7 word title summarising the message. 2. Run the script — replace placeholders with actual values from the message context: ``` scripts/telegram-auto-topic.sh <chat_id> <message_id> "<sender name>" "<title>" "<text after /topic>" ``` Pass an empty string for the text arg if there's no text (e.g. media-only). Use the path relative to this skill's directory. 3. The script returns JSON with `topic_id`, `title`, and `link`. 4. Reply to the original message with: `Topic created → [<title>](<link>)` 5. Then send a response to the actual message content in the NEW topic (use message tool with `threadId` from the returned `topic_id`). Respond naturally as you would to any message. 6. After both replies are sent, respond with NO_REPLY. ## How It Works 1. You send a message starting with `/topic` 2. A new forum topic is created — titled from your message automatically 3. Your message is quoted in the new topic with your name 4. You get a reply with a clickable link to the new topic 5. The bot responds to your message in the new topic Works with media too — photos, videos, or documents with `/topic` in the caption get forwarded into the new topic. ## Script Reference ```bash scripts/telegram-auto-topic.sh <chat_id> <message_id> <sender> [title] [text] ``` | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `chat_id` | arg | yes | Supergroup chat ID (negative number) | | `message_id` | arg | yes | Original message to quote | | `sender` | arg | yes | Display name of original sender | | `title` | arg | no | Topic title. Falls back to first ~50 chars of text if omitted | | `text` | arg | no | Message body after `/topic`. If empty, forwards as media | Returns JSON: `{"topic_id": 123, "title": "Used title", "link": "https://t.me/c/..."}` ## Optional configuration **Skip the @bot mention** — by default, the bot only responds when mentioned. To use `/topic` without mentioning the bot: ```json "channels.telegram.groups.<CHAT_ID>": { "requireMention": false } ``` **Telegram autocomplete** — to get `/topic` in Telegram's command menu, add under `channels.telegram`: ```json { "customCommands": [ { "command": "topic", "description": "Create a new forum topic from a message" } ] } ``` ## Limitations - **Attribution:** Quoted messages appear as sent by the bot (Telegram API limitation). Sender name is included as attribution text below the quote. - **Media:** Forwarded media shows a "Forwarded from" header — best available but not native. - **Forum groups only:** Won't work in regular groups or DMs. - **Permissions:** Bot needs admin with Manage Topics. - **Title length:** Telegram caps topic names at 128 characters.

path: scripts/telegram-auto-topic.sh
content: #!/bin/bash
# telegram-auto-topic.sh — Create a Telegram forum topic from a /topic command
# and post the original message as a quote inside it.
#
# Usage:
#   ./telegram-auto-topic.sh <chat_id> <message_id> <sender> [title] [text]
#
# Args:
#   chat_id   (required) — target supergroup chat ID
#   message_id(required) — original message to quote
#   sender    (required) — display name of the original sender
#   title     (optional) — topic title. If empty, auto-generates from first
#                           ~50 chars of text at a word boundary.
#   text      (optional) — message body (everything after "/topic").
#                           If empty, the message is forwarded as media.
#
# Output: JSON — {"topic_id": <id>, "title": "<title>", "link": "<url>"}
# Exit codes: 0 = success, 1 = error (details on stderr)

set -eo pipefail

# ── dependency check ────────────────────────────────────────────────
for cmd in curl jq; do
  if ! command -v "$cmd" &>/dev/null; then
    echo "ERROR: '$cmd' is required but not found in PATH" >&2
    exit 1
  fi
done

# ── config ──────────────────────────────────────────────────────────
CONFIG_FILE="${OPENCLAW_CONFIG:-$HOME/.openclaw/openclaw.json}"
if [ ! -f "$CONFIG_FILE" ]; then
  echo "ERROR: OpenClaw config not found at $CONFIG_FILE" >&2
  exit 1
fi

BOT_TOKEN=$(jq -r '.channels.telegram.botToken // empty' "$CONFIG_FILE")
if [ -z "$BOT_TOKEN" ]; then
  echo "ERROR: Bot token not found in $CONFIG_FILE" >&2
  exit 1
fi

API="https://api.telegram.org/bot${BOT_TOKEN}"

# ── arguments ───────────────────────────────────────────────────────
CHAT_ID="$1"
MESSAGE_ID="$2"
SENDER="$3"
TITLE_ARG="${4:-}"
RAW_TEXT="${5:-}"

if [ -z "$CHAT_ID" ] || [ -z "$MESSAGE_ID" ] || [ -z "$SENDER" ]; then
  echo "Usage: $0 <chat_id> <message_id> <sender> [title] [text]" >&2
  exit 1
fi

# ── validate numeric arguments ──────────────────────────────────────
if ! printf '%s' "$CHAT_ID" | grep -qE '^-?[0-9]+$'; then
  echo "ERROR: chat_id must be an integer, got: '$CHAT_ID'" >&2
  exit 1
fi
if ! printf '%s' "$MESSAGE_ID" | grep -qE '^[0-9]+$'; then
  echo "ERROR: message_id must be a positive integer, got: '$MESSAGE_ID'" >&2
  exit 1
fi

# ── strip leading/trailing whitespace from text ─────────────────────
MSG=$(printf '%s' "$RAW_TEXT" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

# ── determine title ─────────────────────────────────────────────────
if [ -n "$TITLE_ARG" ]; then
  TITLE="$TITLE_ARG"
elif [ -n "$MSG" ]; then
  # Fallback: first ~50 chars at a word boundary
  FIRST_LINE=$(printf '%s' "$MSG" | head -1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
  TITLE=$(printf '%s' "$FIRST_LINE" | cut -c1-50 | sed 's/[[:space:]][^[:space:]]*$//')
  if [ "${#FIRST_LINE}" -gt 50 ]; then
    TITLE="${TITLE}…"
  fi
else
  TITLE="New Topic"
fi

# Telegram caps topic names at 128 chars
TITLE=$(printf '%s' "$TITLE" | cut -c1-128)

# ── create forum topic ──────────────────────────────────────────────
CREATE_RESULT=$(curl -s "$API/createForumTopic" \
  -d "chat_id=${CHAT_ID}" \
  --data-urlencode "name=${TITLE}")

TOPIC_ID=$(echo "$CREATE_RESULT" | jq -r '.result.message_thread_id // empty')

if [ -z "$TOPIC_ID" ]; then
  ERR_DESC=$(echo "$CREATE_RESULT" | jq -r '.description // "unknown error"')
  echo "ERROR: Failed to create topic: $ERR_DESC" >&2
  exit 1
fi

# ── post quote into the new topic ───────────────────────────────────
if [ -n "$MSG" ]; then
  # HTML-escape for blockquote
  ESC_MSG=$(printf '%s' "$MSG" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g')
  ESC_SENDER=$(printf '%s' "$SENDER" | sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g')

  QUOTED="<blockquote>${ESC_MSG}</blockquote>
— <b>${ESC_SENDER}</b>"

  SEND_RESULT=$(curl -s "$API/sendMessage" \
    -d "chat_id=${CHAT_ID}" \
    -d "message_thread_id=${TOPIC_ID}" \
    --data-urlencode "text=${QUOTED}" \
    -d "parse_mode=HTML")

  SEND_OK=$(echo "$SEND_RESULT" | jq -r '.ok // "false"')
  if [ "$SEND_OK" != "true" ]; then
    echo "WARNING: sendMessage failed: $(echo "$SEND_RESULT" | jq -r '.description // "unknown"')" >&2
  fi
else
  # Media — forward to preserve attachments
  FWD_RESULT=$(curl -s "$API/forwardMessage" \
    -d "chat_id=${CHAT_ID}" \
    -d "from_chat_id=${CHAT_ID}" \
    -d "message_id=${MESSAGE_ID}" \
    -d "message_thread_id=${TOPIC_ID}")

  FWD_OK=$(echo "$FWD_RESULT" | jq -r '.ok // "false"')
  if [ "$FWD_OK" != "true" ]; then
    echo "WARNING: forwardMessage failed: $(echo "$FWD_RESULT" | jq -r '.description // "unknown"')" >&2
  fi
fi

# ── build topic link ────────────────────────────────────────────────
# Strip -100 prefix from chat_id for the t.me/c/ link format
STRIPPED_ID=$(printf '%s' "$CHAT_ID" | sed 's/^-100//')
LINK="https://t.me/c/${STRIPPED_ID}/${TOPIC_ID}"

# ── output (use jq for safe JSON encoding) ──────────────────────────
jq -n --argjson tid "$TOPIC_ID" --arg title "$TITLE" --arg link "$LINK" \
  '{"topic_id": $tid, "title": $title, "link": $link}'


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)