Skip to content

Commit f2fa9a7

Browse files
authored
feat: add openclaw skill for lgtm cli access
1 parent 6107fca commit f2fa9a7

2 files changed

Lines changed: 198 additions & 0 deletions

File tree

openclaw-skill/SKILL.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
name: lgtm-openclaw
3+
version: "1.0.0"
4+
description: >
5+
Generate random alternative meanings for LGTM from the command line.
6+
Fetch entries from the official lgtm.airscript.it dataset with weighted rarity selection.
7+
Perfect for code reviews, CLI tools, and automation.
8+
author: Clawdeeo (@clawdeeo)
9+
source_url: https://github.com/airscripts/lgtm
10+
---
11+
12+
# LGTM OpenClaw Skill
13+
14+
Generate creative alternative meanings for "Looks Good To Me" directly from your terminal.
15+
16+
## Features
17+
18+
- HTTP fetching of full dataset (260+ entries)
19+
- Weighted random selection by rarity (Common 55%, Rare 27%, Epic 14%, Legendary 5%)
20+
- Filter by category or rarity tier
21+
- Local caching for offline use
22+
- Perfect for CI/CD pipelines and git hooks
23+
24+
## Installation
25+
26+
```bash
27+
cp -r openclaw-skill ~/.openclaw/skills/lgtm
28+
```
29+
30+
## Commands
31+
32+
| Command | Description |
33+
|---------|-------------|
34+
| `python3 scripts/lgtm.py random` | Random entry (weighted) |
35+
| `python3 scripts/lgtm.py random --category nerd` | Random from category |
36+
| `python3 scripts/lgtm.py random --epic` | Random epic or legendary |
37+
| `python3 scripts/lgtm.py get 42` | Get specific entry by ID |
38+
| `python3 scripts/lgtm.py list categories` | Show all categories |
39+
| `python3 scripts/lgtm.py fetch` | Refresh cache from source |
40+
41+
## Categories
42+
43+
- chaotic, corporate, existential, funny, mateo, nerd, sarcastic, wholesome
44+
45+
## Data Source
46+
47+
Entries sourced from lgtm.airscript.it by @airscript
48+
49+
## Example Output
50+
51+
LGTM #191 [COMMON]
52+
"Low Grade, Totally Merged"
53+
Category: sarcastic
54+
Description: Not your best work. You know it. They know it. Merge anyway.
55+
Tags: sarcasm, quality, merge
56+
57+
## License
58+
59+
MIT - Same as the main LGTM project.

openclaw-skill/scripts/lgtm.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/env python3
2+
"""LGTM - Fetch and display random alternative meanings from lgtm.airscript.it"""
3+
4+
import json
5+
import random
6+
import sys
7+
import argparse
8+
import urllib.request
9+
import os
10+
from pathlib import Path
11+
12+
DATA_URL = "https://raw.githubusercontent.com/airscripts/lgtm/main/data/lgtm.json"
13+
CACHE_FILE = Path.home() / ".cache" / "openclaw" / "lgtm" / "entries.json"
14+
RARITY_WEIGHTS = {"common": 0.55, "rare": 0.27, "epic": 0.14, "legendary": 0.05}
15+
16+
17+
def ensure_cache_dir():
18+
CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
19+
20+
21+
def fetch_data():
22+
"""Fetch LGTM data from GitHub."""
23+
try:
24+
req = urllib.request.Request(DATA_URL, headers={"User-Agent": "OpenClaw-LGTM/2.0"})
25+
with urllib.request.urlopen(req, timeout=30) as resp:
26+
data = json.loads(resp.read().decode("utf-8"))
27+
ensure_cache_dir()
28+
with open(CACHE_FILE, "w") as f:
29+
json.dump(data, f, indent=2)
30+
return data
31+
except Exception as e:
32+
print(f"Error fetching data: {e}", file=sys.stderr)
33+
return None
34+
35+
36+
def load_data():
37+
"""Load data from cache or fetch fresh."""
38+
if CACHE_FILE.exists():
39+
try:
40+
with open(CACHE_FILE) as f:
41+
return json.load(f)
42+
except Exception:
43+
pass
44+
return fetch_data()
45+
46+
47+
def weighted_random(entries):
48+
"""Select random entry weighted by rarity."""
49+
weights = [RARITY_WEIGHTS.get(e["rarity"], 0.1) for e in entries]
50+
return random.choices(entries, weights=weights, k=1)[0]
51+
52+
53+
def format_entry(entry):
54+
"""Format entry for display."""
55+
rarity = entry["rarity"].upper()
56+
tags = ", ".join(entry.get("tags", []))
57+
return f"""LGTM #{entry['id']} [{rarity}]
58+
"{entry['meaning']}"
59+
Category: {entry['category']}
60+
Description: {entry['description']}
61+
Tags: {tags}"""
62+
63+
64+
def main():
65+
parser = argparse.ArgumentParser(description="LGTM - Alternative meanings generator")
66+
subparsers = parser.add_subparsers(dest="command", help="Commands")
67+
68+
random_parser = subparsers.add_parser("random", help="Get random entry")
69+
random_parser.add_argument("--category", help="Filter by category")
70+
random_parser.add_argument("--rare", action="store_true", help="Only rare+")
71+
random_parser.add_argument("--epic", action="store_true", help="Only epic+")
72+
73+
get_parser = subparsers.add_parser("get", help="Get entry by ID")
74+
get_parser.add_argument("id", type=int, help="Entry ID")
75+
76+
list_parser = subparsers.add_parser("list", help="List categories or rarities")
77+
list_parser.add_argument("type", choices=["categories", "rarities"])
78+
79+
subparsers.add_parser("fetch", help="Refresh data from source")
80+
81+
args = parser.parse_args()
82+
83+
if not args.command:
84+
parser.print_help()
85+
sys.exit(1)
86+
87+
if args.command == "fetch":
88+
data = fetch_data()
89+
if data:
90+
print(f"Cached {len(data)} entries")
91+
return
92+
93+
if args.command == "list":
94+
if args.type == "categories":
95+
data = load_data()
96+
if data:
97+
cats = {}
98+
for e in data:
99+
cats[e["category"]] = cats.get(e["category"], 0) + 1
100+
for cat, count in sorted(cats.items()):
101+
print(f" {cat}: {count} entries")
102+
elif args.type == "rarities":
103+
for rarity, weight in RARITY_WEIGHTS.items():
104+
pct = int(weight * 100)
105+
print(f" {rarity}: {pct}%")
106+
return
107+
108+
data = load_data()
109+
if not data:
110+
print("Failed to load data. Run 'fetch' first.", file=sys.stderr)
111+
sys.exit(1)
112+
113+
if args.command == "get":
114+
entry = next((e for e in data if e["id"] == args.id), None)
115+
if entry:
116+
print(format_entry(entry))
117+
else:
118+
print(f"Entry #{args.id} not found", file=sys.stderr)
119+
sys.exit(1)
120+
121+
elif args.command == "random":
122+
filtered = data
123+
if args.category:
124+
filtered = [e for e in data if e["category"] == args.category.lower()]
125+
if args.rare:
126+
filtered = [e for e in filtered if e["rarity"] in ("rare", "epic", "legendary")]
127+
if args.epic:
128+
filtered = [e for e in filtered if e["rarity"] in ("epic", "legendary")]
129+
130+
if not filtered:
131+
print("No entries match criteria", file=sys.stderr)
132+
sys.exit(1)
133+
134+
entry = weighted_random(filtered) if not any([args.category, args.rare, args.epic]) else random.choice(filtered)
135+
print(format_entry(entry))
136+
137+
138+
if __name__ == "__main__":
139+
main()

0 commit comments

Comments
 (0)