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
최근 소스 활동
2026년 7월 14일 23:14
감지된 SKILL.md 언어
영어
스타
443
포크
459

설치 방법

기본적으로 소스를 먼저 확인하는 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에서 보기