Skill: bangyizhang/tg-stickers (version 0.2.0)

--- name: tg-stickers description: "Collect and send Telegram stickers smartly. Auto-import packs, tag by emotion, select contextually, and respect frequency limits (2-5 messages)." --- # Telegram Stickers Skill Intelligently manage and send Telegram stickers with emotional awareness. ## Core Value **OpenClaw natively supports sending stickers** (`message` tool), but this skill adds: - ✅ **Collection management** - Import entire sticker packs at once - ✅ **Emotion tagging** - 100+ emoji → emotion mappings - ✅ **Smart selection** - Context-based + randomization (avoid repetition) - ✅ **Frequency control** - 2-5 messages between stickers - ✅ **Usage analytics** - Track which stickers work best ## Quick Start ### 1. Import Sticker Packs ```bash ./import-sticker-pack.sh <pack_short_name_or_id> ``` ### 2. Auto-Tag by Emotion ```bash ./auto-tag-stickers.sh ``` ### 3. Send Stickers (in agent code) ```javascript // ✅ Use OpenClaw's message tool directly message(action='sticker', target='<chat_id>', stickerId=['<file_id>']) // No bash script needed - OpenClaw handles sending natively ``` ### 4. Smart Selection ```bash ./random-sticker.sh "goodnight" # Returns random sticker tagged "goodnight" ``` ## Tools | Script | Purpose | Usage | |--------|---------|-------| | `import-sticker-pack.sh` | Bulk import Telegram sticker pack | `./import-sticker-pack.sh pa_XXX...` | | `auto-tag-stickers.sh` | Tag stickers by emoji → emotion | `./auto-tag-stickers.sh` | | `random-sticker.sh` | Select random sticker by tag | `./random-sticker.sh "happy"` | | `check-collection.sh` | View collection stats | `./check-collection.sh` | ## Agent Integration ```markdown ## Sticker Usage When to send: - Goodnight/morning greetings (always use sticker over text) - Celebrating success/milestones - Humorous moments - Emotional responses (joy, sympathy, encouragement) How to send: 1. Use random-sticker.sh to pick appropriate sticker by emotion 2. Call message(action=sticker, ...) directly 3. (Optional) Update stickers.json manually to track usage Frequency: 2-5 messages between stickers (track in agent logic) ``` ## Emotion Tags Auto-tagging maps 100+ emoji to emotions: - `happy` 😊😄🥳 - `sad` 😢😭😔 - `love` ❤️💕😍 - `laugh` 😂🤣😆 - `thinking` 🤔💭 - `goodnight` 🌙💤😴 - `goodmorning` ☀️🌅 - `warm`, `gentle`, `greeting`, ... ## File Structure ``` tg-stickers/ ├── SKILL.md # This file ├── README.md # Quick start guide ├── stickers.json # Collection + usage data ├── stickers.json.example # Empty template ├── import-sticker-pack.sh # Bulk import ├── auto-tag-stickers.sh # Emoji → emotion ├── random-sticker.sh # Context-based selection └── check-collection.sh # Stats viewer ``` ## stickers.json Structure ```json { "collected": [ { "file_id": "CAACAgEAAxUAAWmq...", "emoji": "🌙", "set_name": "pa_dKjUP9P2dt4k...", "added_at": "2026-03-06T23:31:00Z", "tags": ["goodnight", "sleep", "night", "warm", "gentle"], "used_count": 3, "last_used": "2026-03-07T00:24:00Z" } ], "usage_log": [ { "file_id": "...", "sent_at": "2026-03-07T00:24:00Z", "context": "User saying goodnight", "message_id": "2599" } ], "stats": { "total_collected": 124, "total_sent": 15, "last_sent_at": "2026-03-07T00:24:00Z", "messages_since_last_sticker": 0 }, "config": { "min_messages_between_stickers": 2, "max_messages_between_stickers": 5, "enabled": true } } ``` ## Usage Philosophy **Like a human:** - Stickers enhance emotion, don't replace words - Use sparingly but meaningfully - Goodnight/morning → always sticker preferred - Celebrations, humor, empathy → good use cases - Technical answers, data reports → skip stickers **Frequency:** - Default: 2-5 messages between stickers - Special occasions (greetings) override frequency rules - Track in `messages_since_last_sticker` ## Example: Goodnight Flow ```bash # 1. Agent detects "goodnight" intent # 2. Select random goodnight sticker FILE_ID=$(bash /path/to/random-sticker.sh "goodnight") # 3. Send via OpenClaw (from agent code) message(action=sticker, target=<chat_id>, stickerId=[$FILE_ID]) # 4. (Optional) Track usage manually jq --arg fid "$FILE_ID" \ '(.collected[] | select(.file_id == $fid) | .used_count) += 1' \ stickers.json > stickers.json.tmp && \ mv stickers.json.tmp stickers.json ``` --- **Philosophy:** Stickers should feel natural, not robotic. Collect user preferences, rotate selections, and respect conversation flow.

path: README.md
content: # tg-stickers

Smart Telegram sticker management for OpenClaw agents.

## What This Does

**OpenClaw natively sends stickers**, but this skill adds intelligence:
- 📦 **Bulk import** - Add entire sticker packs at once
- 🏷️ **Auto-tagging** - Map 100+ emoji to emotions (happy, sad, goodnight, etc.)
- 🎲 **Smart selection** - Context-based random picks (avoid repetition)
- 📊 **Analytics** - Track usage patterns

## Quick Start

```bash
# 1. Import a sticker pack
./import-sticker-pack.sh pa_YK0WQxd6HTw52j6bazKo_by_SigStick21Bot

# 2. Auto-tag all stickers
./auto-tag-stickers.sh

# 3. Select a sticker (returns file_id)
./random-sticker.sh "goodnight"

# 4. Send via OpenClaw (in agent code)
message(action=sticker, target=<chat_id>, stickerId=[<file_id>])
```

## Tools

| Script | Purpose |
|--------|---------|
| `import-sticker-pack.sh` | Import entire Telegram sticker pack |
| `auto-tag-stickers.sh` | Tag stickers by emoji → emotion mapping |
| `random-sticker.sh` | Pick random sticker by tag |
| `check-collection.sh` | View collection stats |

## Files

- `stickers.json` - Your collection + usage data
- `stickers.json.example` - Empty template
- `SKILL.md` - Full documentation

## Usage Philosophy

**Use stickers like humans do:**
- Greetings (goodnight/morning) → always prefer sticker over text
- Celebrations, humor, empathy → great use cases
- Technical answers, reports → skip stickers
- Frequency: ~1 per 2-5 messages (track yourself in agent logic)

## Integration

Read `SKILL.md` for full integration guide with OpenClaw agents.

## License

MIT


path: RELEASE_NOTES.md
content: # Release Notes

## v0.1.0 (2026-03-06)

Initial release! 🎉

### Features

- ✅ **Sticker Collection** - Collect stickers sent by users
- ✅ **Smart Sending** - Context-aware sticker selection
- ✅ **Frequency Limits** - Respect conversation flow (1 per 5-10 messages)
- ✅ **Native Telegram API** - Direct `sendSticker` API calls
- ✅ **Usage Tracking** - Monitor sticker collection and usage
- ✅ **Rule-Based Decision** - Based on OpenClaw Reactions guidelines

### Files Included

- `SKILL.md` - Complete documentation
- `README.md` - Quick start guide
- `LICENSE` - MIT License
- `stickers.json.example` - Template configuration
- `send-sticker.sh` - Sticker sending script
- `add-sticker.sh` - Collection management
- `should_send_sticker.py` - Decision logic
- `.gitignore` - Git configuration

### Requirements

- OpenClaw 2026.3.0+
- Telegram channel configured
- Python 3.6+
- `jq` (for JSON manipulation)

### Installation

```bash
cd ~/.openclaw/workspace/skills
tar -xzf tg-stickers.tar.gz
cd tg-stickers
cp stickers.json.example stickers.json
chmod +x *.sh
```

### Quick Test

```bash
# Add a test sticker
./add-sticker.sh "YOUR_FILE_ID" "😀" "TestSet" "happy"

# Check decision
python3 should_send_sticker.py "test" "Great job!"

# Send sticker
./send-sticker.sh "YOUR_FILE_ID" YOUR_CHAT_ID "Testing"
```

### Known Issues

None yet! Please report any issues on GitHub.

### Roadmap

- [ ] Auto-collect stickers from incoming messages
- [ ] Emoji-based smart selection
- [ ] Tag-based filtering
- [ ] Statistics dashboard
- [ ] Integration with OpenClaw message tool

### Credits

Created with love for the OpenClaw community. Special thanks to all contributors!

---

**Enjoy! 🎨**


path: auto-tag-stickers.sh
content: #!/bin/bash
#
# Auto-tag stickers based on emoji meaning
# Usage: ./auto-tag-stickers.sh
#

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STICKERS_JSON="$SCRIPT_DIR/stickers.json"

echo "🏷️  Auto-tagging stickers based on emoji..."

# Python script to auto-tag
python3 - <<'PYTHON'
import json
from pathlib import Path

STICKERS_JSON = Path(__file__).parent / "stickers.json"

# Emoji to tags mapping
EMOJI_TAGS = {
    "😀": ["happy", "smile", "joy"],
    "😃": ["happy", "smile", "joy"],
    "😄": ["happy", "smile", "joy"],
    "😁": ["happy", "grin", "joy"],
    "😅": ["relief", "embarrassed", "nervous"],
    "😂": ["laugh", "joy", "funny"],
    "🤣": ["laugh", "joy", "funny"],
    "😊": ["happy", "warm", "gentle"],
    "😇": ["innocent", "angelic", "pure"],
    "🙂": ["neutral", "okay", "mild"],
    "🙃": ["playful", "silly", "upside-down"],
    "😉": ["wink", "playful", "flirt"],
    "😌": ["relief", "calm", "peaceful"],
    "😍": ["love", "heart-eyes", "adoration"],
    "🥰": ["love", "warm", "affection"],
    "😘": ["kiss", "love", "affection"],
    "😗": ["kiss", "affection"],
    "😙": ["kiss", "affection"],
    "😚": ["kiss", "affection"],
    "😋": ["yummy", "delicious", "tasty"],
    "😛": ["playful", "silly", "tongue"],
    "😝": ["playful", "silly", "tongue"],
    "😜": ["playful", "wink", "tongue"],
    "🤪": ["crazy", "silly", "wild"],
    "🤨": ["suspicious", "doubtful", "raised-eyebrow"],
    "🧐": ["thinking", "curious", "monocle"],
    "🤓": ["nerd", "geek", "smart"],
    "😎": ["cool", "confident", "sunglasses"],
    "🤩": ["star-struck", "excited", "amazed"],
    "🥳": ["party", "celebration", "excited"],
    "😏": ["smirk", "confident", "sly"],
    "😒": ["bored", "annoyed", "unimpressed"],
    "😞": ["sad", "disappointed", "down"],
    "😔": ["sad", "pensive", "thoughtful"],
    "😟": ["worried", "concerned", "anxious"],
    "😕": ["confused", "uncertain", "puzzled"],
    "🙁": ["sad", "frown", "disappointed"],
    "☹️": ["sad", "frown", "disappointed"],
    "😣": ["struggle", "persevere", "difficulty"],
    "😖": ["confused", "frustrated", "mixed"],
    "😫": ["tired", "exhausted", "weary"],
    "😩": ["weary", "tired", "fed-up"],
    "🥺": ["pleading", "puppy-eyes", "begging"],
    "😢": ["sad", "cry", "tears"],
    "😭": ["cry", "sob", "very-sad"],
    "😤": ["frustrated", "annoyed", "triumph"],
    "😠": ["angry", "mad", "furious"],
    "😡": ["angry", "rage", "furious"],
    "🤬": ["angry", "swear", "censored"],
    "🤯": ["mind-blown", "shocked", "exploding"],
    "😳": ["flushed", "embarrassed", "shocked"],
    "🥵": ["hot", "sweat", "feverish"],
    "🥶": ["cold", "freezing", "shiver"],
    "😱": ["scream", "shocked", "scared"],
    "😨": ["fearful", "scared", "anxious"],
    "😰": ["anxious", "cold-sweat", "worried"],
    "😥": ["sad", "relieved", "disappointed"],
    "😓": ["sweat", "tired", "hard-work"],
    "🤗": ["hug", "warm", "caring"],
    "🤔": ["thinking", "pondering", "hmm"],
    "🤭": ["giggle", "oops", "secret"],
    "🤫": ["shush", "quiet", "secret"],
    "🤥": ["lie", "pinocchio", "dishonest"],
    "😶": ["silent", "blank", "speechless"],
    "😐": ["neutral", "expressionless", "meh"],
    "😑": ["expressionless", "unimpressed", "deadpan"],
    "😬": ["grimace", "awkward", "oops"],
    "🙄": ["eye-roll", "annoyed", "whatever"],
    "😯": ["surprised", "wow", "shocked"],
    "😦": ["frown", "surprised", "concerned"],
    "😧": ["anguished", "worried", "shocked"],
    "😮": ["surprised", "wow", "gasp"],
    "😲": ["astonished", "shocked", "amazed"],
    "🥱": ["yawn", "tired", "bored"],
    "😴": ["sleep", "tired", "zzz"],
    "🤤": ["drool", "desire", "hungry"],
    "😪": ["sleepy", "tired", "drowsy"],
    "😵": ["dizzy", "confused", "knocked-out"],
    "🤐": ["zipper-mouth", "sealed", "secret"],
    "🥴": ["woozy", "dizzy", "drunk"],
    "🤢": ["nauseous", "sick", "disgust"],
    "🤮": ["vomit", "sick", "disgusted"],
    "🤧": ["sneeze", "sick", "tissue"],
    "😷": ["mask", "sick", "health"],
    "🤒": ["sick", "fever", "thermometer"],
    "🤕": ["injured", "bandage", "hurt"],
    "🤑": ["money", "greedy", "rich"],
    "🤠": ["cowboy", "western", "yee-haw"],
    "😈": ["devil", "evil", "mischief"],
    "👿": ["devil", "angry", "evil"],
    "👹": ["ogre", "monster", "scary"],
    "👺": ["goblin", "monster", "angry"],
    "🤡": ["clown", "silly", "joker"],
    "💩": ["poop", "silly", "crap"],
    "👻": ["ghost", "boo", "spooky"],
    "💀": ["skull", "dead", "danger"],
    "☠️": ["skull-crossbones", "danger", "pirate"],
    "👽": ["alien", "ufo", "extraterrestrial"],
    "👾": ["alien-monster", "game", "retro"],
    "🤖": ["robot", "ai", "mechanical"],
    "🎃": ["halloween", "pumpkin", "spooky"],
    "😺": ["cat", "happy", "smile"],
    "😸": ["cat", "grin", "happy"],
    "😹": ["cat", "laugh", "joy"],
    "😻": ["cat", "love", "heart-eyes"],
    "😼": ["cat", "smirk", "confident"],
    "😽": ["cat", "kiss", "affection"],
    "🙀": ["cat", "shocked", "surprised"],
    "😿": ["cat", "cry", "sad"],
    "😾": ["cat", "angry", "grumpy"],
    "👋": ["wave", "hello", "bye"],
    "🤚": ["raised-hand", "stop", "high-five"],
    "🖐️": ["hand", "stop", "five"],
    "✋": ["raised-hand", "stop", "halt"],
    "🖖": ["vulcan-salute", "star-trek", "live-long"],
    "👌": ["ok", "perfect", "good"],
    "🤌": ["pinched-fingers", "italian", "what"],
    "🤏": ["pinching-hand", "small", "tiny"],
    "✌️": ["victory", "peace", "two"],
    "🤞": ["crossed-fingers", "hope", "luck"],
    "🤟": ["love-you", "rock", "metal"],
    "🤘": ["rock-on", "metal", "horns"],
    "🤙": ["call-me", "hang-loose", "shaka"],
    "👈": ["point-left", "that", "direction"],
    "👉": ["point-right", "this", "direction"],
    "👆": ["point-up", "above", "look"],
    "🖕": ["middle-finger", "rude", "offensive"],
    "👇": ["point-down", "below", "look"],
    "☝️": ["point-up", "number-one", "attention"],
    "👍": ["thumbs-up", "good", "like"],
    "👎": ["thumbs-down", "bad", "dislike"],
    "✊": ["fist", "power", "solidarity"],
    "👊": ["fist-bump", "punch", "strong"],
    "🤛": ["left-fist-bump", "punch", "strong"],
    "🤜": ["right-fist-bump", "punch", "strong"],
    "👏": ["clap", "applause", "bravo"],
    "🙌": ["raising-hands", "celebration", "praise"],
    "👐": ["open-hands", "hug", "offering"],
    "🤲": ["palms-up", "prayer", "offering"],
    "🤝": ["handshake", "deal", "agreement"],
    "🙏": ["pray", "thanks", "namaste"],
    "✍️": ["writing", "note", "sign"],
    "💪": ["muscle", "strong", "flex"],
    "🦾": ["mechanical-arm", "strong", "robot"],
    "🦿": ["mechanical-leg", "prosthetic", "robot"],
    "🦵": ["leg", "kick", "limb"],
    "🦶": ["foot", "kick", "step"],
    "👂": ["ear", "listen", "hear"],
    "🦻": ["ear-hearing-aid", "listen", "assist"],
    "👃": ["nose", "smell", "sniff"],
    "🧠": ["brain", "smart", "think"],
    "🫀": ["heart-anatomy", "love", "life"],
    "🫁": ["lungs", "breath", "respiratory"],
    "🦷": ["tooth", "dental", "smile"],
    "🦴": ["bone", "skeleton", "structure"],
    "👀": ["eyes", "looking", "watching"],
    "👁️": ["eye", "see", "vision"],
    "👅": ["tongue", "taste", "lick"],
    "👄": ["mouth", "lips", "kiss"],
    "💋": ["kiss-mark", "lipstick", "love"],
    "🩸": ["blood", "donate", "injury"],
    "🔪": ["knife", "cut", "dangerous"],
    "❓": ["question", "confused", "unknown"],
    "❗": ["exclamation", "important", "alert"],
    "💯": ["hundred", "perfect", "full"],
    "💢": ["anger", "frustrated", "symbol"],
    "💥": ["collision", "boom", "explosion"],
    "💫": ["dizzy", "stars", "sparkle"],
    "💦": ["sweat", "water", "droplets"],
    "💨": ["dash", "wind", "fast"],
    "🕳️": ["hole", "empty", "void"],
    "💣": ["bomb", "explosive", "danger"],
    "💬": ["speech-balloon", "chat", "talk"],
    "👁️‍🗨️": ["eye-speech-bubble", "witness", "i-am-witness"],
    "🗨️": ["left-speech-bubble", "chat", "talk"],
    "🗯️": ["right-anger-bubble", "angry", "shout"],
    "💭": ["thought-balloon", "thinking", "dream"],
    "💤": ["zzz", "sleep", "tired"],
    "👨⚕️": ["doctor", "medical", "health"],
    "👩⚕️": ["doctor", "medical", "health"],
    "🙋♀️": ["woman-raising-hand", "question", "volunteer"],
    "🙋‍♂️": ["man-raising-hand", "question", "volunteer"],
    "🍚": ["rice", "food", "meal"],
    "🫠": ["melting", "hot", "dissolve"],
    "🫨": ["shaking", "vibrate", "earthquake"],
    "🌞": ["sun-face", "happy", "sunny", "positive"],
}

with open("stickers.json") as f:
    data = json.load(f)

tagged_count = 0
for sticker in data["collected"]:
    emoji = sticker["emoji"]
    # Skip if already has tags
    if sticker["tags"]:
        continue
    
    # Auto-tag based on emoji
    if emoji in EMOJI_TAGS:
        sticker["tags"] = EMOJI_TAGS[emoji]
        tagged_count += 1
        print(f"  ✅ Tagged {emoji}: {', '.join(EMOJI_TAGS[emoji])}")
    else:
        print(f"  ⏭️  Skipped {emoji}: no auto-tag rule")

with open("stickers.json", "w") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

print(f"\n✅ Auto-tagged {tagged_count} stickers!")
PYTHON

echo ""
echo "📊 Run './check-collection.sh' to see your tagged collection"


path: check-collection.sh
content: #!/bin/bash
#
# Check Sticker Collection Status
# Quick check if you have stickers ready to use
#

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STICKERS_JSON="$SCRIPT_DIR/stickers.json"

# Check if stickers.json exists
if [ ! -f "$STICKERS_JSON" ]; then
    echo "⚠️  No stickers.json found!"
    echo ""
    echo "📝 Quick setup:"
    echo "   1. cp stickers.json.example stickers.json"
    echo "   2. Send some stickers in Telegram"
    echo "   3. Run: ./add-sticker.sh <file_id> <emoji>"
    exit 1
fi

# Count collected stickers
TOTAL=$(jq '.collected | length' "$STICKERS_JSON")

if [ "$TOTAL" -eq 0 ]; then
    echo "📭 Sticker collection is empty!"
    echo ""
    echo "💡 To get started:"
    echo "   1. Send me some stickers in Telegram"
    echo "   2. I'll show you the file_id in the message"
    echo "   3. Run: ./add-sticker.sh <file_id> <emoji> [set_name] [tags]"
    echo ""
    echo "Example:"
    echo "   ./add-sticker.sh 'CAACAgEA...' '😀' 'MySet' 'happy,excited'"
else
    echo "✅ You have $TOTAL sticker(s) in your collection!"
    echo ""
    echo "📊 Collection preview:"
    jq -r '.collected[] | "   \(.emoji) - \(.set_name) (used \(.used_count) times)"' "$STICKERS_JSON"
    echo ""
    echo "📈 Stats:"
    jq -r '"   Total sent: \(.stats.total_sent)"' "$STICKERS_JSON"
    jq -r '"   Last sent: \(.stats.last_sent_at // "Never")"' "$STICKERS_JSON"
fi


path: import-sticker-pack.sh
content: #!/bin/bash
#
# Import entire Telegram sticker pack
# Usage: ./import-sticker-pack.sh <pack_name>
#

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STICKERS_JSON="$SCRIPT_DIR/stickers.json"

# Telegram Bot Token (read from OpenClaw config)
BOT_TOKEN=$(jq -r '.channels.telegram.botToken' ~/.openclaw/openclaw.json)

if [ -z "$1" ]; then
    echo "Usage: $0 <pack_name>"
    echo ""
    echo "Example:"
    echo "  $0 p_8RnHygLOjgFhGENFwoc1_by_SigStick11Bot"
    echo ""
    echo "To find pack name: right-click a sticker in Telegram → Copy Link"
    echo "The URL will be: https://t.me/addstickers/<pack_name>"
    exit 1
fi

PACK_NAME="$1"

echo "🔍 Fetching sticker pack: $PACK_NAME"

# Get sticker set from Telegram API
RESPONSE=$(curl -s "https://api.telegram.org/bot$BOT_TOKEN/getStickerSet?name=$PACK_NAME")

# Check if successful
if ! echo "$RESPONSE" | jq -e '.ok' > /dev/null; then
    ERROR=$(echo "$RESPONSE" | jq -r '.description // "Unknown error"')
    echo "❌ Failed to fetch sticker pack: $ERROR"
    exit 1
fi

# Extract sticker count
STICKER_COUNT=$(echo "$RESPONSE" | jq '.result.stickers | length')
PACK_TITLE=$(echo "$RESPONSE" | jq -r '.result.title')

echo "📦 Pack: $PACK_TITLE ($STICKER_COUNT stickers)"
echo ""

# Process each sticker
ADDED=0
SKIPPED=0
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "$RESPONSE" | jq -c '.result.stickers[]' | while read -r sticker; do
    FILE_ID=$(echo "$sticker" | jq -r '.file_id')
    EMOJI=$(echo "$sticker" | jq -r '.emoji')
    
    # Check if already exists
    if jq -e --arg fid "$FILE_ID" '.collected[] | select(.file_id == $fid)' "$STICKERS_JSON" > /dev/null 2>&1; then
        echo "  ⏭️  Skipped: $EMOJI (already in collection)"
        ((SKIPPED++)) || true
        continue
    fi
    
    # Add to collection
    jq --arg fid "$FILE_ID" \
       --arg emoji "$EMOJI" \
       --arg set "$PACK_NAME" \
       --arg ts "$TIMESTAMP" \
       '.collected += [{
           "file_id": $fid,
           "emoji": $emoji,
           "set_name": $set,
           "added_at": $ts,
           "used_count": 0,
           "last_used": null,
           "tags": []
       }]' "$STICKERS_JSON" > "$STICKERS_JSON.tmp"
    
    mv "$STICKERS_JSON.tmp" "$STICKERS_JSON"
    
    echo "  ✅ Added: $EMOJI"
    ((ADDED++)) || true
done

# Update total count
jq --arg count "$ADDED" '.stats.total_collected += ($count | tonumber)' "$STICKERS_JSON" > "$STICKERS_JSON.tmp"
mv "$STICKERS_JSON.tmp" "$STICKERS_JSON"

echo ""
echo "✅ Import complete!"
echo "   Added: $ADDED stickers"
echo "   Skipped: $SKIPPED (duplicates)"
echo ""
echo "📊 Run './check-collection.sh' to see your collection"


path: random-sticker.sh
content: #!/bin/bash
# random-sticker.sh - Pick a random sticker by emotion tags
# Usage: ./random-sticker.sh "happy" "excited"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STICKERS_JSON="$SCRIPT_DIR/stickers.json"

if [ ! -f "$STICKERS_JSON" ]; then
    echo "Error: stickers.json not found" >&2
    exit 1
fi

if [ $# -eq 0 ]; then
    echo "Usage: $0 <tag1> [tag2] [tag3]..." >&2
    exit 1
fi

# Build jq filter for multiple tags (OR logic)
TAGS=("$@")
JQ_FILTER='.collected[] | select('

for i in "${!TAGS[@]}"; do
    if [ $i -gt 0 ]; then
        JQ_FILTER+=" or "
    fi
    JQ_FILTER+=".tags[]? | contains(\"${TAGS[$i]}\")"
done

JQ_FILTER+=') | .file_id'

# Get all matching stickers and pick random one
cat "$STICKERS_JSON" | jq -r "$JQ_FILTER" | sort -R | head -1


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