Skip to main content

skill-zulip

Fetch a Zulip thread via API and write formatted JSON to a file. Invoke for /zulip command.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
benbrastmckie/nvim
آخر نشاط في المصدر
١٤ يوليو ٢٠٢٦ في ٢٣:١٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٤٤٤
التفرعات
٤٥٩

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
skill-zulip
description
Fetch a Zulip thread via API and write formatted JSON to a file. Invoke for /zulip command.
allowed-tools
Bash, AskUserQuestion
# Zulip Fetch Skill (Direct Execution) Direct execution skill that fetches all messages from a Zulip chat thread and writes formatted JSON output (sender, date, content) to a target file. Reads credentials from ~/.zuliprc and parses the Zulip URL to extract channel and topic. ## Execution ### Step 1: Parse Arguments Extract URL and optional output path from the arguments passed to this skill. Run these bash commands to parse the arguments: ```bash url=$(echo "$ARGUMENTS" | awk '{print $1}') output_path=$(echo "$ARGUMENTS" | awk 'NF>=2{print $2}') ``` If `$url` is empty, print usage and stop: ```bash if [ -z "$url" ]; then echo "Error: Usage: /zulip <zulip-url> [output-path]" echo "Example: /zulip https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/some.20topic" exit 1 fi ``` ### Step 2: Validate Prerequisites Check that the credentials file exists and all required tools are available: ```bash zuliprc="$HOME/.zuliprc" if [ ! -f "$zuliprc" ]; then echo "Error: ~/.zuliprc not found. Create it with:" echo " [api]" echo " email=your@email.com" echo " key=your_api_key" echo " site=https://yourorg.zulipchat.com" exit 1 fi for tool in curl jq python3; do if ! which "$tool" >/dev/null 2>&1; then echo "Error: Required tool not found: $tool" exit 1 fi done ``` ### Step 3: Read Credentials Parse ~/.zuliprc to extract the API email, key, and site URL: ```bash email=$(grep -oP '(?<=email=)\S+' "$zuliprc") api_key=$(grep -oP '(?<=key=)\S+' "$zuliprc") site=$(grep -oP '(?<=site=)\S+' "$zuliprc" | sed 's|/$||') if [ -z "$email" ] || [ -z "$api_key" ] || [ -z "$site" ]; then echo "Error: ~/.zuliprc is missing required fields (email, key, site)" exit 1 fi ``` ### Step 4: Parse Zulip URL Extract the base URL, channel/stream segment, topic segment, and optional message anchor from the URL. Note: Zulip uses `#narrow/channel/` in newer versions and `#narrow/stream/` in older ones — both must be handled. ```bash base=$(echo "$url" | grep -oP 'https?://[^/#]+') channel_raw=$(echo "$url" | grep -oP '(?<=#narrow/(?:channel|stream)/)[^/]+') topic_raw=$(echo "$url" | grep -oP '(?<=/topic/)[^/]+') near_id=$(echo "$url" | grep -oP '(?<=/near/)[0-9]+' || true) if [ -z "$base" ] || [ -z "$channel_raw" ]; then echo "Error: Could not parse Zulip URL. Expected format:" echo " https://REALM.zulipchat.com/#narrow/channel/ID-stream-name/topic/topic.20text" exit 1 fi if [ -z "$topic_raw" ]; then echo "Error: URL does not contain a topic segment. Provide a thread URL (not just a channel URL)." exit 1 fi ``` ### Step 5: Decode URL Components Convert the raw URL segments into a usable stream name and topic string. Zulip uses dot-encoding in URL fragments: `.20` means space, `.2C` means comma, etc. These are different from standard percent-encoding. The conversion is: `.XX` -> `%XX`, then standard URL-decode. ```bash channel_slug=$(echo "$channel_raw" | sed 's/^[0-9]*-//') stream_name=$(echo "$channel_slug" | tr '-' ' ') topic=$(python3 -c " import re, sys from urllib.parse import unquote raw = sys.argv[1] pct = re.sub(r'\.([0-9A-Fa-f]{2})', lambda m: '%' + m.group(1), raw) print(unquote(pct)) " "$topic_raw") echo "Fetching thread: stream='$stream_name', topic='$topic'" if [ -n "$near_id" ]; then echo "Anchor: message ID $near_id" fi ``` ### Step 6: Resolve Output Path If no output path was provided in the arguments, prompt the user to choose where to send the output. Use AskUserQuestion to present two choices: - **Option 1**: Print JSON to the screen (stdout) - **Option 2**: Write JSON to a file (user provides path) Ask: "Where should the Zulip thread output go? Enter '1' to display inline, or '2' to write to a file." If the user chooses option 2 (write to file), ask a follow-up question: "Enter output file path (e.g., /tmp/thread.json or ~/thread.json):" Set `output_path` to the entered path, or set `use_stdout=true` if option 1 was chosen. If `output_path` was already provided in the arguments (Step 1), skip this step entirely. ### Step 7: Fetch Messages Build the narrow parameter, URL-encode it, and call the Zulip REST API. ```bash narrow=$(python3 -c " import json, sys print(json.dumps([ {'operator': 'stream', 'operand': sys.argv[1]}, {'operator': 'topic', 'operand': sys.argv[2]} ])) " "$stream_name" "$topic") narrow_encoded=$(python3 -c " from urllib.parse import quote import sys print(quote(sys.argv[1])) " "$narrow") anchor="${near_id:-newest}" echo "Calling Zulip API..." response=$(curl -s --user "$email:$api_key" \ "${site}/api/v1/messages?anchor=${anchor}&num_before=5000&num_after=0&narrow=${narrow_encoded}") api_result=$(echo "$response" | jq -r '.result' 2>/dev/null) if [ "$api_result" != "success" ]; then api_msg=$(echo "$response" | jq -r '.msg' 2>/dev/null || echo "Unknown error") echo "Error: Zulip API returned error: $api_msg" exit 1 fi msg_count=$(echo "$response" | jq '.messages | length' 2>/dev/null || echo 0) echo "Fetched $msg_count messages." ``` ### Step 8: Format and Write Output Extract sender, date, and content from the API response and write to the destination. Format each message as a JSON object with three fields: `sender` (full name), `date` (ISO 8601 date string from Unix timestamp), and `content` (raw HTML). ```bash formatted=$(echo "$response" | jq '[.messages[] | { sender: .sender_full_name, date: (.timestamp | todate), content: .content }]') ``` If `use_stdout` is true, or if `output_path` is still empty after Step 6, print `$formatted` directly to stdout. Otherwise write to file: ```bash mkdir -p "$(dirname "$output_path")" echo "$formatted" > "$output_path" ``` ### Step 9: Report Result Print a completion summary. If output was written to a file: ```bash echo "" echo "Thread written to: $output_path" echo "Messages: $msg_count" echo "Stream: $stream_name" echo "Topic: $topic" ``` If output was printed to stdout: ```bash echo "" echo "---" echo "Stream: $stream_name | Topic: $topic | Messages: $msg_count" ``` --- ## Error Handling - **~/.zuliprc missing**: Print setup instructions, exit 1 - **Required tool missing** (curl/jq/python3): Print tool name, exit 1 - **URL missing or malformed**: Print usage example, exit 1 - **No topic segment in URL**: Print error explaining a thread URL is needed, exit 1 - **API returns non-success**: Print the API error message, exit 1 - **Empty response**: jq safely returns empty array `[]` — this is valid output - **Output directory missing**: `mkdir -p $(dirname "$output_path")` before writing
عرض على GitHub