mirror of
https://github.com/cporter202/coreclaw-api-directory.git
synced 2026-08-03 21:15:24 +02:00
Add live star history tracking
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
name: Update star history
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "17 3 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: update-star-history
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Record stars and render chart
|
||||
run: python scripts/update_star_history.py
|
||||
|
||||
- name: Commit updated history
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add assets/star-history.svg data/star-history.json
|
||||
git diff --cached --quiet || git commit -m "Update star history"
|
||||
git push
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/cporter202/coreclaw-api-directory/actions/workflows/validate-catalog.yml"><img alt="Validate Catalog" src="https://github.com/cporter202/coreclaw-api-directory/actions/workflows/validate-catalog.yml/badge.svg"></a>
|
||||
<a href="https://github.com/cporter202/coreclaw-api-directory/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/cporter202/coreclaw-api-directory?style=for-the-badge&logo=github&label=Stars&color=f59e0b"></a>
|
||||
<img alt="118 public Workers" src="https://img.shields.io/badge/Public_Workers-118-6366f1?style=for-the-badge">
|
||||
<img alt="11 use-case categories" src="https://img.shields.io/badge/Categories-11-06b6d4?style=for-the-badge">
|
||||
<img alt="29 data sources" src="https://img.shields.io/badge/Data_Sources-29-8b5cf6?style=for-the-badge">
|
||||
@@ -44,6 +45,16 @@ A polished, community-maintained directory of **118 public CoreClaw Workers** fo
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Star history
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/cporter202/coreclaw-api-directory/stargazers">
|
||||
<img src="assets/star-history.svg" alt="CoreClaw API Directory star history chart" width="720">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center"><sub>Updated daily from GitHub. Like the directory? Star the repository to help more developers discover it.</sub></p>
|
||||
|
||||
CoreClaw calls these integrations **Workers**. Each Worker is a runnable web-data workflow with its own input schema and structured output, exposed through CoreClaw’s shared REST and MCP integration layers.
|
||||
|
||||
## Explore by use case
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="430" viewBox="0 0 1200 430" role="img" aria-labelledby="title desc">
|
||||
<title id="title">CoreClaw API Directory star history</title>
|
||||
<desc id="desc">Daily GitHub star count, currently 1 stars.</desc>
|
||||
<defs>
|
||||
<linearGradient id="background" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#070B1D"/><stop offset=".55" stop-color="#111B46"/><stop offset="1" stop-color="#0B3A4A"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="line" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop stop-color="#8B5CF6"/><stop offset=".5" stop-color="#6366F1"/><stop offset="1" stop-color="#22D3EE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop stop-color="#22D3EE" stop-opacity=".3"/><stop offset="1" stop-color="#6366F1" stop-opacity=".02"/>
|
||||
</linearGradient>
|
||||
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||
<path d="M40 0H0V40" fill="none" stroke="#A5B4FC" stroke-opacity=".035"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="1200" height="430" rx="26" fill="url(#background)"/>
|
||||
<rect width="1200" height="430" rx="26" fill="url(#grid)"/>
|
||||
<g font-family="Inter,Segoe UI,Arial,sans-serif">
|
||||
<text x="60" y="61" fill="#C7D2FE" font-size="16" font-weight="700" letter-spacing="2.4">STAR GROWTH</text>
|
||||
<text x="60" y="101" fill="#FFFFFF" font-size="30" font-weight="800">CoreClaw API Directory</text>
|
||||
<text x="1138" y="65" text-anchor="end" fill="#FBBF24" font-size="34" font-weight="800">★ 1</text>
|
||||
<text x="1138" y="94" text-anchor="end" fill="#A5B4FC" font-size="14">CURRENT STARS</text>
|
||||
<line x1="92" y1="132.0" x2="1135" y2="132.0" stroke="#A5B4FC" stroke-opacity=".12"/><text x="74" y="137.0" text-anchor="end" fill="#818CF8" font-size="14">4</text><line x1="92" y1="184.0" x2="1135" y2="184.0" stroke="#A5B4FC" stroke-opacity=".12"/><text x="74" y="189.0" text-anchor="end" fill="#818CF8" font-size="14">3</text><line x1="92" y1="236.0" x2="1135" y2="236.0" stroke="#A5B4FC" stroke-opacity=".12"/><text x="74" y="241.0" text-anchor="end" fill="#818CF8" font-size="14">2</text><line x1="92" y1="288.0" x2="1135" y2="288.0" stroke="#A5B4FC" stroke-opacity=".12"/><text x="74" y="293.0" text-anchor="end" fill="#818CF8" font-size="14">1</text><line x1="92" y1="340.0" x2="1135" y2="340.0" stroke="#A5B4FC" stroke-opacity=".12"/><text x="74" y="345.0" text-anchor="end" fill="#818CF8" font-size="14">0</text>
|
||||
<path d="M 613.5 340 L 613.5 288.0 L 613.5 340 Z" fill="url(#area)"/>
|
||||
<polyline points="613.5,288.0" fill="none" stroke="url(#line)" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="613.5" cy="288.0" r="4" fill="#22D3EE" stroke="#07101F" stroke-width="2"/>
|
||||
<text x="92" y="380" fill="#A5B4FC" font-size="14">2026-07-22</text>
|
||||
<text x="1135" y="380" text-anchor="end" fill="#A5B4FC" font-size="14">Tracking started</text>
|
||||
<text x="600" y="409" text-anchor="middle" fill="#818CF8" font-size="13">Daily snapshots recorded by this repository</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"repository": "cporter202/coreclaw-api-directory",
|
||||
"points": [
|
||||
{
|
||||
"date": "2026-07-22",
|
||||
"stars": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Record the repository's daily star count and render its README chart."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import math
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DATA_PATH = ROOT / "data" / "star-history.json"
|
||||
SVG_PATH = ROOT / "assets" / "star-history.svg"
|
||||
REPOSITORY = "cporter202/coreclaw-api-directory"
|
||||
|
||||
|
||||
def fetch_star_count() -> int:
|
||||
request = Request(
|
||||
f"https://api.github.com/repos/{REPOSITORY}",
|
||||
headers={
|
||||
"Accept": "application/vnd.github+json",
|
||||
"User-Agent": "coreclaw-api-directory-star-history",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
},
|
||||
)
|
||||
with urlopen(request, timeout=20) as response:
|
||||
return int(json.load(response)["stargazers_count"])
|
||||
|
||||
|
||||
def update_history(stars: int) -> dict:
|
||||
history = json.loads(DATA_PATH.read_text(encoding="utf-8"))
|
||||
today = datetime.now(timezone.utc).date().isoformat()
|
||||
points = history.setdefault("points", [])
|
||||
|
||||
if points and points[-1]["date"] == today:
|
||||
points[-1]["stars"] = stars
|
||||
else:
|
||||
points.append({"date": today, "stars": stars})
|
||||
|
||||
points.sort(key=lambda point: point["date"])
|
||||
DATA_PATH.write_text(json.dumps(history, indent=2) + "\n", encoding="utf-8")
|
||||
return history
|
||||
|
||||
|
||||
def render_svg(history: dict) -> str:
|
||||
points = history["points"]
|
||||
width, height = 1200, 430
|
||||
left, right, top, bottom = 92, 1135, 132, 340
|
||||
current = int(points[-1]["stars"])
|
||||
max_value = max(int(point["stars"]) for point in points)
|
||||
max_y = max(4, int(math.ceil(max_value / 4.0) * 4))
|
||||
|
||||
def x_at(index: int) -> float:
|
||||
if len(points) == 1:
|
||||
return (left + right) / 2
|
||||
return left + (right - left) * index / (len(points) - 1)
|
||||
|
||||
def y_at(value: int) -> float:
|
||||
return bottom - (bottom - top) * value / max_y
|
||||
|
||||
coordinates = [
|
||||
(x_at(index), y_at(int(point["stars"])))
|
||||
for index, point in enumerate(points)
|
||||
]
|
||||
polyline = " ".join(f"{x:.1f},{y:.1f}" for x, y in coordinates)
|
||||
area = (
|
||||
f"M {coordinates[0][0]:.1f} {bottom} "
|
||||
+ " ".join(f"L {x:.1f} {y:.1f}" for x, y in coordinates)
|
||||
+ f" L {coordinates[-1][0]:.1f} {bottom} Z"
|
||||
)
|
||||
grid = []
|
||||
for step in range(5):
|
||||
y = top + (bottom - top) * step / 4
|
||||
label = round(max_y * (4 - step) / 4)
|
||||
grid.append(
|
||||
f'<line x1="{left}" y1="{y:.1f}" x2="{right}" y2="{y:.1f}" '
|
||||
'stroke="#A5B4FC" stroke-opacity=".12"/>'
|
||||
f'<text x="{left - 18}" y="{y + 5:.1f}" text-anchor="end" '
|
||||
f'fill="#818CF8" font-size="14">{label}</text>'
|
||||
)
|
||||
dots = "".join(
|
||||
f'<circle cx="{x:.1f}" cy="{y:.1f}" r="4" fill="#22D3EE" '
|
||||
'stroke="#07101F" stroke-width="2"/>'
|
||||
for x, y in coordinates[-30:]
|
||||
)
|
||||
end_label = points[-1]["date"] if len(points) > 1 else "Tracking started"
|
||||
|
||||
return f'''<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" viewBox="0 0 {width} {height}" role="img" aria-labelledby="title desc">
|
||||
<title id="title">CoreClaw API Directory star history</title>
|
||||
<desc id="desc">Daily GitHub star count, currently {current} stars.</desc>
|
||||
<defs>
|
||||
<linearGradient id="background" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#070B1D"/><stop offset=".55" stop-color="#111B46"/><stop offset="1" stop-color="#0B3A4A"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="line" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop stop-color="#8B5CF6"/><stop offset=".5" stop-color="#6366F1"/><stop offset="1" stop-color="#22D3EE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop stop-color="#22D3EE" stop-opacity=".3"/><stop offset="1" stop-color="#6366F1" stop-opacity=".02"/>
|
||||
</linearGradient>
|
||||
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
||||
<path d="M40 0H0V40" fill="none" stroke="#A5B4FC" stroke-opacity=".035"/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="1200" height="430" rx="26" fill="url(#background)"/>
|
||||
<rect width="1200" height="430" rx="26" fill="url(#grid)"/>
|
||||
<g font-family="Inter,Segoe UI,Arial,sans-serif">
|
||||
<text x="60" y="61" fill="#C7D2FE" font-size="16" font-weight="700" letter-spacing="2.4">STAR GROWTH</text>
|
||||
<text x="60" y="101" fill="#FFFFFF" font-size="30" font-weight="800">CoreClaw API Directory</text>
|
||||
<text x="1138" y="65" text-anchor="end" fill="#FBBF24" font-size="34" font-weight="800">★ {current}</text>
|
||||
<text x="1138" y="94" text-anchor="end" fill="#A5B4FC" font-size="14">CURRENT STARS</text>
|
||||
{''.join(grid)}
|
||||
<path d="{area}" fill="url(#area)"/>
|
||||
<polyline points="{polyline}" fill="none" stroke="url(#line)" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
{dots}
|
||||
<text x="{left}" y="380" fill="#A5B4FC" font-size="14">{points[0]['date']}</text>
|
||||
<text x="{right}" y="380" text-anchor="end" fill="#A5B4FC" font-size="14">{end_label}</text>
|
||||
<text x="600" y="409" text-anchor="middle" fill="#818CF8" font-size="13">Daily snapshots recorded by this repository</text>
|
||||
</g>
|
||||
</svg>
|
||||
'''
|
||||
|
||||
|
||||
def main() -> None:
|
||||
history = update_history(fetch_star_count())
|
||||
SVG_PATH.write_text(render_svg(history), encoding="utf-8")
|
||||
print(
|
||||
f"Recorded {history['points'][-1]['stars']} stars for "
|
||||
f"{history['points'][-1]['date']}"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user