diff --git a/.github/stats/chart-dark.svg b/.github/stats/chart-dark.svg deleted file mode 100644 index 9795683..0000000 --- a/.github/stats/chart-dark.svg +++ /dev/null @@ -1,111 +0,0 @@ - - lahfir/agent-desktop — GitHub stars and ClawHub downloads over time - Time-series chart showing GitHub stars and ClawHub downloads for lahfir/agent-desktop. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lahfir/agent-desktop - - - GitHub stars · ClawHub downloads — updated daily - - - - ★ 89 GitHub - ⬇ 510 ClawHub - - - - 0 - 25 - 50 - 75 - 100 - - - - 0 - 250 - 500 - 750 - 1.0k - - - - Feb 21 - Mar 6 - Mar 18 - Mar 31 - Apr 12 - Apr 25 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Updated 2026-04-25 - - \ No newline at end of file diff --git a/.github/stats/chart-light.svg b/.github/stats/chart-light.svg deleted file mode 100644 index 10328c8..0000000 --- a/.github/stats/chart-light.svg +++ /dev/null @@ -1,111 +0,0 @@ - - lahfir/agent-desktop — GitHub stars and ClawHub downloads over time - Time-series chart showing GitHub stars and ClawHub downloads for lahfir/agent-desktop. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lahfir/agent-desktop - - - GitHub stars · ClawHub downloads — updated daily - - - - ★ 89 GitHub - ⬇ 510 ClawHub - - - - 0 - 25 - 50 - 75 - 100 - - - - 0 - 250 - 500 - 750 - 1.0k - - - - Feb 21 - Mar 6 - Mar 18 - Mar 31 - Apr 12 - Apr 25 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Updated 2026-04-25 - - \ No newline at end of file diff --git a/.github/stats/generate.mjs b/.github/stats/generate.mjs deleted file mode 100644 index f014acf..0000000 --- a/.github/stats/generate.mjs +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env node -import { readFile, writeFile } from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { dirname, join } from "node:path"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const HISTORY_PATH = join(__dirname, "history.json"); -const OUT_LIGHT = join(__dirname, "chart-light.svg"); -const OUT_DARK = join(__dirname, "chart-dark.svg"); - -const W = 1200; -const H = 420; -const PAD = { top: 76, right: 72, bottom: 56, left: 72 }; -const PLOT_W = W - PAD.left - PAD.right; -const PLOT_H = H - PAD.top - PAD.bottom; - -const THEMES = { - light: { - bg: "#ffffff", - surface: "#f6f8fa", - grid: "#d0d7de", - gridSoft: "#d0d7de", - axis: "#656d76", - text: "#1f2328", - textSoft: "#656d76", - titleAccent: "#0969da", - line1: "#0969da", - line1End: "#54aeff", - line2: "#bc4c00", - line2End: "#fb8500", - glowOpacity: 0.18, - fillOpacityTop: 0.18, - fillOpacityBottom: 0.0, - cardBorder: "#d0d7de", - }, - dark: { - bg: "#0d1117", - surface: "#161b22", - grid: "#30363d", - gridSoft: "#21262d", - axis: "#8b949e", - text: "#e6edf3", - textSoft: "#8b949e", - titleAccent: "#58a6ff", - line1: "#58a6ff", - line1End: "#a5d6ff", - line2: "#ff7b35", - line2End: "#ffa657", - glowOpacity: 0.32, - fillOpacityTop: 0.28, - fillOpacityBottom: 0.0, - cardBorder: "#30363d", - }, -}; - -function fmtNumber(n) { - if (n >= 1e6) return (n / 1e6).toFixed(n >= 1e7 ? 0 : 1) + "M"; - if (n >= 1e4) return (n / 1e3).toFixed(0) + "k"; - if (n >= 1e3) return (n / 1e3).toFixed(1) + "k"; - return String(Math.round(n)); -} - -function fmtDateShort(iso) { - const d = new Date(iso + "T00:00:00Z"); - return d.toLocaleDateString("en-US", { - month: "short", - day: "numeric", - timeZone: "UTC", - }); -} - -function niceMax(v) { - if (v <= 0) return 10; - const p = Math.pow(10, Math.floor(Math.log10(v))); - const f = v / p; - let nice; - if (f <= 1) nice = 1; - else if (f <= 2) nice = 2; - else if (f <= 5) nice = 5; - else nice = 10; - return nice * p; -} - -function dateToX(iso, minDay, maxDay) { - const d = new Date(iso + "T00:00:00Z").getTime() / 86400000; - const t = (d - minDay) / Math.max(1, maxDay - minDay); - return PAD.left + t * PLOT_W; -} - -function valToY(v, maxV) { - const t = v / Math.max(1, maxV); - return PAD.top + PLOT_H - t * PLOT_H; -} - -function catmullRomPath(points) { - if (points.length === 0) return ""; - if (points.length === 1) { - const [x, y] = points[0]; - return `M ${x.toFixed(2)} ${y.toFixed(2)}`; - } - let d = `M ${points[0][0].toFixed(2)} ${points[0][1].toFixed(2)}`; - for (let i = 0; i < points.length - 1; i++) { - const p0 = points[i - 1] || points[i]; - const p1 = points[i]; - const p2 = points[i + 1]; - const p3 = points[i + 2] || p2; - const cp1x = p1[0] + (p2[0] - p0[0]) / 6; - const cp1y = p1[1] + (p2[1] - p0[1]) / 6; - const cp2x = p2[0] - (p3[0] - p1[0]) / 6; - const cp2y = p2[1] - (p3[1] - p1[1]) / 6; - d += ` C ${cp1x.toFixed(2)} ${cp1y.toFixed(2)}, ${cp2x.toFixed(2)} ${cp2y.toFixed(2)}, ${p2[0].toFixed(2)} ${p2[1].toFixed(2)}`; - } - return d; -} - -function pathLength(points) { - let len = 0; - for (let i = 1; i < points.length; i++) { - const dx = points[i][0] - points[i - 1][0]; - const dy = points[i][1] - points[i - 1][1]; - len += Math.sqrt(dx * dx + dy * dy); - } - return Math.max(len, 1); -} - -function gridTicks(maxV, count = 4) { - const step = maxV / count; - return Array.from({ length: count + 1 }, (_, i) => i * step); -} - -function dateTicks(minDay, maxDay, count = 5) { - const span = maxDay - minDay; - const step = span / count; - return Array.from({ length: count + 1 }, (_, i) => { - const day = Math.round(minDay + i * step); - const iso = new Date(day * 86400000).toISOString().slice(0, 10); - return iso; - }); -} - -function renderChart(theme, history, meta) { - const t = THEMES[theme]; - const series1 = history.github_stars; // [[iso, n], ...] - const series2 = history.clawhub_downloads; - - const allDates = [...series1, ...series2].map(([iso]) => iso); - const minIso = allDates.reduce((a, b) => (a < b ? a : b)); - const maxIso = allDates.reduce((a, b) => (a > b ? a : b)); - const minDay = new Date(minIso + "T00:00:00Z").getTime() / 86400000; - const todayDay = new Date(maxIso + "T00:00:00Z").getTime() / 86400000; - const maxDay = todayDay; // x-axis ends today - - const max1 = niceMax(Math.max(...series1.map(([, v]) => v), 1)); - const max2 = niceMax(Math.max(...series2.map(([, v]) => v), 1)); - - const pts1 = series1.map(([iso, v]) => [ - dateToX(iso, minDay, maxDay), - valToY(v, max1), - ]); - const pts2 = series2.map(([iso, v]) => [ - dateToX(iso, minDay, maxDay), - valToY(v, max2), - ]); - - const line1Path = catmullRomPath(pts1); - const line2Path = catmullRomPath(pts2); - - const area1Path = - pts1.length >= 2 - ? `${line1Path} L ${pts1[pts1.length - 1][0].toFixed(2)} ${(PAD.top + PLOT_H).toFixed(2)} L ${pts1[0][0].toFixed(2)} ${(PAD.top + PLOT_H).toFixed(2)} Z` - : ""; - const area2Path = - pts2.length >= 2 - ? `${line2Path} L ${pts2[pts2.length - 1][0].toFixed(2)} ${(PAD.top + PLOT_H).toFixed(2)} L ${pts2[0][0].toFixed(2)} ${(PAD.top + PLOT_H).toFixed(2)} Z` - : ""; - - const yTicks1 = gridTicks(max1); - const yTicks2 = gridTicks(max2); - const xTicks = dateTicks(minDay, maxDay); - - const last1 = series1[series1.length - 1]?.[1] ?? 0; - const last2 = series2[series2.length - 1]?.[1] ?? 0; - - const titleY = 30; - const subtitleY = 50; - - const lastPt1 = pts1[pts1.length - 1]; - const lastPt2 = pts2[pts2.length - 1]; - - const FONT = - "-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif"; - - return ` - ${meta.repo} — GitHub stars and ClawHub downloads over time - Time-series chart showing GitHub stars and ClawHub downloads for ${meta.repo}. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${meta.repo} - - - ${meta.subtitle} - - - - ★ ${fmtNumber(last1)} GitHub - ⬇ ${fmtNumber(last2)} ClawHub - - - - ${yTicks1 - .map((v, i) => { - const y = valToY(v, max1); - const gridLine = - i === 0 - ? "" - : ``; - return `${gridLine}${fmtNumber(v)}`; - }) - .join("\n ")} - - - - ${yTicks2 - .map((v) => { - const y = valToY(v, max2); - return `${fmtNumber(v)}`; - }) - .join("\n ")} - - - - ${xTicks - .map((iso) => { - const x = dateToX(iso, minDay, maxDay); - return `${fmtDateShort(iso)}`; - }) - .join("\n ")} - - - - - - ${area1Path ? `` : ""} - ${area2Path ? `` : ""} - - ${ - pts1.length >= 2 - ? ` - - ` - : "" - } - - ${ - pts2.length >= 2 - ? ` - - ` - : "" - } - - ${ - lastPt1 - ? ` - - - - ` - : "" - } - ${ - lastPt2 - ? ` - - - - ` - : "" - } - - - - Updated ${meta.updatedAt} - -`; -} - -function hex(color, channel) { - const m = color.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i); - if (!m) return "0"; - const r = parseInt(m[1], 16) / 255; - const g = parseInt(m[2], 16) / 255; - const b = parseInt(m[3], 16) / 255; - return ({ r, g, b })[channel].toFixed(3); -} - -async function main() { - const raw = await readFile(HISTORY_PATH, "utf8"); - const history = JSON.parse(raw); - const meta = { - repo: history.repo, - subtitle: history.subtitle ?? "GitHub stars · ClawHub downloads", - updatedAt: new Date().toISOString().slice(0, 10), - }; - - const lightSvg = renderChart("light", history, meta); - const darkSvg = renderChart("dark", history, meta); - - await writeFile(OUT_LIGHT, lightSvg); - await writeFile(OUT_DARK, darkSvg); - - console.log(`Wrote ${OUT_LIGHT}`); - console.log(`Wrote ${OUT_DARK}`); - console.log( - `GitHub stars: ${history.github_stars[history.github_stars.length - 1]?.[1] ?? 0}`, - ); - console.log( - `ClawHub downloads: ${history.clawhub_downloads[history.clawhub_downloads.length - 1]?.[1] ?? 0}`, - ); -} - -main().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/.github/stats/history.json b/.github/stats/history.json deleted file mode 100644 index afef2bb..0000000 --- a/.github/stats/history.json +++ /dev/null @@ -1,488 +0,0 @@ -{ - "repo": "lahfir/agent-desktop", - "slug": "agent-desktop", - "clawhub_created_at": "2026-03-03", - "subtitle": "GitHub stars · ClawHub downloads — updated daily", - "github_stars": [ - [ - "2026-02-21", - 2 - ], - [ - "2026-02-22", - 2 - ], - [ - "2026-02-23", - 3 - ], - [ - "2026-02-24", - 3 - ], - [ - "2026-02-25", - 3 - ], - [ - "2026-02-26", - 4 - ], - [ - "2026-02-27", - 4 - ], - [ - "2026-02-28", - 4 - ], - [ - "2026-03-01", - 8 - ], - [ - "2026-03-02", - 10 - ], - [ - "2026-03-03", - 12 - ], - [ - "2026-03-04", - 16 - ], - [ - "2026-03-05", - 16 - ], - [ - "2026-03-06", - 16 - ], - [ - "2026-03-07", - 20 - ], - [ - "2026-03-08", - 21 - ], - [ - "2026-03-09", - 23 - ], - [ - "2026-03-10", - 28 - ], - [ - "2026-03-11", - 28 - ], - [ - "2026-03-12", - 32 - ], - [ - "2026-03-13", - 32 - ], - [ - "2026-03-14", - 32 - ], - [ - "2026-03-15", - 32 - ], - [ - "2026-03-16", - 32 - ], - [ - "2026-03-17", - 32 - ], - [ - "2026-03-18", - 32 - ], - [ - "2026-03-19", - 33 - ], - [ - "2026-03-20", - 33 - ], - [ - "2026-03-21", - 33 - ], - [ - "2026-03-22", - 33 - ], - [ - "2026-03-23", - 33 - ], - [ - "2026-03-24", - 33 - ], - [ - "2026-03-25", - 33 - ], - [ - "2026-03-26", - 33 - ], - [ - "2026-03-27", - 33 - ], - [ - "2026-03-28", - 34 - ], - [ - "2026-03-29", - 34 - ], - [ - "2026-03-30", - 34 - ], - [ - "2026-03-31", - 34 - ], - [ - "2026-04-01", - 36 - ], - [ - "2026-04-02", - 36 - ], - [ - "2026-04-03", - 37 - ], - [ - "2026-04-04", - 37 - ], - [ - "2026-04-05", - 40 - ], - [ - "2026-04-06", - 43 - ], - [ - "2026-04-07", - 44 - ], - [ - "2026-04-08", - 44 - ], - [ - "2026-04-09", - 44 - ], - [ - "2026-04-10", - 44 - ], - [ - "2026-04-11", - 45 - ], - [ - "2026-04-12", - 46 - ], - [ - "2026-04-13", - 50 - ], - [ - "2026-04-14", - 58 - ], - [ - "2026-04-15", - 66 - ], - [ - "2026-04-16", - 67 - ], - [ - "2026-04-17", - 68 - ], - [ - "2026-04-18", - 68 - ], - [ - "2026-04-19", - 68 - ], - [ - "2026-04-20", - 68 - ], - [ - "2026-04-21", - 70 - ], - [ - "2026-04-22", - 70 - ], - [ - "2026-04-23", - 70 - ], - [ - "2026-04-24", - 86 - ], - [ - "2026-04-25", - 89 - ] - ], - "clawhub_downloads": [ - [ - "2026-03-03", - 0 - ], - [ - "2026-03-04", - 10 - ], - [ - "2026-03-05", - 19 - ], - [ - "2026-03-06", - 29 - ], - [ - "2026-03-07", - 38 - ], - [ - "2026-03-08", - 48 - ], - [ - "2026-03-09", - 58 - ], - [ - "2026-03-10", - 67 - ], - [ - "2026-03-11", - 77 - ], - [ - "2026-03-12", - 87 - ], - [ - "2026-03-13", - 96 - ], - [ - "2026-03-14", - 106 - ], - [ - "2026-03-15", - 115 - ], - [ - "2026-03-16", - 125 - ], - [ - "2026-03-17", - 135 - ], - [ - "2026-03-18", - 144 - ], - [ - "2026-03-19", - 154 - ], - [ - "2026-03-20", - 164 - ], - [ - "2026-03-21", - 173 - ], - [ - "2026-03-22", - 183 - ], - [ - "2026-03-23", - 192 - ], - [ - "2026-03-24", - 202 - ], - [ - "2026-03-25", - 212 - ], - [ - "2026-03-26", - 221 - ], - [ - "2026-03-27", - 231 - ], - [ - "2026-03-28", - 241 - ], - [ - "2026-03-29", - 250 - ], - [ - "2026-03-30", - 260 - ], - [ - "2026-03-31", - 269 - ], - [ - "2026-04-01", - 279 - ], - [ - "2026-04-02", - 289 - ], - [ - "2026-04-03", - 298 - ], - [ - "2026-04-04", - 308 - ], - [ - "2026-04-05", - 318 - ], - [ - "2026-04-06", - 327 - ], - [ - "2026-04-07", - 337 - ], - [ - "2026-04-08", - 346 - ], - [ - "2026-04-09", - 356 - ], - [ - "2026-04-10", - 366 - ], - [ - "2026-04-11", - 375 - ], - [ - "2026-04-12", - 385 - ], - [ - "2026-04-13", - 395 - ], - [ - "2026-04-14", - 404 - ], - [ - "2026-04-15", - 414 - ], - [ - "2026-04-16", - 423 - ], - [ - "2026-04-17", - 433 - ], - [ - "2026-04-18", - 443 - ], - [ - "2026-04-19", - 452 - ], - [ - "2026-04-20", - 462 - ], - [ - "2026-04-21", - 472 - ], - [ - "2026-04-22", - 481 - ], - [ - "2026-04-23", - 491 - ], - [ - "2026-04-24", - 500 - ], - [ - "2026-04-25", - 510 - ] - ], - "sources": { - "github": "https://github.com/lahfir/agent-desktop", - "clawhub": "https://clawhub.ai/lahfir/agent-desktop", - "convex": "https://wry-manatee-359.convex.cloud" - }, - "schema_version": 1 -} diff --git a/.github/stats/seed.mjs b/.github/stats/seed.mjs deleted file mode 100644 index de40ffe..0000000 --- a/.github/stats/seed.mjs +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env node -import { writeFile } from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { dirname, join } from "node:path"; -import { execFileSync } from "node:child_process"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const HISTORY_PATH = join(__dirname, "history.json"); - -const REPO = process.env.STATS_REPO || "lahfir/agent-desktop"; -const SLUG = process.env.CLAWHUB_SLUG || "agent-desktop"; -const CONVEX_URL = "https://wry-manatee-359.convex.cloud"; - -function gh(args) { - return execFileSync("gh", args, { encoding: "utf8", maxBuffer: 50 * 1024 * 1024 }); -} - -async function fetchClawHubSkill(slug) { - const res = await fetch(`${CONVEX_URL}/api/query`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Convex-Client": "npm-1.20.0", - }, - body: JSON.stringify({ - path: "skills:getBySlug", - format: "convex_encoded_json", - args: [{ slug }], - }), - }); - if (!res.ok) throw new Error(`ClawHub HTTP ${res.status}: ${await res.text()}`); - const body = await res.json(); - if (body.status !== "success") { - throw new Error(`ClawHub error: ${body.errorMessage ?? "unknown"}`); - } - return body.value.skill; -} - -function backfillClawHubDaily(createdAtMs, currentDownloads, todayIso) { - const startMs = new Date( - new Date(createdAtMs).toISOString().slice(0, 10) + "T00:00:00Z", - ).getTime(); - const endMs = new Date(todayIso + "T00:00:00Z").getTime(); - const days = Math.max(1, Math.round((endMs - startMs) / 86400000)); - const out = []; - for (let i = 0; i <= days; i++) { - const dayMs = startMs + i * 86400000; - const iso = new Date(dayMs).toISOString().slice(0, 10); - const value = Math.round((currentDownloads * i) / days); - out.push([iso, value]); - } - return out; -} - -function fetchStarHistory(repo) { - const out = gh([ - "api", - "-H", - "Accept: application/vnd.github.star+json", - "--paginate", - `repos/${repo}/stargazers`, - "--jq", - "[.[] | .starred_at]", - ]); - const events = out - .split("\n") - .filter(Boolean) - .flatMap((chunk) => JSON.parse(chunk)); - return events.sort(); -} - -function bucketCumulative(starredAt) { - const counts = new Map(); - let cum = 0; - for (const iso of starredAt) { - cum += 1; - counts.set(iso.slice(0, 10), cum); - } - return [...counts.entries()].sort(); -} - -function fillDailyForward(buckets, untilIso) { - if (buckets.length === 0) return []; - const out = []; - const startMs = new Date(buckets[0][0] + "T00:00:00Z").getTime(); - const endMs = new Date(untilIso + "T00:00:00Z").getTime(); - const days = Math.round((endMs - startMs) / 86400000); - let bi = 0; - let cur = buckets[0][1]; - for (let i = 0; i <= days; i++) { - const dayMs = startMs + i * 86400000; - const iso = new Date(dayMs).toISOString().slice(0, 10); - while (bi < buckets.length && buckets[bi][0] <= iso) { - cur = buckets[bi][1]; - bi++; - } - out.push([iso, cur]); - } - return out; -} - -async function main() { - const today = new Date().toISOString().slice(0, 10); - console.log(`[seed] repo=${REPO} slug=${SLUG} today=${today}`); - - console.log("[seed] fetching GitHub star history..."); - const starredAt = fetchStarHistory(REPO); - console.log(`[seed] got ${starredAt.length} star events`); - - const buckets = bucketCumulative(starredAt); - const ghDaily = fillDailyForward(buckets, today); - console.log(`[seed] github series: ${ghDaily.length} daily points`); - - console.log("[seed] fetching ClawHub stats..."); - const skill = await fetchClawHubSkill(SLUG); - const downloads = Math.round(skill.stats?.downloads ?? 0); - const createdAtMs = skill.createdAt ?? skill._creationTime ?? Date.now(); - console.log( - `[seed] clawhub downloads=${downloads} createdAt=${new Date(createdAtMs).toISOString().slice(0, 10)}`, - ); - - const chDaily = backfillClawHubDaily(createdAtMs, downloads, today); - console.log(`[seed] clawhub series: ${chDaily.length} daily points (linear backfill)`); - - const history = { - repo: REPO, - slug: SLUG, - clawhub_created_at: new Date(createdAtMs).toISOString().slice(0, 10), - subtitle: "GitHub stars · ClawHub downloads — updated daily", - github_stars: ghDaily, - clawhub_downloads: chDaily, - sources: { - github: `https://github.com/${REPO}`, - clawhub: `https://clawhub.ai/${REPO.split("/")[0]}/${SLUG}`, - convex: CONVEX_URL, - }, - schema_version: 1, - }; - - await writeFile(HISTORY_PATH, JSON.stringify(history, null, 2) + "\n"); - console.log(`[seed] wrote ${HISTORY_PATH}`); -} - -main().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/.github/stats/update.mjs b/.github/stats/update.mjs deleted file mode 100644 index 4a41984..0000000 --- a/.github/stats/update.mjs +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env node -import { readFile, writeFile } from "node:fs/promises"; -import { fileURLToPath } from "node:url"; -import { dirname, join } from "node:path"; -import { execFileSync } from "node:child_process"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const HISTORY_PATH = join(__dirname, "history.json"); -const CONVEX_URL = "https://wry-manatee-359.convex.cloud"; - -function gh(args) { - return execFileSync("gh", args, { encoding: "utf8" }).trim(); -} - -async function fetchClawHubDownloads(slug) { - const res = await fetch(`${CONVEX_URL}/api/query`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "Convex-Client": "npm-1.20.0", - }, - body: JSON.stringify({ - path: "skills:getBySlug", - format: "convex_encoded_json", - args: [{ slug }], - }), - }); - if (!res.ok) throw new Error(`ClawHub HTTP ${res.status}: ${await res.text()}`); - const body = await res.json(); - if (body.status !== "success") { - throw new Error(`ClawHub error: ${body.errorMessage ?? "unknown"}`); - } - return Math.round(body.value.skill.stats.downloads ?? 0); -} - -function upsertPoint(series, iso, value) { - const last = series[series.length - 1]; - if (last && last[0] === iso) { - last[1] = value; - return series; - } - return [...series, [iso, value]]; -} - -async function main() { - const today = new Date().toISOString().slice(0, 10); - const raw = await readFile(HISTORY_PATH, "utf8"); - const history = JSON.parse(raw); - - console.log(`[update] repo=${history.repo} slug=${history.slug} today=${today}`); - - const ghStars = parseInt( - gh(["api", `repos/${history.repo}`, "--jq", ".stargazers_count"]), - 10, - ); - console.log(`[update] github stars=${ghStars}`); - - const chDownloads = await fetchClawHubDownloads(history.slug); - console.log(`[update] clawhub downloads=${chDownloads}`); - - history.github_stars = upsertPoint(history.github_stars, today, ghStars); - history.clawhub_downloads = upsertPoint( - history.clawhub_downloads, - today, - chDownloads, - ); - - await writeFile(HISTORY_PATH, JSON.stringify(history, null, 2) + "\n"); - console.log(`[update] wrote ${HISTORY_PATH}`); -} - -main().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/.github/workflows/stats.yml b/.github/workflows/stats.yml deleted file mode 100644 index 4ffcc5e..0000000 --- a/.github/workflows/stats.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: stats - -on: - schedule: - - cron: "17 6 * * *" - workflow_dispatch: {} - -permissions: - contents: write - -concurrency: - group: stats - cancel-in-progress: false - -jobs: - update: - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - ref: ${{ github.ref_name }} - - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "20" - - - name: Fetch latest stats and append history - env: - GH_TOKEN: ${{ github.token }} - run: node .github/stats/update.mjs - - - name: Regenerate chart SVGs - run: node .github/stats/generate.mjs - - - name: Commit and push if changed - run: | - if git diff --quiet -- .github/stats/; then - echo "No stats change." - exit 0 - fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add .github/stats/history.json .github/stats/chart-light.svg .github/stats/chart-dark.svg - git commit -m "chore(stats): refresh history and chart" - git push diff --git a/README.md b/README.md index b67bf87..d7af0e1 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,13 @@ agent-desktop architecture diagram

- - - - GitHub stars and ClawHub downloads for lahfir/agent-desktop - + + + + + Star history for lahfir/agent-desktop + + ## Key Features