mirror of
https://github.com/lahfir/agent-desktop.git
synced 2026-07-26 17:12:15 +00:00
chore(stats): drop self-hosted chart pipeline; embed star-history.com
The custom SVG chart, daily cron, history.json, peter-evans PR
pattern, and AUTOMERGE_PAT are all gone. Replaced by a one-line
star-history.com embed inside <picture> for native light/dark.
Why the rollback:
- The chart was never meant to require a workflow + protected-branch
bypass + admin PAT to keep ticking
- ClawHub history was always linearly backfilled (the marketplace
doesn't expose history); GitHub stars is the only metric with a
real timeline anyway
- star-history.com renders the same chart, free, no infra, used by
thousands of OSS repos
Removes:
- .github/workflows/stats.yml
- .github/stats/{generate,seed,update}.mjs
- .github/stats/history.json
- .github/stats/chart-{light,dark}.svg
Stays:
- README header + badges (current ClawHub/npm/release values are
already covered by shields.io badges in the header)
This commit is contained in:
parent
bf3722503b
commit
8e36e9fc7f
8 changed files with 7 additions and 1348 deletions
111
.github/stats/chart-dark.svg
vendored
111
.github/stats/chart-dark.svg
vendored
|
|
@ -1,111 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 420" width="1200" height="420" preserveAspectRatio="xMidYMid meet" role="img" aria-labelledby="title desc">
|
||||
<title id="title">lahfir/agent-desktop — GitHub stars and ClawHub downloads over time</title>
|
||||
<desc id="desc">Time-series chart showing GitHub stars and ClawHub downloads for lahfir/agent-desktop.</desc>
|
||||
<defs>
|
||||
<linearGradient id="fill1" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#58a6ff" stop-opacity="0.28"/>
|
||||
<stop offset="100%" stop-color="#58a6ff" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="fill2" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ff7b35" stop-opacity="0.28"/>
|
||||
<stop offset="100%" stop-color="#ff7b35" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="stroke1" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#58a6ff"/>
|
||||
<stop offset="100%" stop-color="#a5d6ff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="stroke2" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#ff7b35"/>
|
||||
<stop offset="100%" stop-color="#ffa657"/>
|
||||
</linearGradient>
|
||||
<filter id="glow1" x="-10%" y="-50%" width="120%" height="200%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 0.345 0 0 0 0 0.651 0 0 0 0 1.000 0 0 0 0.32 0" result="coloredGlow"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredGlow"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<filter id="glow2" x="-10%" y="-50%" width="120%" height="200%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 1.000 0 0 0 0 0.482 0 0 0 0 0.208 0 0 0 0.32 0" result="coloredGlow"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredGlow"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<clipPath id="plot-clip">
|
||||
<rect x="72" y="72" width="1056" height="296"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect width="100%" height="100%" fill="#0d1117"/>
|
||||
<rect x="0.5" y="0.5" width="1199" height="419" fill="none" stroke="#30363d" stroke-width="1" rx="8" ry="8"/>
|
||||
|
||||
<text x="72" y="30" fill="#e6edf3" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="18" font-weight="600">
|
||||
lahfir/agent-desktop
|
||||
</text>
|
||||
<text x="72" y="50" fill="#8b949e" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="12" font-weight="400">
|
||||
GitHub stars · ClawHub downloads — updated daily
|
||||
</text>
|
||||
|
||||
<g transform="translate(1128, 30)" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="14" font-weight="600" style="font-variant-numeric: tabular-nums;">
|
||||
<text fill="#58a6ff">★ 89 <tspan fill="#8b949e" font-weight="400" font-size="11">GitHub</tspan></text>
|
||||
<text y="20" fill="#ff7b35">⬇ 510 <tspan fill="#8b949e" font-weight="400" font-size="11">ClawHub</tspan></text>
|
||||
</g>
|
||||
|
||||
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#8b949e" style="font-variant-numeric: tabular-nums;">
|
||||
<text x="64" y="367.00" text-anchor="end" fill="#58a6ff" opacity="0.85">0</text>
|
||||
<line x1="72" x2="1128" y1="292.00" y2="292.00" stroke="#21262d" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="295.00" text-anchor="end" fill="#58a6ff" opacity="0.85">25</text>
|
||||
<line x1="72" x2="1128" y1="220.00" y2="220.00" stroke="#21262d" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="223.00" text-anchor="end" fill="#58a6ff" opacity="0.85">50</text>
|
||||
<line x1="72" x2="1128" y1="148.00" y2="148.00" stroke="#21262d" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="151.00" text-anchor="end" fill="#58a6ff" opacity="0.85">75</text>
|
||||
<line x1="72" x2="1128" y1="76.00" y2="76.00" stroke="#21262d" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="79.00" text-anchor="end" fill="#58a6ff" opacity="0.85">100</text>
|
||||
</g>
|
||||
|
||||
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#ff7b35" opacity="0.85" style="font-variant-numeric: tabular-nums;">
|
||||
<text x="1136" y="367.00" text-anchor="start">0</text>
|
||||
<text x="1136" y="295.00" text-anchor="start">250</text>
|
||||
<text x="1136" y="223.00" text-anchor="start">500</text>
|
||||
<text x="1136" y="151.00" text-anchor="start">750</text>
|
||||
<text x="1136" y="79.00" text-anchor="start">1.0k</text>
|
||||
</g>
|
||||
|
||||
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#8b949e" style="font-variant-numeric: tabular-nums;">
|
||||
<text x="72.00" y="382" text-anchor="middle">Feb 21</text>
|
||||
<text x="289.90" y="382" text-anchor="middle">Mar 6</text>
|
||||
<text x="491.05" y="382" text-anchor="middle">Mar 18</text>
|
||||
<text x="708.95" y="382" text-anchor="middle">Mar 31</text>
|
||||
<text x="910.10" y="382" text-anchor="middle">Apr 12</text>
|
||||
<text x="1128.00" y="382" text-anchor="middle">Apr 25</text>
|
||||
</g>
|
||||
|
||||
<line x1="72" x2="1128" y1="364" y2="364" stroke="#30363d" stroke-width="1" opacity="0.8"/>
|
||||
|
||||
<g clip-path="url(#plot-clip)">
|
||||
<path d="M 72.00 358.24 C 74.79 358.24, 83.17 358.72, 88.76 358.24 C 94.35 357.76, 99.94 355.84, 105.52 355.36 C 111.11 354.88, 116.70 355.36, 122.29 355.36 C 127.87 355.36, 133.46 355.84, 139.05 355.36 C 144.63 354.88, 150.22 352.96, 155.81 352.48 C 161.40 352.00, 166.98 352.48, 172.57 352.48 C 178.16 352.48, 183.75 354.40, 189.33 352.48 C 194.92 350.56, 200.51 343.84, 206.10 340.96 C 211.68 338.08, 217.27 337.12, 222.86 335.20 C 228.44 333.28, 234.03 332.32, 239.62 329.44 C 245.21 326.56, 250.79 319.84, 256.38 317.92 C 261.97 316.00, 267.56 317.92, 273.14 317.92 C 278.73 317.92, 284.32 319.84, 289.90 317.92 C 295.49 316.00, 301.08 308.80, 306.67 306.40 C 312.25 304.00, 317.84 304.96, 323.43 303.52 C 329.02 302.08, 334.60 301.12, 340.19 297.76 C 345.78 294.40, 351.37 285.76, 356.95 283.36 C 362.54 280.96, 368.13 285.28, 373.71 283.36 C 379.30 281.44, 384.89 273.76, 390.48 271.84 C 396.06 269.92, 401.65 271.84, 407.24 271.84 C 412.83 271.84, 418.41 271.84, 424.00 271.84 C 429.59 271.84, 435.17 271.84, 440.76 271.84 C 446.35 271.84, 451.94 271.84, 457.52 271.84 C 463.11 271.84, 468.70 271.84, 474.29 271.84 C 479.87 271.84, 485.46 272.32, 491.05 271.84 C 496.63 271.36, 502.22 269.44, 507.81 268.96 C 513.40 268.48, 518.98 268.96, 524.57 268.96 C 530.16 268.96, 535.75 268.96, 541.33 268.96 C 546.92 268.96, 552.51 268.96, 558.10 268.96 C 563.68 268.96, 569.27 268.96, 574.86 268.96 C 580.44 268.96, 586.03 268.96, 591.62 268.96 C 597.21 268.96, 602.79 268.96, 608.38 268.96 C 613.97 268.96, 619.56 268.96, 625.14 268.96 C 630.73 268.96, 636.32 269.44, 641.90 268.96 C 647.49 268.48, 653.08 266.56, 658.67 266.08 C 664.25 265.60, 669.84 266.08, 675.43 266.08 C 681.02 266.08, 686.60 266.08, 692.19 266.08 C 697.78 266.08, 703.37 267.04, 708.95 266.08 C 714.54 265.12, 720.13 261.28, 725.71 260.32 C 731.30 259.36, 736.89 260.80, 742.48 260.32 C 748.06 259.84, 753.65 257.92, 759.24 257.44 C 764.83 256.96, 770.41 258.88, 776.00 257.44 C 781.59 256.00, 787.17 251.68, 792.76 248.80 C 798.35 245.92, 803.94 242.08, 809.52 240.16 C 815.11 238.24, 820.70 237.76, 826.29 237.28 C 831.87 236.80, 837.46 237.28, 843.05 237.28 C 848.63 237.28, 854.22 237.28, 859.81 237.28 C 865.40 237.28, 870.98 237.76, 876.57 237.28 C 882.16 236.80, 887.75 235.36, 893.33 234.40 C 898.92 233.44, 904.51 233.92, 910.10 231.52 C 915.68 229.12, 921.27 225.76, 926.86 220.00 C 932.44 214.24, 938.03 204.64, 943.62 196.96 C 949.21 189.28, 954.79 178.24, 960.38 173.92 C 965.97 169.60, 971.56 172.00, 977.14 171.04 C 982.73 170.08, 988.32 168.64, 993.90 168.16 C 999.49 167.68, 1005.08 168.16, 1010.67 168.16 C 1016.25 168.16, 1021.84 168.16, 1027.43 168.16 C 1033.02 168.16, 1038.60 169.12, 1044.19 168.16 C 1049.78 167.20, 1055.37 163.36, 1060.95 162.40 C 1066.54 161.44, 1072.13 162.40, 1077.71 162.40 C 1083.30 162.40, 1088.89 170.08, 1094.48 162.40 C 1100.06 154.72, 1105.65 125.44, 1111.24 116.32 C 1116.83 107.20, 1125.21 109.12, 1128.00 107.68 L 1128.00 364.00 L 72.00 364.00 Z" fill="url(#fill1)" stroke="none"/>
|
||||
<path d="M 239.62 364.00 C 242.41 363.52, 250.79 362.03, 256.38 361.12 C 261.97 360.21, 267.56 359.44, 273.14 358.53 C 278.73 357.62, 284.32 356.56, 289.90 355.65 C 295.49 354.74, 301.08 353.97, 306.67 353.06 C 312.25 352.14, 317.84 351.14, 323.43 350.18 C 329.02 349.22, 334.60 348.21, 340.19 347.30 C 345.78 346.38, 351.37 345.62, 356.95 344.70 C 362.54 343.79, 368.13 342.78, 373.71 341.82 C 379.30 340.86, 384.89 339.86, 390.48 338.94 C 396.06 338.03, 401.65 337.26, 407.24 336.35 C 412.83 335.44, 418.41 334.38, 424.00 333.47 C 429.59 332.56, 435.17 331.79, 440.76 330.88 C 446.35 329.97, 451.94 328.96, 457.52 328.00 C 463.11 327.04, 468.70 326.03, 474.29 325.12 C 479.87 324.21, 485.46 323.44, 491.05 322.53 C 496.63 321.62, 502.22 320.61, 507.81 319.65 C 513.40 318.69, 518.98 317.68, 524.57 316.77 C 530.16 315.86, 535.75 315.09, 541.33 314.18 C 546.92 313.26, 552.51 312.21, 558.10 311.30 C 563.68 310.38, 569.27 309.62, 574.86 308.70 C 580.44 307.79, 586.03 306.78, 591.62 305.82 C 597.21 304.86, 602.79 303.86, 608.38 302.94 C 613.97 302.03, 619.56 301.26, 625.14 300.35 C 630.73 299.44, 636.32 298.43, 641.90 297.47 C 647.49 296.51, 653.08 295.50, 658.67 294.59 C 664.25 293.68, 669.84 292.91, 675.43 292.00 C 681.02 291.09, 686.60 290.03, 692.19 289.12 C 697.78 288.21, 703.37 287.44, 708.95 286.53 C 714.54 285.62, 720.13 284.61, 725.71 283.65 C 731.30 282.69, 736.89 281.68, 742.48 280.77 C 748.06 279.86, 753.65 279.09, 759.24 278.18 C 764.83 277.26, 770.41 276.26, 776.00 275.30 C 781.59 274.34, 787.17 273.33, 792.76 272.42 C 798.35 271.50, 803.94 270.74, 809.52 269.82 C 815.11 268.91, 820.70 267.86, 826.29 266.94 C 831.87 266.03, 837.46 265.26, 843.05 264.35 C 848.63 263.44, 854.22 262.43, 859.81 261.47 C 865.40 260.51, 870.98 259.50, 876.57 258.59 C 882.16 257.68, 887.75 256.91, 893.33 256.00 C 898.92 255.09, 904.51 254.08, 910.10 253.12 C 915.68 252.16, 921.27 251.15, 926.86 250.24 C 932.44 249.33, 938.03 248.56, 943.62 247.65 C 949.21 246.74, 954.79 245.68, 960.38 244.77 C 965.97 243.86, 971.56 243.09, 977.14 242.18 C 982.73 241.26, 988.32 240.26, 993.90 239.30 C 999.49 238.34, 1005.08 237.33, 1010.67 236.42 C 1016.25 235.50, 1021.84 234.74, 1027.43 233.82 C 1033.02 232.91, 1038.60 231.90, 1044.19 230.94 C 1049.78 229.98, 1055.37 228.98, 1060.95 228.06 C 1066.54 227.15, 1072.13 226.38, 1077.71 225.47 C 1083.30 224.56, 1088.89 223.50, 1094.48 222.59 C 1100.06 221.68, 1105.65 220.91, 1111.24 220.00 C 1116.83 219.09, 1125.21 217.60, 1128.00 217.12 L 1128.00 364.00 L 239.62 364.00 Z" fill="url(#fill2)" stroke="none"/>
|
||||
|
||||
<path d="M 72.00 358.24 C 74.79 358.24, 83.17 358.72, 88.76 358.24 C 94.35 357.76, 99.94 355.84, 105.52 355.36 C 111.11 354.88, 116.70 355.36, 122.29 355.36 C 127.87 355.36, 133.46 355.84, 139.05 355.36 C 144.63 354.88, 150.22 352.96, 155.81 352.48 C 161.40 352.00, 166.98 352.48, 172.57 352.48 C 178.16 352.48, 183.75 354.40, 189.33 352.48 C 194.92 350.56, 200.51 343.84, 206.10 340.96 C 211.68 338.08, 217.27 337.12, 222.86 335.20 C 228.44 333.28, 234.03 332.32, 239.62 329.44 C 245.21 326.56, 250.79 319.84, 256.38 317.92 C 261.97 316.00, 267.56 317.92, 273.14 317.92 C 278.73 317.92, 284.32 319.84, 289.90 317.92 C 295.49 316.00, 301.08 308.80, 306.67 306.40 C 312.25 304.00, 317.84 304.96, 323.43 303.52 C 329.02 302.08, 334.60 301.12, 340.19 297.76 C 345.78 294.40, 351.37 285.76, 356.95 283.36 C 362.54 280.96, 368.13 285.28, 373.71 283.36 C 379.30 281.44, 384.89 273.76, 390.48 271.84 C 396.06 269.92, 401.65 271.84, 407.24 271.84 C 412.83 271.84, 418.41 271.84, 424.00 271.84 C 429.59 271.84, 435.17 271.84, 440.76 271.84 C 446.35 271.84, 451.94 271.84, 457.52 271.84 C 463.11 271.84, 468.70 271.84, 474.29 271.84 C 479.87 271.84, 485.46 272.32, 491.05 271.84 C 496.63 271.36, 502.22 269.44, 507.81 268.96 C 513.40 268.48, 518.98 268.96, 524.57 268.96 C 530.16 268.96, 535.75 268.96, 541.33 268.96 C 546.92 268.96, 552.51 268.96, 558.10 268.96 C 563.68 268.96, 569.27 268.96, 574.86 268.96 C 580.44 268.96, 586.03 268.96, 591.62 268.96 C 597.21 268.96, 602.79 268.96, 608.38 268.96 C 613.97 268.96, 619.56 268.96, 625.14 268.96 C 630.73 268.96, 636.32 269.44, 641.90 268.96 C 647.49 268.48, 653.08 266.56, 658.67 266.08 C 664.25 265.60, 669.84 266.08, 675.43 266.08 C 681.02 266.08, 686.60 266.08, 692.19 266.08 C 697.78 266.08, 703.37 267.04, 708.95 266.08 C 714.54 265.12, 720.13 261.28, 725.71 260.32 C 731.30 259.36, 736.89 260.80, 742.48 260.32 C 748.06 259.84, 753.65 257.92, 759.24 257.44 C 764.83 256.96, 770.41 258.88, 776.00 257.44 C 781.59 256.00, 787.17 251.68, 792.76 248.80 C 798.35 245.92, 803.94 242.08, 809.52 240.16 C 815.11 238.24, 820.70 237.76, 826.29 237.28 C 831.87 236.80, 837.46 237.28, 843.05 237.28 C 848.63 237.28, 854.22 237.28, 859.81 237.28 C 865.40 237.28, 870.98 237.76, 876.57 237.28 C 882.16 236.80, 887.75 235.36, 893.33 234.40 C 898.92 233.44, 904.51 233.92, 910.10 231.52 C 915.68 229.12, 921.27 225.76, 926.86 220.00 C 932.44 214.24, 938.03 204.64, 943.62 196.96 C 949.21 189.28, 954.79 178.24, 960.38 173.92 C 965.97 169.60, 971.56 172.00, 977.14 171.04 C 982.73 170.08, 988.32 168.64, 993.90 168.16 C 999.49 167.68, 1005.08 168.16, 1010.67 168.16 C 1016.25 168.16, 1021.84 168.16, 1027.43 168.16 C 1033.02 168.16, 1038.60 169.12, 1044.19 168.16 C 1049.78 167.20, 1055.37 163.36, 1060.95 162.40 C 1066.54 161.44, 1072.13 162.40, 1077.71 162.40 C 1083.30 162.40, 1088.89 170.08, 1094.48 162.40 C 1100.06 154.72, 1105.65 125.44, 1111.24 116.32 C 1116.83 107.20, 1125.21 109.12, 1128.00 107.68" fill="none" stroke="url(#stroke1)" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow1)" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100">
|
||||
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.4s" begin="0s" fill="freeze" calcMode="spline" keySplines="0.4 0 0.2 1" keyTimes="0;1" values="100;0"/>
|
||||
</path>
|
||||
|
||||
<path d="M 239.62 364.00 C 242.41 363.52, 250.79 362.03, 256.38 361.12 C 261.97 360.21, 267.56 359.44, 273.14 358.53 C 278.73 357.62, 284.32 356.56, 289.90 355.65 C 295.49 354.74, 301.08 353.97, 306.67 353.06 C 312.25 352.14, 317.84 351.14, 323.43 350.18 C 329.02 349.22, 334.60 348.21, 340.19 347.30 C 345.78 346.38, 351.37 345.62, 356.95 344.70 C 362.54 343.79, 368.13 342.78, 373.71 341.82 C 379.30 340.86, 384.89 339.86, 390.48 338.94 C 396.06 338.03, 401.65 337.26, 407.24 336.35 C 412.83 335.44, 418.41 334.38, 424.00 333.47 C 429.59 332.56, 435.17 331.79, 440.76 330.88 C 446.35 329.97, 451.94 328.96, 457.52 328.00 C 463.11 327.04, 468.70 326.03, 474.29 325.12 C 479.87 324.21, 485.46 323.44, 491.05 322.53 C 496.63 321.62, 502.22 320.61, 507.81 319.65 C 513.40 318.69, 518.98 317.68, 524.57 316.77 C 530.16 315.86, 535.75 315.09, 541.33 314.18 C 546.92 313.26, 552.51 312.21, 558.10 311.30 C 563.68 310.38, 569.27 309.62, 574.86 308.70 C 580.44 307.79, 586.03 306.78, 591.62 305.82 C 597.21 304.86, 602.79 303.86, 608.38 302.94 C 613.97 302.03, 619.56 301.26, 625.14 300.35 C 630.73 299.44, 636.32 298.43, 641.90 297.47 C 647.49 296.51, 653.08 295.50, 658.67 294.59 C 664.25 293.68, 669.84 292.91, 675.43 292.00 C 681.02 291.09, 686.60 290.03, 692.19 289.12 C 697.78 288.21, 703.37 287.44, 708.95 286.53 C 714.54 285.62, 720.13 284.61, 725.71 283.65 C 731.30 282.69, 736.89 281.68, 742.48 280.77 C 748.06 279.86, 753.65 279.09, 759.24 278.18 C 764.83 277.26, 770.41 276.26, 776.00 275.30 C 781.59 274.34, 787.17 273.33, 792.76 272.42 C 798.35 271.50, 803.94 270.74, 809.52 269.82 C 815.11 268.91, 820.70 267.86, 826.29 266.94 C 831.87 266.03, 837.46 265.26, 843.05 264.35 C 848.63 263.44, 854.22 262.43, 859.81 261.47 C 865.40 260.51, 870.98 259.50, 876.57 258.59 C 882.16 257.68, 887.75 256.91, 893.33 256.00 C 898.92 255.09, 904.51 254.08, 910.10 253.12 C 915.68 252.16, 921.27 251.15, 926.86 250.24 C 932.44 249.33, 938.03 248.56, 943.62 247.65 C 949.21 246.74, 954.79 245.68, 960.38 244.77 C 965.97 243.86, 971.56 243.09, 977.14 242.18 C 982.73 241.26, 988.32 240.26, 993.90 239.30 C 999.49 238.34, 1005.08 237.33, 1010.67 236.42 C 1016.25 235.50, 1021.84 234.74, 1027.43 233.82 C 1033.02 232.91, 1038.60 231.90, 1044.19 230.94 C 1049.78 229.98, 1055.37 228.98, 1060.95 228.06 C 1066.54 227.15, 1072.13 226.38, 1077.71 225.47 C 1083.30 224.56, 1088.89 223.50, 1094.48 222.59 C 1100.06 221.68, 1105.65 220.91, 1111.24 220.00 C 1116.83 219.09, 1125.21 217.60, 1128.00 217.12" fill="none" stroke="url(#stroke2)" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow2)" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100">
|
||||
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.4s" begin="0.15s" fill="freeze" calcMode="spline" keySplines="0.4 0 0.2 1" keyTimes="0;1" values="100;0"/>
|
||||
</path>
|
||||
|
||||
<g opacity="0">
|
||||
<circle cx="1128.00" cy="107.68" r="7" fill="#58a6ff" opacity="0.22"/>
|
||||
<circle cx="1128.00" cy="107.68" r="4" fill="#0d1117" stroke="#58a6ff" stroke-width="2"/>
|
||||
<animate attributeName="opacity" from="0" to="1" begin="1.4s" dur="0.4s" fill="freeze"/>
|
||||
</g>
|
||||
<g opacity="0">
|
||||
<circle cx="1128.00" cy="217.12" r="7" fill="#ff7b35" opacity="0.22"/>
|
||||
<circle cx="1128.00" cy="217.12" r="4" fill="#0d1117" stroke="#ff7b35" stroke-width="2"/>
|
||||
<animate attributeName="opacity" from="0" to="1" begin="1.55s" dur="0.4s" fill="freeze"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<text x="1128" y="408" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#8b949e" opacity="0.7">
|
||||
Updated 2026-04-25
|
||||
</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 18 KiB |
111
.github/stats/chart-light.svg
vendored
111
.github/stats/chart-light.svg
vendored
|
|
@ -1,111 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 420" width="1200" height="420" preserveAspectRatio="xMidYMid meet" role="img" aria-labelledby="title desc">
|
||||
<title id="title">lahfir/agent-desktop — GitHub stars and ClawHub downloads over time</title>
|
||||
<desc id="desc">Time-series chart showing GitHub stars and ClawHub downloads for lahfir/agent-desktop.</desc>
|
||||
<defs>
|
||||
<linearGradient id="fill1" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#0969da" stop-opacity="0.18"/>
|
||||
<stop offset="100%" stop-color="#0969da" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="fill2" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#bc4c00" stop-opacity="0.18"/>
|
||||
<stop offset="100%" stop-color="#bc4c00" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="stroke1" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#0969da"/>
|
||||
<stop offset="100%" stop-color="#54aeff"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="stroke2" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#bc4c00"/>
|
||||
<stop offset="100%" stop-color="#fb8500"/>
|
||||
</linearGradient>
|
||||
<filter id="glow1" x="-10%" y="-50%" width="120%" height="200%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 0.035 0 0 0 0 0.412 0 0 0 0 0.855 0 0 0 0.18 0" result="coloredGlow"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredGlow"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<filter id="glow2" x="-10%" y="-50%" width="120%" height="200%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 0.737 0 0 0 0 0.298 0 0 0 0 0.000 0 0 0 0.18 0" result="coloredGlow"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredGlow"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<clipPath id="plot-clip">
|
||||
<rect x="72" y="72" width="1056" height="296"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect width="100%" height="100%" fill="#ffffff"/>
|
||||
<rect x="0.5" y="0.5" width="1199" height="419" fill="none" stroke="#d0d7de" stroke-width="1" rx="8" ry="8"/>
|
||||
|
||||
<text x="72" y="30" fill="#1f2328" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="18" font-weight="600">
|
||||
lahfir/agent-desktop
|
||||
</text>
|
||||
<text x="72" y="50" fill="#656d76" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="12" font-weight="400">
|
||||
GitHub stars · ClawHub downloads — updated daily
|
||||
</text>
|
||||
|
||||
<g transform="translate(1128, 30)" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="14" font-weight="600" style="font-variant-numeric: tabular-nums;">
|
||||
<text fill="#0969da">★ 89 <tspan fill="#656d76" font-weight="400" font-size="11">GitHub</tspan></text>
|
||||
<text y="20" fill="#bc4c00">⬇ 510 <tspan fill="#656d76" font-weight="400" font-size="11">ClawHub</tspan></text>
|
||||
</g>
|
||||
|
||||
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#656d76" style="font-variant-numeric: tabular-nums;">
|
||||
<text x="64" y="367.00" text-anchor="end" fill="#0969da" opacity="0.85">0</text>
|
||||
<line x1="72" x2="1128" y1="292.00" y2="292.00" stroke="#d0d7de" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="295.00" text-anchor="end" fill="#0969da" opacity="0.85">25</text>
|
||||
<line x1="72" x2="1128" y1="220.00" y2="220.00" stroke="#d0d7de" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="223.00" text-anchor="end" fill="#0969da" opacity="0.85">50</text>
|
||||
<line x1="72" x2="1128" y1="148.00" y2="148.00" stroke="#d0d7de" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="151.00" text-anchor="end" fill="#0969da" opacity="0.85">75</text>
|
||||
<line x1="72" x2="1128" y1="76.00" y2="76.00" stroke="#d0d7de" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/><text x="64" y="79.00" text-anchor="end" fill="#0969da" opacity="0.85">100</text>
|
||||
</g>
|
||||
|
||||
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#bc4c00" opacity="0.85" style="font-variant-numeric: tabular-nums;">
|
||||
<text x="1136" y="367.00" text-anchor="start">0</text>
|
||||
<text x="1136" y="295.00" text-anchor="start">250</text>
|
||||
<text x="1136" y="223.00" text-anchor="start">500</text>
|
||||
<text x="1136" y="151.00" text-anchor="start">750</text>
|
||||
<text x="1136" y="79.00" text-anchor="start">1.0k</text>
|
||||
</g>
|
||||
|
||||
<g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#656d76" style="font-variant-numeric: tabular-nums;">
|
||||
<text x="72.00" y="382" text-anchor="middle">Feb 21</text>
|
||||
<text x="289.90" y="382" text-anchor="middle">Mar 6</text>
|
||||
<text x="491.05" y="382" text-anchor="middle">Mar 18</text>
|
||||
<text x="708.95" y="382" text-anchor="middle">Mar 31</text>
|
||||
<text x="910.10" y="382" text-anchor="middle">Apr 12</text>
|
||||
<text x="1128.00" y="382" text-anchor="middle">Apr 25</text>
|
||||
</g>
|
||||
|
||||
<line x1="72" x2="1128" y1="364" y2="364" stroke="#d0d7de" stroke-width="1" opacity="0.8"/>
|
||||
|
||||
<g clip-path="url(#plot-clip)">
|
||||
<path d="M 72.00 358.24 C 74.79 358.24, 83.17 358.72, 88.76 358.24 C 94.35 357.76, 99.94 355.84, 105.52 355.36 C 111.11 354.88, 116.70 355.36, 122.29 355.36 C 127.87 355.36, 133.46 355.84, 139.05 355.36 C 144.63 354.88, 150.22 352.96, 155.81 352.48 C 161.40 352.00, 166.98 352.48, 172.57 352.48 C 178.16 352.48, 183.75 354.40, 189.33 352.48 C 194.92 350.56, 200.51 343.84, 206.10 340.96 C 211.68 338.08, 217.27 337.12, 222.86 335.20 C 228.44 333.28, 234.03 332.32, 239.62 329.44 C 245.21 326.56, 250.79 319.84, 256.38 317.92 C 261.97 316.00, 267.56 317.92, 273.14 317.92 C 278.73 317.92, 284.32 319.84, 289.90 317.92 C 295.49 316.00, 301.08 308.80, 306.67 306.40 C 312.25 304.00, 317.84 304.96, 323.43 303.52 C 329.02 302.08, 334.60 301.12, 340.19 297.76 C 345.78 294.40, 351.37 285.76, 356.95 283.36 C 362.54 280.96, 368.13 285.28, 373.71 283.36 C 379.30 281.44, 384.89 273.76, 390.48 271.84 C 396.06 269.92, 401.65 271.84, 407.24 271.84 C 412.83 271.84, 418.41 271.84, 424.00 271.84 C 429.59 271.84, 435.17 271.84, 440.76 271.84 C 446.35 271.84, 451.94 271.84, 457.52 271.84 C 463.11 271.84, 468.70 271.84, 474.29 271.84 C 479.87 271.84, 485.46 272.32, 491.05 271.84 C 496.63 271.36, 502.22 269.44, 507.81 268.96 C 513.40 268.48, 518.98 268.96, 524.57 268.96 C 530.16 268.96, 535.75 268.96, 541.33 268.96 C 546.92 268.96, 552.51 268.96, 558.10 268.96 C 563.68 268.96, 569.27 268.96, 574.86 268.96 C 580.44 268.96, 586.03 268.96, 591.62 268.96 C 597.21 268.96, 602.79 268.96, 608.38 268.96 C 613.97 268.96, 619.56 268.96, 625.14 268.96 C 630.73 268.96, 636.32 269.44, 641.90 268.96 C 647.49 268.48, 653.08 266.56, 658.67 266.08 C 664.25 265.60, 669.84 266.08, 675.43 266.08 C 681.02 266.08, 686.60 266.08, 692.19 266.08 C 697.78 266.08, 703.37 267.04, 708.95 266.08 C 714.54 265.12, 720.13 261.28, 725.71 260.32 C 731.30 259.36, 736.89 260.80, 742.48 260.32 C 748.06 259.84, 753.65 257.92, 759.24 257.44 C 764.83 256.96, 770.41 258.88, 776.00 257.44 C 781.59 256.00, 787.17 251.68, 792.76 248.80 C 798.35 245.92, 803.94 242.08, 809.52 240.16 C 815.11 238.24, 820.70 237.76, 826.29 237.28 C 831.87 236.80, 837.46 237.28, 843.05 237.28 C 848.63 237.28, 854.22 237.28, 859.81 237.28 C 865.40 237.28, 870.98 237.76, 876.57 237.28 C 882.16 236.80, 887.75 235.36, 893.33 234.40 C 898.92 233.44, 904.51 233.92, 910.10 231.52 C 915.68 229.12, 921.27 225.76, 926.86 220.00 C 932.44 214.24, 938.03 204.64, 943.62 196.96 C 949.21 189.28, 954.79 178.24, 960.38 173.92 C 965.97 169.60, 971.56 172.00, 977.14 171.04 C 982.73 170.08, 988.32 168.64, 993.90 168.16 C 999.49 167.68, 1005.08 168.16, 1010.67 168.16 C 1016.25 168.16, 1021.84 168.16, 1027.43 168.16 C 1033.02 168.16, 1038.60 169.12, 1044.19 168.16 C 1049.78 167.20, 1055.37 163.36, 1060.95 162.40 C 1066.54 161.44, 1072.13 162.40, 1077.71 162.40 C 1083.30 162.40, 1088.89 170.08, 1094.48 162.40 C 1100.06 154.72, 1105.65 125.44, 1111.24 116.32 C 1116.83 107.20, 1125.21 109.12, 1128.00 107.68 L 1128.00 364.00 L 72.00 364.00 Z" fill="url(#fill1)" stroke="none"/>
|
||||
<path d="M 239.62 364.00 C 242.41 363.52, 250.79 362.03, 256.38 361.12 C 261.97 360.21, 267.56 359.44, 273.14 358.53 C 278.73 357.62, 284.32 356.56, 289.90 355.65 C 295.49 354.74, 301.08 353.97, 306.67 353.06 C 312.25 352.14, 317.84 351.14, 323.43 350.18 C 329.02 349.22, 334.60 348.21, 340.19 347.30 C 345.78 346.38, 351.37 345.62, 356.95 344.70 C 362.54 343.79, 368.13 342.78, 373.71 341.82 C 379.30 340.86, 384.89 339.86, 390.48 338.94 C 396.06 338.03, 401.65 337.26, 407.24 336.35 C 412.83 335.44, 418.41 334.38, 424.00 333.47 C 429.59 332.56, 435.17 331.79, 440.76 330.88 C 446.35 329.97, 451.94 328.96, 457.52 328.00 C 463.11 327.04, 468.70 326.03, 474.29 325.12 C 479.87 324.21, 485.46 323.44, 491.05 322.53 C 496.63 321.62, 502.22 320.61, 507.81 319.65 C 513.40 318.69, 518.98 317.68, 524.57 316.77 C 530.16 315.86, 535.75 315.09, 541.33 314.18 C 546.92 313.26, 552.51 312.21, 558.10 311.30 C 563.68 310.38, 569.27 309.62, 574.86 308.70 C 580.44 307.79, 586.03 306.78, 591.62 305.82 C 597.21 304.86, 602.79 303.86, 608.38 302.94 C 613.97 302.03, 619.56 301.26, 625.14 300.35 C 630.73 299.44, 636.32 298.43, 641.90 297.47 C 647.49 296.51, 653.08 295.50, 658.67 294.59 C 664.25 293.68, 669.84 292.91, 675.43 292.00 C 681.02 291.09, 686.60 290.03, 692.19 289.12 C 697.78 288.21, 703.37 287.44, 708.95 286.53 C 714.54 285.62, 720.13 284.61, 725.71 283.65 C 731.30 282.69, 736.89 281.68, 742.48 280.77 C 748.06 279.86, 753.65 279.09, 759.24 278.18 C 764.83 277.26, 770.41 276.26, 776.00 275.30 C 781.59 274.34, 787.17 273.33, 792.76 272.42 C 798.35 271.50, 803.94 270.74, 809.52 269.82 C 815.11 268.91, 820.70 267.86, 826.29 266.94 C 831.87 266.03, 837.46 265.26, 843.05 264.35 C 848.63 263.44, 854.22 262.43, 859.81 261.47 C 865.40 260.51, 870.98 259.50, 876.57 258.59 C 882.16 257.68, 887.75 256.91, 893.33 256.00 C 898.92 255.09, 904.51 254.08, 910.10 253.12 C 915.68 252.16, 921.27 251.15, 926.86 250.24 C 932.44 249.33, 938.03 248.56, 943.62 247.65 C 949.21 246.74, 954.79 245.68, 960.38 244.77 C 965.97 243.86, 971.56 243.09, 977.14 242.18 C 982.73 241.26, 988.32 240.26, 993.90 239.30 C 999.49 238.34, 1005.08 237.33, 1010.67 236.42 C 1016.25 235.50, 1021.84 234.74, 1027.43 233.82 C 1033.02 232.91, 1038.60 231.90, 1044.19 230.94 C 1049.78 229.98, 1055.37 228.98, 1060.95 228.06 C 1066.54 227.15, 1072.13 226.38, 1077.71 225.47 C 1083.30 224.56, 1088.89 223.50, 1094.48 222.59 C 1100.06 221.68, 1105.65 220.91, 1111.24 220.00 C 1116.83 219.09, 1125.21 217.60, 1128.00 217.12 L 1128.00 364.00 L 239.62 364.00 Z" fill="url(#fill2)" stroke="none"/>
|
||||
|
||||
<path d="M 72.00 358.24 C 74.79 358.24, 83.17 358.72, 88.76 358.24 C 94.35 357.76, 99.94 355.84, 105.52 355.36 C 111.11 354.88, 116.70 355.36, 122.29 355.36 C 127.87 355.36, 133.46 355.84, 139.05 355.36 C 144.63 354.88, 150.22 352.96, 155.81 352.48 C 161.40 352.00, 166.98 352.48, 172.57 352.48 C 178.16 352.48, 183.75 354.40, 189.33 352.48 C 194.92 350.56, 200.51 343.84, 206.10 340.96 C 211.68 338.08, 217.27 337.12, 222.86 335.20 C 228.44 333.28, 234.03 332.32, 239.62 329.44 C 245.21 326.56, 250.79 319.84, 256.38 317.92 C 261.97 316.00, 267.56 317.92, 273.14 317.92 C 278.73 317.92, 284.32 319.84, 289.90 317.92 C 295.49 316.00, 301.08 308.80, 306.67 306.40 C 312.25 304.00, 317.84 304.96, 323.43 303.52 C 329.02 302.08, 334.60 301.12, 340.19 297.76 C 345.78 294.40, 351.37 285.76, 356.95 283.36 C 362.54 280.96, 368.13 285.28, 373.71 283.36 C 379.30 281.44, 384.89 273.76, 390.48 271.84 C 396.06 269.92, 401.65 271.84, 407.24 271.84 C 412.83 271.84, 418.41 271.84, 424.00 271.84 C 429.59 271.84, 435.17 271.84, 440.76 271.84 C 446.35 271.84, 451.94 271.84, 457.52 271.84 C 463.11 271.84, 468.70 271.84, 474.29 271.84 C 479.87 271.84, 485.46 272.32, 491.05 271.84 C 496.63 271.36, 502.22 269.44, 507.81 268.96 C 513.40 268.48, 518.98 268.96, 524.57 268.96 C 530.16 268.96, 535.75 268.96, 541.33 268.96 C 546.92 268.96, 552.51 268.96, 558.10 268.96 C 563.68 268.96, 569.27 268.96, 574.86 268.96 C 580.44 268.96, 586.03 268.96, 591.62 268.96 C 597.21 268.96, 602.79 268.96, 608.38 268.96 C 613.97 268.96, 619.56 268.96, 625.14 268.96 C 630.73 268.96, 636.32 269.44, 641.90 268.96 C 647.49 268.48, 653.08 266.56, 658.67 266.08 C 664.25 265.60, 669.84 266.08, 675.43 266.08 C 681.02 266.08, 686.60 266.08, 692.19 266.08 C 697.78 266.08, 703.37 267.04, 708.95 266.08 C 714.54 265.12, 720.13 261.28, 725.71 260.32 C 731.30 259.36, 736.89 260.80, 742.48 260.32 C 748.06 259.84, 753.65 257.92, 759.24 257.44 C 764.83 256.96, 770.41 258.88, 776.00 257.44 C 781.59 256.00, 787.17 251.68, 792.76 248.80 C 798.35 245.92, 803.94 242.08, 809.52 240.16 C 815.11 238.24, 820.70 237.76, 826.29 237.28 C 831.87 236.80, 837.46 237.28, 843.05 237.28 C 848.63 237.28, 854.22 237.28, 859.81 237.28 C 865.40 237.28, 870.98 237.76, 876.57 237.28 C 882.16 236.80, 887.75 235.36, 893.33 234.40 C 898.92 233.44, 904.51 233.92, 910.10 231.52 C 915.68 229.12, 921.27 225.76, 926.86 220.00 C 932.44 214.24, 938.03 204.64, 943.62 196.96 C 949.21 189.28, 954.79 178.24, 960.38 173.92 C 965.97 169.60, 971.56 172.00, 977.14 171.04 C 982.73 170.08, 988.32 168.64, 993.90 168.16 C 999.49 167.68, 1005.08 168.16, 1010.67 168.16 C 1016.25 168.16, 1021.84 168.16, 1027.43 168.16 C 1033.02 168.16, 1038.60 169.12, 1044.19 168.16 C 1049.78 167.20, 1055.37 163.36, 1060.95 162.40 C 1066.54 161.44, 1072.13 162.40, 1077.71 162.40 C 1083.30 162.40, 1088.89 170.08, 1094.48 162.40 C 1100.06 154.72, 1105.65 125.44, 1111.24 116.32 C 1116.83 107.20, 1125.21 109.12, 1128.00 107.68" fill="none" stroke="url(#stroke1)" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow1)" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100">
|
||||
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.4s" begin="0s" fill="freeze" calcMode="spline" keySplines="0.4 0 0.2 1" keyTimes="0;1" values="100;0"/>
|
||||
</path>
|
||||
|
||||
<path d="M 239.62 364.00 C 242.41 363.52, 250.79 362.03, 256.38 361.12 C 261.97 360.21, 267.56 359.44, 273.14 358.53 C 278.73 357.62, 284.32 356.56, 289.90 355.65 C 295.49 354.74, 301.08 353.97, 306.67 353.06 C 312.25 352.14, 317.84 351.14, 323.43 350.18 C 329.02 349.22, 334.60 348.21, 340.19 347.30 C 345.78 346.38, 351.37 345.62, 356.95 344.70 C 362.54 343.79, 368.13 342.78, 373.71 341.82 C 379.30 340.86, 384.89 339.86, 390.48 338.94 C 396.06 338.03, 401.65 337.26, 407.24 336.35 C 412.83 335.44, 418.41 334.38, 424.00 333.47 C 429.59 332.56, 435.17 331.79, 440.76 330.88 C 446.35 329.97, 451.94 328.96, 457.52 328.00 C 463.11 327.04, 468.70 326.03, 474.29 325.12 C 479.87 324.21, 485.46 323.44, 491.05 322.53 C 496.63 321.62, 502.22 320.61, 507.81 319.65 C 513.40 318.69, 518.98 317.68, 524.57 316.77 C 530.16 315.86, 535.75 315.09, 541.33 314.18 C 546.92 313.26, 552.51 312.21, 558.10 311.30 C 563.68 310.38, 569.27 309.62, 574.86 308.70 C 580.44 307.79, 586.03 306.78, 591.62 305.82 C 597.21 304.86, 602.79 303.86, 608.38 302.94 C 613.97 302.03, 619.56 301.26, 625.14 300.35 C 630.73 299.44, 636.32 298.43, 641.90 297.47 C 647.49 296.51, 653.08 295.50, 658.67 294.59 C 664.25 293.68, 669.84 292.91, 675.43 292.00 C 681.02 291.09, 686.60 290.03, 692.19 289.12 C 697.78 288.21, 703.37 287.44, 708.95 286.53 C 714.54 285.62, 720.13 284.61, 725.71 283.65 C 731.30 282.69, 736.89 281.68, 742.48 280.77 C 748.06 279.86, 753.65 279.09, 759.24 278.18 C 764.83 277.26, 770.41 276.26, 776.00 275.30 C 781.59 274.34, 787.17 273.33, 792.76 272.42 C 798.35 271.50, 803.94 270.74, 809.52 269.82 C 815.11 268.91, 820.70 267.86, 826.29 266.94 C 831.87 266.03, 837.46 265.26, 843.05 264.35 C 848.63 263.44, 854.22 262.43, 859.81 261.47 C 865.40 260.51, 870.98 259.50, 876.57 258.59 C 882.16 257.68, 887.75 256.91, 893.33 256.00 C 898.92 255.09, 904.51 254.08, 910.10 253.12 C 915.68 252.16, 921.27 251.15, 926.86 250.24 C 932.44 249.33, 938.03 248.56, 943.62 247.65 C 949.21 246.74, 954.79 245.68, 960.38 244.77 C 965.97 243.86, 971.56 243.09, 977.14 242.18 C 982.73 241.26, 988.32 240.26, 993.90 239.30 C 999.49 238.34, 1005.08 237.33, 1010.67 236.42 C 1016.25 235.50, 1021.84 234.74, 1027.43 233.82 C 1033.02 232.91, 1038.60 231.90, 1044.19 230.94 C 1049.78 229.98, 1055.37 228.98, 1060.95 228.06 C 1066.54 227.15, 1072.13 226.38, 1077.71 225.47 C 1083.30 224.56, 1088.89 223.50, 1094.48 222.59 C 1100.06 221.68, 1105.65 220.91, 1111.24 220.00 C 1116.83 219.09, 1125.21 217.60, 1128.00 217.12" fill="none" stroke="url(#stroke2)" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow2)" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100">
|
||||
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.4s" begin="0.15s" fill="freeze" calcMode="spline" keySplines="0.4 0 0.2 1" keyTimes="0;1" values="100;0"/>
|
||||
</path>
|
||||
|
||||
<g opacity="0">
|
||||
<circle cx="1128.00" cy="107.68" r="7" fill="#0969da" opacity="0.22"/>
|
||||
<circle cx="1128.00" cy="107.68" r="4" fill="#ffffff" stroke="#0969da" stroke-width="2"/>
|
||||
<animate attributeName="opacity" from="0" to="1" begin="1.4s" dur="0.4s" fill="freeze"/>
|
||||
</g>
|
||||
<g opacity="0">
|
||||
<circle cx="1128.00" cy="217.12" r="7" fill="#bc4c00" opacity="0.22"/>
|
||||
<circle cx="1128.00" cy="217.12" r="4" fill="#ffffff" stroke="#bc4c00" stroke-width="2"/>
|
||||
<animate attributeName="opacity" from="0" to="1" begin="1.55s" dur="0.4s" fill="freeze"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<text x="1128" y="408" text-anchor="end" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="10" fill="#656d76" opacity="0.7">
|
||||
Updated 2026-04-25
|
||||
</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 18 KiB |
365
.github/stats/generate.mjs
vendored
365
.github/stats/generate.mjs
vendored
|
|
@ -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 `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}" preserveAspectRatio="xMidYMid meet" role="img" aria-labelledby="title desc">
|
||||
<title id="title">${meta.repo} — GitHub stars and ClawHub downloads over time</title>
|
||||
<desc id="desc">Time-series chart showing GitHub stars and ClawHub downloads for ${meta.repo}.</desc>
|
||||
<defs>
|
||||
<linearGradient id="fill1" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="${t.line1}" stop-opacity="${t.fillOpacityTop}"/>
|
||||
<stop offset="100%" stop-color="${t.line1}" stop-opacity="${t.fillOpacityBottom}"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="fill2" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="${t.line2}" stop-opacity="${t.fillOpacityTop}"/>
|
||||
<stop offset="100%" stop-color="${t.line2}" stop-opacity="${t.fillOpacityBottom}"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="stroke1" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="${t.line1}"/>
|
||||
<stop offset="100%" stop-color="${t.line1End}"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="stroke2" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="${t.line2}"/>
|
||||
<stop offset="100%" stop-color="${t.line2End}"/>
|
||||
</linearGradient>
|
||||
<filter id="glow1" x="-10%" y="-50%" width="120%" height="200%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 ${hex(t.line1, "r")} 0 0 0 0 ${hex(t.line1, "g")} 0 0 0 0 ${hex(t.line1, "b")} 0 0 0 ${t.glowOpacity} 0" result="coloredGlow"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredGlow"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<filter id="glow2" x="-10%" y="-50%" width="120%" height="200%">
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"/>
|
||||
<feColorMatrix in="blur" type="matrix" values="0 0 0 0 ${hex(t.line2, "r")} 0 0 0 0 ${hex(t.line2, "g")} 0 0 0 0 ${hex(t.line2, "b")} 0 0 0 ${t.glowOpacity} 0" result="coloredGlow"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredGlow"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
<clipPath id="plot-clip">
|
||||
<rect x="${PAD.left}" y="${PAD.top - 4}" width="${PLOT_W}" height="${PLOT_H + 8}"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect width="100%" height="100%" fill="${t.bg}"/>
|
||||
<rect x="0.5" y="0.5" width="${W - 1}" height="${H - 1}" fill="none" stroke="${t.cardBorder}" stroke-width="1" rx="8" ry="8"/>
|
||||
|
||||
<text x="${PAD.left}" y="${titleY}" fill="${t.text}" font-family="${FONT}" font-size="18" font-weight="600">
|
||||
${meta.repo}
|
||||
</text>
|
||||
<text x="${PAD.left}" y="${subtitleY}" fill="${t.textSoft}" font-family="${FONT}" font-size="12" font-weight="400">
|
||||
${meta.subtitle}
|
||||
</text>
|
||||
|
||||
<g transform="translate(${W - PAD.right}, ${titleY})" text-anchor="end" font-family="${FONT}" font-size="14" font-weight="600" style="font-variant-numeric: tabular-nums;">
|
||||
<text fill="${t.line1}">★ ${fmtNumber(last1)} <tspan fill="${t.textSoft}" font-weight="400" font-size="11">GitHub</tspan></text>
|
||||
<text y="20" fill="${t.line2}">⬇ ${fmtNumber(last2)} <tspan fill="${t.textSoft}" font-weight="400" font-size="11">ClawHub</tspan></text>
|
||||
</g>
|
||||
|
||||
<g font-family="${FONT}" font-size="10" fill="${t.textSoft}" style="font-variant-numeric: tabular-nums;">
|
||||
${yTicks1
|
||||
.map((v, i) => {
|
||||
const y = valToY(v, max1);
|
||||
const gridLine =
|
||||
i === 0
|
||||
? ""
|
||||
: `<line x1="${PAD.left}" x2="${W - PAD.right}" y1="${y.toFixed(2)}" y2="${y.toFixed(2)}" stroke="${t.gridSoft}" stroke-width="1" stroke-dasharray="2 4" opacity="0.6"/>`;
|
||||
return `${gridLine}<text x="${PAD.left - 8}" y="${(y + 3).toFixed(2)}" text-anchor="end" fill="${t.line1}" opacity="0.85">${fmtNumber(v)}</text>`;
|
||||
})
|
||||
.join("\n ")}
|
||||
</g>
|
||||
|
||||
<g font-family="${FONT}" font-size="10" fill="${t.line2}" opacity="0.85" style="font-variant-numeric: tabular-nums;">
|
||||
${yTicks2
|
||||
.map((v) => {
|
||||
const y = valToY(v, max2);
|
||||
return `<text x="${W - PAD.right + 8}" y="${(y + 3).toFixed(2)}" text-anchor="start">${fmtNumber(v)}</text>`;
|
||||
})
|
||||
.join("\n ")}
|
||||
</g>
|
||||
|
||||
<g font-family="${FONT}" font-size="10" fill="${t.textSoft}" style="font-variant-numeric: tabular-nums;">
|
||||
${xTicks
|
||||
.map((iso) => {
|
||||
const x = dateToX(iso, minDay, maxDay);
|
||||
return `<text x="${x.toFixed(2)}" y="${H - PAD.bottom + 18}" text-anchor="middle">${fmtDateShort(iso)}</text>`;
|
||||
})
|
||||
.join("\n ")}
|
||||
</g>
|
||||
|
||||
<line x1="${PAD.left}" x2="${W - PAD.right}" y1="${PAD.top + PLOT_H}" y2="${PAD.top + PLOT_H}" stroke="${t.grid}" stroke-width="1" opacity="0.8"/>
|
||||
|
||||
<g clip-path="url(#plot-clip)">
|
||||
${area1Path ? `<path d="${area1Path}" fill="url(#fill1)" stroke="none"/>` : ""}
|
||||
${area2Path ? `<path d="${area2Path}" fill="url(#fill2)" stroke="none"/>` : ""}
|
||||
|
||||
${
|
||||
pts1.length >= 2
|
||||
? `<path d="${line1Path}" fill="none" stroke="url(#stroke1)" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow1)" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100">
|
||||
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.4s" begin="0s" fill="freeze" calcMode="spline" keySplines="0.4 0 0.2 1" keyTimes="0;1" values="100;0"/>
|
||||
</path>`
|
||||
: ""
|
||||
}
|
||||
|
||||
${
|
||||
pts2.length >= 2
|
||||
? `<path d="${line2Path}" fill="none" stroke="url(#stroke2)" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow2)" pathLength="100" stroke-dasharray="100" stroke-dashoffset="100">
|
||||
<animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.4s" begin="0.15s" fill="freeze" calcMode="spline" keySplines="0.4 0 0.2 1" keyTimes="0;1" values="100;0"/>
|
||||
</path>`
|
||||
: ""
|
||||
}
|
||||
|
||||
${
|
||||
lastPt1
|
||||
? `<g opacity="0">
|
||||
<circle cx="${lastPt1[0].toFixed(2)}" cy="${lastPt1[1].toFixed(2)}" r="7" fill="${t.line1}" opacity="0.22"/>
|
||||
<circle cx="${lastPt1[0].toFixed(2)}" cy="${lastPt1[1].toFixed(2)}" r="4" fill="${t.bg}" stroke="${t.line1}" stroke-width="2"/>
|
||||
<animate attributeName="opacity" from="0" to="1" begin="1.4s" dur="0.4s" fill="freeze"/>
|
||||
</g>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
lastPt2
|
||||
? `<g opacity="0">
|
||||
<circle cx="${lastPt2[0].toFixed(2)}" cy="${lastPt2[1].toFixed(2)}" r="7" fill="${t.line2}" opacity="0.22"/>
|
||||
<circle cx="${lastPt2[0].toFixed(2)}" cy="${lastPt2[1].toFixed(2)}" r="4" fill="${t.bg}" stroke="${t.line2}" stroke-width="2"/>
|
||||
<animate attributeName="opacity" from="0" to="1" begin="1.55s" dur="0.4s" fill="freeze"/>
|
||||
</g>`
|
||||
: ""
|
||||
}
|
||||
</g>
|
||||
|
||||
<text x="${W - PAD.right}" y="${H - 12}" text-anchor="end" font-family="${FONT}" font-size="10" fill="${t.textSoft}" opacity="0.7">
|
||||
Updated ${meta.updatedAt}
|
||||
</text>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
488
.github/stats/history.json
vendored
488
.github/stats/history.json
vendored
|
|
@ -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
|
||||
}
|
||||
147
.github/stats/seed.mjs
vendored
147
.github/stats/seed.mjs
vendored
|
|
@ -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);
|
||||
});
|
||||
75
.github/stats/update.mjs
vendored
75
.github/stats/update.mjs
vendored
|
|
@ -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);
|
||||
});
|
||||
46
.github/workflows/stats.yml
vendored
46
.github/workflows/stats.yml
vendored
|
|
@ -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
|
||||
12
README.md
12
README.md
|
|
@ -21,11 +21,13 @@
|
|||
<img src="docs/architecture.png" alt="agent-desktop architecture diagram" width="800" />
|
||||
</p>
|
||||
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./.github/stats/chart-dark.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="./.github/stats/chart-light.svg">
|
||||
<img alt="GitHub stars and ClawHub downloads for lahfir/agent-desktop" src="./.github/stats/chart-light.svg" width="100%">
|
||||
</picture>
|
||||
<a href="https://star-history.com/#lahfir/agent-desktop&Date">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=lahfir/agent-desktop&type=Date&theme=dark">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=lahfir/agent-desktop&type=Date">
|
||||
<img alt="Star history for lahfir/agent-desktop" src="https://api.star-history.com/svg?repos=lahfir/agent-desktop&type=Date">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## Key Features
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue