@elisym/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env python3
2
+ """Check website status, response time, and SSL."""
3
+
4
+ import json
5
+ import ssl
6
+ import sys
7
+ import time
8
+ from urllib.parse import urlparse
9
+
10
+ import requests
11
+
12
+
13
+ def check_ssl(hostname):
14
+ """Check if SSL certificate is valid."""
15
+ try:
16
+ ctx = ssl.create_default_context()
17
+ with ctx.wrap_socket(ssl.socket(), server_hostname=hostname) as s:
18
+ s.settimeout(5)
19
+ s.connect((hostname, 443))
20
+ return True
21
+ except Exception:
22
+ return False
23
+
24
+
25
+ def main():
26
+ if len(sys.argv) < 2:
27
+ print(json.dumps({"error": "Usage: site_status.py <url>"}))
28
+ sys.exit(1)
29
+
30
+ url = sys.argv[1]
31
+ if not url.startswith(("http://", "https://")):
32
+ url = "https://" + url
33
+
34
+ parsed = urlparse(url)
35
+
36
+ try:
37
+ start = time.time()
38
+ resp = requests.get(url, timeout=15, allow_redirects=True)
39
+ elapsed_ms = round((time.time() - start) * 1000)
40
+ except requests.exceptions.ConnectionError:
41
+ print(json.dumps({"url": url, "error": "Connection failed", "status": "down"}))
42
+ sys.exit(1)
43
+ except requests.exceptions.Timeout:
44
+ print(json.dumps({"url": url, "error": "Timeout", "status": "timeout"}))
45
+ sys.exit(1)
46
+ except Exception as e:
47
+ print(json.dumps({"url": url, "error": str(e)}))
48
+ sys.exit(1)
49
+
50
+ redirect_chain = []
51
+ for r in resp.history:
52
+ redirect_chain.append({
53
+ "url": r.url,
54
+ "status_code": r.status_code,
55
+ })
56
+
57
+ ssl_valid = None
58
+ if parsed.scheme == "https" or resp.url.startswith("https://"):
59
+ final_host = urlparse(resp.url).hostname
60
+ ssl_valid = check_ssl(final_host)
61
+
62
+ result = {
63
+ "url": resp.url,
64
+ "status_code": resp.status_code,
65
+ "response_time_ms": elapsed_ms,
66
+ "redirect_chain": redirect_chain if redirect_chain else None,
67
+ "ssl_valid": ssl_valid,
68
+ "server": resp.headers.get("Server"),
69
+ }
70
+
71
+ print(json.dumps(result, indent=2))
72
+
73
+
74
+ if __name__ == "__main__":
75
+ main()
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: stock-price
3
+ description: Stock quote agent. Send a ticker (e.g. AAPL) - get price, daily change, volume, and 52-week range
4
+ capabilities:
5
+ - stock-price
6
+ - stocks
7
+ tools:
8
+ - name: get_quote
9
+ description: Get current stock quote for a ticker symbol. Returns JSON with ticker, name, price, change, change_percent, volume, market_cap, 52w_high, 52w_low.
10
+ command: ['python3', 'scripts/stock_price.py']
11
+ parameters:
12
+ - name: ticker
13
+ description: Stock ticker symbol (e.g. AAPL, GOOGL, TSLA)
14
+ required: true
15
+ ---
16
+
17
+ You are a stock price agent.
18
+
19
+ When asked about stock prices:
20
+
21
+ 1. Use the get_quote tool with the ticker symbol
22
+ 2. Present price, daily change, volume, and market cap
23
+ 3. Include 52-week high/low for context
24
+
25
+ IMPORTANT: Output plain text only. No markdown formatting (no #, \*\*, -, ```, etc.). Use simple line breaks and dashes for structure.
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env python3
2
+ """Fetch stock quote using yfinance."""
3
+
4
+ import json
5
+ import sys
6
+
7
+ import yfinance as yf
8
+
9
+
10
+ def main():
11
+ if len(sys.argv) < 2:
12
+ print(json.dumps({"error": "Usage: stock_price.py <ticker>"}))
13
+ sys.exit(1)
14
+
15
+ ticker = sys.argv[1].upper()
16
+
17
+ try:
18
+ stock = yf.Ticker(ticker)
19
+ info = stock.info
20
+ except Exception as e:
21
+ print(json.dumps({"error": f"yfinance failed: {e}"}))
22
+ sys.exit(1)
23
+
24
+ if not info or info.get("regularMarketPrice") is None:
25
+ print(json.dumps({"error": f"No data found for ticker '{ticker}'"}))
26
+ sys.exit(1)
27
+
28
+ price = info.get("regularMarketPrice") or info.get("currentPrice")
29
+ prev_close = info.get("regularMarketPreviousClose")
30
+ change = round(price - prev_close, 2) if price and prev_close else None
31
+ change_pct = round((change / prev_close) * 100, 2) if change and prev_close else None
32
+
33
+ result = {
34
+ "ticker": ticker,
35
+ "name": info.get("shortName") or info.get("longName"),
36
+ "price": price,
37
+ "change": change,
38
+ "change_percent": change_pct,
39
+ "volume": info.get("regularMarketVolume"),
40
+ "market_cap": info.get("marketCap"),
41
+ "52w_high": info.get("fiftyTwoWeekHigh"),
42
+ "52w_low": info.get("fiftyTwoWeekLow"),
43
+ }
44
+
45
+ print(json.dumps(result, indent=2))
46
+
47
+
48
+ if __name__ == "__main__":
49
+ main()
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: trending
3
+ description: Trending agent. Ask for GitHub or Reddit trends - get a ranked list of top repos or posts
4
+ capabilities:
5
+ - trending
6
+ - popular
7
+ tools:
8
+ - name: get_trending
9
+ description: Get trending items from GitHub or Reddit. Returns JSON array of [{rank, title, url, description, score/stars}, ...]. No API key needed.
10
+ command: ['python3', 'scripts/trending.py']
11
+ parameters:
12
+ - name: source
13
+ description: "Source to fetch from: 'github' or 'reddit'"
14
+ required: true
15
+ - name: category
16
+ description: 'For GitHub: language filter (e.g. python, rust). For Reddit: subreddit name (e.g. technology, programming). Default: all/popular'
17
+ required: false
18
+ ---
19
+
20
+ You are a trending content agent.
21
+
22
+ When asked about what's trending:
23
+
24
+ 1. Use the get_trending tool with the appropriate source
25
+ 2. Present the top items with rank, title, description, and score
26
+ 3. You can query both GitHub and Reddit if the user wants a broad overview
27
+
28
+ IMPORTANT: Output plain text only. No markdown formatting (no #, \*\*, -, ```, etc.). Use simple line breaks and dashes for structure.
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python3
2
+ """Fetch trending repos from GitHub or posts from Reddit."""
3
+
4
+ import json
5
+ import sys
6
+
7
+ import requests
8
+ from bs4 import BeautifulSoup
9
+
10
+
11
+ def github_trending(language=None):
12
+ """Scrape GitHub trending page."""
13
+ url = "https://github.com/trending"
14
+ if language:
15
+ url += f"/{language}"
16
+
17
+ headers = {"User-Agent": "Mozilla/5.0 (compatible; elisym-agent/1.0)"}
18
+
19
+ try:
20
+ resp = requests.get(url, headers=headers, timeout=15)
21
+ resp.raise_for_status()
22
+ except Exception as e:
23
+ return {"error": f"Failed to fetch GitHub trending: {e}"}
24
+
25
+ soup = BeautifulSoup(resp.text, "html.parser")
26
+ articles = soup.select("article.Box-row")
27
+
28
+ results = []
29
+ for i, article in enumerate(articles[:25], 1):
30
+ h2 = article.select_one("h2 a")
31
+ if not h2:
32
+ continue
33
+ repo_path = h2.get("href", "").strip("/")
34
+ name = repo_path
35
+
36
+ desc_p = article.select_one("p")
37
+ description = desc_p.get_text(strip=True) if desc_p else None
38
+
39
+ stars_el = article.select_one("a[href$='/stargazers']")
40
+ stars = stars_el.get_text(strip=True).replace(",", "") if stars_el else None
41
+
42
+ lang_el = article.select_one("[itemprop='programmingLanguage']")
43
+ lang = lang_el.get_text(strip=True) if lang_el else None
44
+
45
+ results.append({
46
+ "rank": i,
47
+ "title": name,
48
+ "url": f"https://github.com/{repo_path}",
49
+ "description": description,
50
+ "stars": stars,
51
+ "language": lang,
52
+ })
53
+
54
+ return results
55
+
56
+
57
+ def reddit_trending(subreddit=None):
58
+ """Fetch hot posts from Reddit."""
59
+ sub = subreddit or "popular"
60
+ url = f"https://old.reddit.com/r/{sub}/.json?limit=25"
61
+ headers = {"User-Agent": "elisym-agent/1.0"}
62
+
63
+ try:
64
+ resp = requests.get(url, headers=headers, timeout=15)
65
+ resp.raise_for_status()
66
+ data = resp.json()
67
+ except Exception as e:
68
+ return {"error": f"Failed to fetch Reddit: {e}"}
69
+
70
+ results = []
71
+ children = data.get("data", {}).get("children", [])
72
+ for i, child in enumerate(children, 1):
73
+ post = child.get("data", {})
74
+ results.append({
75
+ "rank": i,
76
+ "title": post.get("title"),
77
+ "url": f"https://reddit.com{post.get('permalink', '')}",
78
+ "description": post.get("selftext", "")[:200] or None,
79
+ "score": post.get("score"),
80
+ "subreddit": post.get("subreddit"),
81
+ })
82
+
83
+ return results
84
+
85
+
86
+ def main():
87
+ if len(sys.argv) < 2:
88
+ print(json.dumps({"error": "Usage: trending.py <github|reddit> [category]"}))
89
+ sys.exit(1)
90
+
91
+ source = sys.argv[1].lower()
92
+ category = sys.argv[2] if len(sys.argv) > 2 else None
93
+
94
+ if source == "github":
95
+ result = github_trending(category)
96
+ elif source == "reddit":
97
+ result = reddit_trending(category)
98
+ else:
99
+ result = {"error": f"Unknown source: {source}. Use 'github' or 'reddit'"}
100
+
101
+ print(json.dumps(result, indent=2))
102
+
103
+
104
+ if __name__ == "__main__":
105
+ main()
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: whois-lookup
3
+ description: WHOIS agent. Send a domain - get registrar, dates, name servers, and status
4
+ capabilities:
5
+ - whois-lookup
6
+ - domain-info
7
+ tools:
8
+ - name: whois_domain
9
+ description: Look up WHOIS registration info for a domain. Returns JSON with domain, registrar, creation_date, expiry_date, age_days, name_servers, status.
10
+ command: ['python3', 'scripts/whois_lookup.py']
11
+ parameters:
12
+ - name: domain
13
+ description: Domain name to look up (e.g. example.com)
14
+ required: true
15
+ ---
16
+
17
+ You are a domain WHOIS lookup agent.
18
+
19
+ When given a request about a domain:
20
+
21
+ 1. Use the whois_domain tool to fetch registration information
22
+ 2. Present the results clearly to the user
23
+
24
+ IMPORTANT: Output plain text only. No markdown formatting (no #, \*\*, -, ```, etc.). Use simple line breaks and dashes for structure.
25
+
26
+ Include: registrar, registration and expiry dates, domain age, name servers, and current status.
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env python3
2
+ """WHOIS lookup for a domain."""
3
+
4
+ import json
5
+ import sys
6
+ from datetime import datetime, timezone
7
+
8
+ import whois
9
+
10
+
11
+ def main():
12
+ if len(sys.argv) < 2:
13
+ print(json.dumps({"error": "Usage: whois_lookup.py <domain>"}))
14
+ sys.exit(1)
15
+
16
+ domain = sys.argv[1]
17
+
18
+ try:
19
+ w = whois.whois(domain)
20
+ except Exception as e:
21
+ print(json.dumps({"error": f"WHOIS lookup failed: {e}"}))
22
+ sys.exit(1)
23
+
24
+ creation = w.creation_date
25
+ if isinstance(creation, list):
26
+ creation = creation[0]
27
+
28
+ expiry = w.expiration_date
29
+ if isinstance(expiry, list):
30
+ expiry = expiry[0]
31
+
32
+ age_days = None
33
+ if creation:
34
+ now = datetime.now(timezone.utc)
35
+ if creation.tzinfo is None:
36
+ creation = creation.replace(tzinfo=timezone.utc)
37
+ age_days = (now - creation).days
38
+
39
+ name_servers = w.name_servers
40
+ if name_servers and isinstance(name_servers, (list, set)):
41
+ name_servers = sorted(set(ns.lower() for ns in name_servers))
42
+
43
+ status = w.status
44
+ if isinstance(status, list):
45
+ status = status
46
+ elif status:
47
+ status = [status]
48
+ else:
49
+ status = []
50
+
51
+ result = {
52
+ "domain": w.domain_name if w.domain_name else domain,
53
+ "registrar": w.registrar,
54
+ "creation_date": str(creation) if creation else None,
55
+ "expiry_date": str(expiry) if expiry else None,
56
+ "age_days": age_days,
57
+ "name_servers": name_servers,
58
+ "status": status,
59
+ }
60
+
61
+ print(json.dumps(result, indent=2, default=str))
62
+
63
+
64
+ if __name__ == "__main__":
65
+ main()
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: youtube-summary
3
+ description: YouTube summary agent. Send a link - get overview, key points, and takeaways
4
+ capabilities:
5
+ - youtube-summary
6
+ - video-analysis
7
+ max_tool_rounds: 15
8
+ tools:
9
+ - name: fetch_transcript
10
+ description: Fetch transcript from a YouTube video. Returns JSON with title, channel, duration_min, language, total_chunks, chunk (current chunk index), and transcript (text of chunk 0). If total_chunks > 1, use read_chunk to get remaining chunks.
11
+ command: ['python3', 'scripts/summarize.py', '--lang', 'auto']
12
+ parameters:
13
+ - name: url
14
+ description: YouTube video URL
15
+ required: true
16
+ - name: read_chunk
17
+ description: Read a specific chunk of a previously fetched transcript. Use this after fetch_transcript when total_chunks > 1. Returns JSON with title, chunk, total_chunks, and transcript text for that chunk.
18
+ command: ['python3', 'scripts/summarize.py']
19
+ parameters:
20
+ - name: url
21
+ description: Same YouTube URL used in fetch_transcript
22
+ required: true
23
+ - name: chunk
24
+ description: Chunk index to read (0-indexed). Start from 1 since fetch_transcript already returns chunk 0.
25
+ required: true
26
+ ---
27
+
28
+ You are a YouTube video summarizer.
29
+
30
+ When given a request:
31
+
32
+ 1. Call fetch_transcript with the video URL
33
+ 2. Check total_chunks in the response:
34
+ - If total_chunks is 1: you have the full transcript, summarize it
35
+ - If total_chunks > 1: you already have chunk 0. Call read_chunk for chunks 1, 2, ... up to total_chunks-1, one at a time. After reading each chunk, note its key points. After all chunks are read, write a combined summary.
36
+ 3. Write the summary in the language the user used. If only a URL was sent, use the video's language.
37
+
38
+ IMPORTANT: Output plain text only. No markdown formatting (no #, \*\*, -, ```, etc.). Use simple line breaks and dashes for structure.
39
+
40
+ Summary format:
41
+ 2-3 sentence overview
42
+ Key points (use dashes for lists)
43
+ Important quotes, numbers, or facts mentioned
44
+ Brief conclusion / takeaway