mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
docs: refresh clawtributors list
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
- When working on an issue: reference the issue in the changelog entry.
|
||||
- When merging a PR: leave a PR comment that explains exactly what we did and include the SHA hashes.
|
||||
- When merging a PR from a new contributor: add their avatar to the README “Thanks to all clawtributors” thumbnail list.
|
||||
- After merging a PR: run `bun scripts/update-clawtributors.ts` if the contributor is missing, then commit the regenerated README.
|
||||
|
||||
### PR Workflow (Review vs Land)
|
||||
- **Review mode (PR link only):** read `gh pr view/diff`; **do not** switch branches; **do not** change code.
|
||||
|
||||
12
README.md
12
README.md
@@ -447,11 +447,9 @@ AI/vibe-coded PRs welcome! 🤖
|
||||
Thanks to all clawtributors:
|
||||
|
||||
<p align="left">
|
||||
<a href="https://github.com/steipete"><img src="https://avatars.githubusercontent.com/u/58493?v=4&s=48" width="48" height="48" alt="steipete" title="steipete"/></a> <a href="https://github.com/thewilloftheshadow"><img src="https://avatars.githubusercontent.com/u/35580099?v=4&s=48" width="48" height="48" alt="thewilloftheshadow" title="thewilloftheshadow"/></a> <a href="https://github.com/joaohlisboa"><img src="https://avatars.githubusercontent.com/u/8200873?v=4&s=48" width="48" height="48" alt="joaohlisboa" title="joaohlisboa"/></a> <a href="https://github.com/mneves75"><img src="https://avatars.githubusercontent.com/u/2423436?v=4&s=48" width="48" height="48" alt="mneves75" title="mneves75"/></a> <a href="https://github.com/mukhtharcm"><img src="https://avatars.githubusercontent.com/u/56378562?v=4&s=48" width="48" height="48" alt="mukhtharcm" title="mukhtharcm"/></a> <a href="https://github.com/maxsumrall"><img src="https://avatars.githubusercontent.com/u/628843?v=4&s=48" width="48" height="48" alt="maxsumrall" title="maxsumrall"/></a> <a href="https://github.com/xadenryan"><img src="https://avatars.githubusercontent.com/u/165437834?v=4&s=48" width="48" height="48" alt="xadenryan" title="xadenryan"/></a> <a href="https://github.com/joshp123"><img src="https://avatars.githubusercontent.com/u/1497361?v=4&s=48" width="48" height="48" alt="joshp123" title="joshp123"/></a> <a href="https://github.com/hsrvc"><img src="https://avatars.githubusercontent.com/u/129702169?v=4&s=48" width="48" height="48" alt="hsrvc" title="hsrvc"/></a> <a href="https://github.com/obviyus"><img src="https://avatars.githubusercontent.com/u/22031114?v=4&s=48" width="48" height="48" alt="obviyus" title="obviyus"/></a>
|
||||
<a href="https://github.com/jamesgroat"><img src="https://avatars.githubusercontent.com/u/2634024?v=4&s=48" width="48" height="48" alt="jamesgroat" title="jamesgroat"/></a> <a href="https://github.com/jalehman"><img src="https://avatars.githubusercontent.com/u/550978?v=4&s=48" width="48" height="48" alt="jalehman" title="jalehman"/></a> <a href="https://github.com/dbhurley"><img src="https://avatars.githubusercontent.com/u/5251425?v=4&s=48" width="48" height="48" alt="dbhurley" title="dbhurley"/></a> <a href="https://github.com/dantelex"><img src="https://avatars.githubusercontent.com/u/631543?v=4&s=48" width="48" height="48" alt="dantelex" title="dantelex"/></a> <a href="https://github.com/mcinteerj"><img src="https://avatars.githubusercontent.com/u/3613653?v=4&s=48" width="48" height="48" alt="mcinteerj" title="mcinteerj"/></a> <a href="https://github.com/zats"><img src="https://avatars.githubusercontent.com/u/2688806?v=4&s=48" width="48" height="48" alt="zats" title="zats"/></a> <a href="https://github.com/jeffersonwarrior"><img src="https://avatars.githubusercontent.com/u/89030989?v=4&s=48" width="48" height="48" alt="jeffersonwarrior" title="jeffersonwarrior"/></a> <a href="https://github.com/azade-c"><img src="https://avatars.githubusercontent.com/u/252790079?v=4&s=48" width="48" height="48" alt="azade-c" title="azade-c"/></a> <a href="https://github.com/Asleep123"><img src="https://avatars.githubusercontent.com/u/122379135?v=4&s=48" width="48" height="48" alt="Asleep123" title="Asleep123"/></a> <a href="https://github.com/omniwired"><img src="https://avatars.githubusercontent.com/u/322761?v=4&s=48" width="48" height="48" alt="omniwired" title="omniwired"/></a>
|
||||
<a href="https://github.com/mbelinky"><img src="https://avatars.githubusercontent.com/u/132747814?v=4&s=48" width="48" height="48" alt="mbelinky" title="mbelinky"/></a> <a href="https://github.com/jverdi"><img src="https://avatars.githubusercontent.com/u/345050?v=4&s=48" width="48" height="48" alt="jverdi" title="jverdi"/></a> <a href="https://github.com/julianengel"><img src="https://avatars.githubusercontent.com/u/10634231?v=4&s=48" width="48" height="48" alt="julianengel" title="julianengel"/></a> <a href="https://github.com/fcatuhe"><img src="https://avatars.githubusercontent.com/u/17382215?v=4&s=48" width="48" height="48" alt="fcatuhe" title="fcatuhe"/></a> <a href="https://github.com/sreekaransrinath"><img src="https://avatars.githubusercontent.com/u/50989977?v=4&s=48" width="48" height="48" alt="sreekaransrinath" title="sreekaransrinath"/></a> <a href="https://github.com/kitze"><img src="https://avatars.githubusercontent.com/u/1160594?v=4&s=48" width="48" height="48" alt="kitze" title="kitze"/></a> <a href="https://github.com/jdrhyne"><img src="https://avatars.githubusercontent.com/u/7828464?v=4&s=48" width="48" height="48" alt="Jonathan D. Rhyne (DJ-D)" title="Jonathan D. Rhyne (DJ-D)"/></a> <a href="https://github.com/vsabavat"><img src="https://avatars.githubusercontent.com/u/50385532?v=4&s=48" width="48" height="48" alt="vsabavat" title="vsabavat"/></a> <a href="https://github.com/claude"><img src="https://avatars.githubusercontent.com/u/81847?v=4&s=48" width="48" height="48" alt="claude" title="claude"/></a> <a href="https://github.com/petter-b"><img src="https://avatars.githubusercontent.com/u/62076402?v=4&s=48" width="48" height="48" alt="petter-b" title="petter-b"/></a>
|
||||
<a href="https://github.com/scald"><img src="https://avatars.githubusercontent.com/u/1215913?v=4&s=48" width="48" height="48" alt="scald" title="scald"/></a> <a href="https://github.com/oswalpalash"><img src="https://avatars.githubusercontent.com/u/6431196?v=4&s=48" width="48" height="48" alt="oswalpalash" title="oswalpalash"/></a> <a href="https://github.com/nachoiacovino"><img src="https://avatars.githubusercontent.com/u/50103937?v=4&s=48" width="48" height="48" alt="nachoiacovino" title="nachoiacovino"/></a> <a href="https://github.com/andranik-sahakyan"><img src="https://avatars.githubusercontent.com/u/8908029?v=4&s=48" width="48" height="48" alt="andranik-sahakyan" title="andranik-sahakyan"/></a> <a href="https://github.com/sircrumpet"><img src="https://avatars.githubusercontent.com/u/4436535?v=4&s=48" width="48" height="48" alt="sircrumpet" title="sircrumpet"/></a> <a href="https://github.com/manmal"><img src="https://avatars.githubusercontent.com/u/142797?v=4&s=48" width="48" height="48" alt="manmal" title="manmal"/></a> <a href="https://github.com/rafaelreis-r"><img src="https://avatars.githubusercontent.com/u/57492577?v=4&s=48" width="48" height="48" alt="rafaelreis-r" title="rafaelreis-r"/></a> <a href="https://github.com/meaningfool"><img src="https://avatars.githubusercontent.com/u/2862331?v=4&s=48" width="48" height="48" alt="meaningfool" title="meaningfool"/></a> <a href="https://github.com/jonasjancarik"><img src="https://avatars.githubusercontent.com/u/2459191?v=4&s=48" width="48" height="48" alt="jonasjancarik" title="jonasjancarik"/></a> <a href="https://github.com/ratulsarna"><img src="https://avatars.githubusercontent.com/u/105903728?v=4&s=48" width="48" height="48" alt="ratulsarna" title="ratulsarna"/></a>
|
||||
<a href="https://github.com/lutr0"><img src="https://avatars.githubusercontent.com/u/76906369?v=4&s=48" width="48" height="48" alt="lutr0" title="lutr0"/></a> <a href="https://github.com/kkarimi"><img src="https://avatars.githubusercontent.com/u/875218?v=4&s=48" width="48" height="48" alt="kkarimi" title="kkarimi"/></a> <a href="https://github.com/emanuelst"><img src="https://avatars.githubusercontent.com/u/9994339?v=4&s=48" width="48" height="48" alt="emanuelst" title="emanuelst"/></a> <a href="https://github.com/Syhids"><img src="https://avatars.githubusercontent.com/u/671202?v=4&s=48" width="48" height="48" alt="Syhids" title="Syhids"/></a> <a href="https://github.com/osolmaz"><img src="https://avatars.githubusercontent.com/u/2453968?v=4&s=48" width="48" height="48" alt="osolmaz" title="osolmaz"/></a> <a href="https://github.com/kiranjd"><img src="https://avatars.githubusercontent.com/u/25822851?v=4&s=48" width="48" height="48" alt="kiranjd" title="kiranjd"/></a> <a href="https://github.com/wstock"><img src="https://avatars.githubusercontent.com/u/1394687?v=4&s=48" width="48" height="48" alt="wstock" title="wstock"/></a> <a href="https://github.com/CashWilliams"><img src="https://avatars.githubusercontent.com/u/613573?v=4&s=48" width="48" height="48" alt="CashWilliams" title="CashWilliams"/></a> <a href="https://github.com/cash-echo-bot"><img src="https://avatars.githubusercontent.com/u/252747386?v=4&s=48" width="48" height="48" alt="cash-echo-bot" title="cash-echo-bot"/></a> <a href="https://github.com/onutc"><img src="https://avatars.githubusercontent.com/u/152018508?v=4&s=48" width="48" height="48" alt="onutc" title="onutc"/></a>
|
||||
<a href="https://github.com/minghinmatthewlam"><img src="https://avatars.githubusercontent.com/u/14224566?v=4&s=48" width="48" height="48" alt="minghinmatthewlam" title="minghinmatthewlam"/></a> <a href="https://github.com/buddyh"><img src="https://avatars.githubusercontent.com/u/31752869?v=4&s=48" width="48" height="48" alt="buddyh" title="buddyh"/></a> <a href="https://github.com/MSch"><img src="https://avatars.githubusercontent.com/u/7475?v=4&s=48" width="48" height="48" alt="MSch" title="MSch"/></a> <a href="https://github.com/timkrase"><img src="https://avatars.githubusercontent.com/u/38947626?v=4&s=48" width="48" height="48" alt="timkrase" title="timkrase"/></a> <a href="https://github.com/gupsammy"><img src="https://avatars.githubusercontent.com/u/20296019?v=4&s=48" width="48" height="48" alt="gupsammy" title="gupsammy"/></a> <a href="https://github.com/hrdwdmrbl"><img src="https://avatars.githubusercontent.com/u/554881?v=4&s=48" width="48" height="48" alt="hrdwdmrbl" title="hrdwdmrbl"/></a> <a href="https://github.com/reeltimeapps"><img src="https://avatars.githubusercontent.com/u/637338?v=4&s=48" width="48" height="48" alt="reeltimeapps" title="reeltimeapps"/></a> <a href="https://github.com/snopoke"><img src="https://avatars.githubusercontent.com/u/249606?v=4&s=48" width="48" height="48" alt="snopoke" title="snopoke"/></a> <a href="https://github.com/ngutman"><img src="https://avatars.githubusercontent.com/u/1540134?v=4&s=48" width="48" height="48" alt="ngutman" title="ngutman"/></a> <a href="https://github.com/antons"><img src="https://avatars.githubusercontent.com/u/129705?v=4&s=48" width="48" height="48" alt="antons" title="antons"/></a>
|
||||
<a href="https://github.com/imfing"><img src="https://avatars.githubusercontent.com/u/5097752?v=4&s=48" width="48" height="48" alt="imfing" title="imfing"/></a> <a href="https://github.com/RandyVentures"><img src="https://avatars.githubusercontent.com/u/149904821?v=4&s=48" width="48" height="48" alt="RandyVentures" title="RandyVentures"/></a> <a href="https://github.com/loukotal"><img src="https://avatars.githubusercontent.com/u/18210858?v=4&s=48" width="48" height="48" alt="loukotal" title="loukotal"/></a> <a href="https://github.com/VACInc"><img src="https://avatars.githubusercontent.com/u/3279061?v=4&s=48" width="48" height="48" alt="VACInc" title="VACInc"/></a> <a href="https://github.com/djangonavarro220"><img src="https://avatars.githubusercontent.com/u/251162586?v=4&s=48" width="48" height="48" alt="djangonavarro220" title="djangonavarro220"/></a> <a href="https://github.com/erikpr1994"><img src="https://avatars.githubusercontent.com/u/6299331?v=4&s=48" width="48" height="48" alt="erikpr1994" title="erikpr1994"/></a> <a href="https://github.com/gtsifrikas"><img src="https://avatars.githubusercontent.com/u/8904378?v=4&s=48" width="48" height="48" alt="gtsifrikas" title="gtsifrikas"/></a> <a href="https://github.com/jayhickey"><img src="https://avatars.githubusercontent.com/u/1676460?v=4&s=48" width="48" height="48" alt="jayhickey" title="jayhickey"/></a> <a href="https://github.com/hugobarauna"><img src="https://avatars.githubusercontent.com/u/2719?v=4&s=48" width="48" height="48" alt="hugobarauna" title="hugobarauna"/></a>
|
||||
<a href="https://github.com/joaohlisboa"><img src="https://avatars.githubusercontent.com/u/8200873?v=4&s=48" width="48" height="48" alt="joaohlisboa" title="joaohlisboa"/></a> <a href="https://github.com/mneves75"><img src="https://avatars.githubusercontent.com/u/2423436?v=4&s=48" width="48" height="48" alt="mneves75" title="mneves75"/></a> <a href="https://github.com/maxsumrall"><img src="https://avatars.githubusercontent.com/u/628843?v=4&s=48" width="48" height="48" alt="maxsumrall" title="maxsumrall"/></a> <a href="https://github.com/xadenryan"><img src="https://avatars.githubusercontent.com/u/165437834?v=4&s=48" width="48" height="48" alt="xadenryan" title="xadenryan"/></a> <a href="https://github.com/joshp123"><img src="https://avatars.githubusercontent.com/u/1497361?v=4&s=48" width="48" height="48" alt="joshp123" title="joshp123"/></a> <a href="https://github.com/mukhtharcm"><img src="https://avatars.githubusercontent.com/u/56378562?v=4&s=48" width="48" height="48" alt="mukhtharcm" title="mukhtharcm"/></a> <a href="https://github.com/hsrvc"><img src="https://avatars.githubusercontent.com/u/129702169?v=4&s=48" width="48" height="48" alt="hsrvc" title="hsrvc"/></a> <a href="https://github.com/jamesgroat"><img src="https://avatars.githubusercontent.com/u/2634024?v=4&s=48" width="48" height="48" alt="jamesgroat" title="jamesgroat"/></a> <a href="https://github.com/dantelex"><img src="https://avatars.githubusercontent.com/u/631543?v=4&s=48" width="48" height="48" alt="dantelex" title="dantelex"/></a> <a href="https://github.com/azade-c"><img src="https://avatars.githubusercontent.com/u/252790079?v=4&s=48" width="48" height="48" alt="azade-c" title="azade-c"/></a>
|
||||
<a href="https://github.com/omniwired"><img src="https://avatars.githubusercontent.com/u/322761?v=4&s=48" width="48" height="48" alt="omniwired" title="omniwired"/></a> <a href="https://github.com/mbelinky"><img src="https://avatars.githubusercontent.com/u/132747814?v=4&s=48" width="48" height="48" alt="mbelinky" title="mbelinky"/></a> <a href="https://github.com/julianengel"><img src="https://avatars.githubusercontent.com/u/10634231?v=4&s=48" width="48" height="48" alt="julianengel" title="julianengel"/></a> <a href="https://github.com/sreekaransrinath"><img src="https://avatars.githubusercontent.com/u/50989977?v=4&s=48" width="48" height="48" alt="sreekaransrinath" title="sreekaransrinath"/></a> <a href="https://github.com/dbhurley"><img src="https://avatars.githubusercontent.com/u/5251425?v=4&s=48" width="48" height="48" alt="dbhurley" title="dbhurley"/></a> <a href="https://github.com/kitze"><img src="https://avatars.githubusercontent.com/u/1160594?v=4&s=48" width="48" height="48" alt="kitze" title="kitze"/></a> <a href="https://github.com/jdrhyne"><img src="https://avatars.githubusercontent.com/u/7828464?v=4&s=48" width="48" height="48" alt="Jonathan D. Rhyne (DJ-D)" title="Jonathan D. Rhyne (DJ-D)"/></a> <a href="https://github.com/vsabavat"><img src="https://avatars.githubusercontent.com/u/50385532?v=4&s=48" width="48" height="48" alt="vsabavat" title="vsabavat"/></a> <a href="https://github.com/jeffersonwarrior"><img src="https://avatars.githubusercontent.com/u/89030989?v=4&s=48" width="48" height="48" alt="jeffersonwarrior" title="jeffersonwarrior"/></a> <a href="https://github.com/claude"><img src="https://avatars.githubusercontent.com/u/81847?v=4&s=48" width="48" height="48" alt="claude" title="claude"/></a>
|
||||
<a href="https://github.com/scald"><img src="https://avatars.githubusercontent.com/u/1215913?v=4&s=48" width="48" height="48" alt="scald" title="scald"/></a> <a href="https://github.com/nachoiacovino"><img src="https://avatars.githubusercontent.com/u/50103937?v=4&s=48" width="48" height="48" alt="nachoiacovino" title="nachoiacovino"/></a> <a href="https://github.com/andranik-sahakyan"><img src="https://avatars.githubusercontent.com/u/8908029?v=4&s=48" width="48" height="48" alt="andranik-sahakyan" title="andranik-sahakyan"/></a> <a href="https://github.com/Nachx639"><img src="https://avatars.githubusercontent.com/u/71144023?v=4&s=48" width="48" height="48" alt="Nachx639" title="Nachx639"/></a> <a href="https://github.com/tobiasbischoff"><img src="https://avatars.githubusercontent.com/u/711564?v=4&s=48" width="48" height="48" alt="tobiasbischoff" title="tobiasbischoff"/></a> <a href="https://github.com/sircrumpet"><img src="https://avatars.githubusercontent.com/u/4436535?v=4&s=48" width="48" height="48" alt="sircrumpet" title="sircrumpet"/></a> <a href="https://github.com/manmal"><img src="https://avatars.githubusercontent.com/u/142797?v=4&s=48" width="48" height="48" alt="manmal" title="manmal"/></a> <a href="https://github.com/rafaelreis-r"><img src="https://avatars.githubusercontent.com/u/57492577?v=4&s=48" width="48" height="48" alt="rafaelreis-r" title="rafaelreis-r"/></a> <a href="https://github.com/meaningfool"><img src="https://avatars.githubusercontent.com/u/2862331?v=4&s=48" width="48" height="48" alt="meaningfool" title="meaningfool"/></a> <a href="https://github.com/ratulsarna"><img src="https://avatars.githubusercontent.com/u/105903728?v=4&s=48" width="48" height="48" alt="ratulsarna" title="ratulsarna"/></a>
|
||||
<a href="https://github.com/lutr0"><img src="https://avatars.githubusercontent.com/u/76906369?v=4&s=48" width="48" height="48" alt="lutr0" title="lutr0"/></a> <a href="https://github.com/AbhisekBasu1"><img src="https://avatars.githubusercontent.com/u/40645221?v=4&s=48" width="48" height="48" alt="AbhisekBasu1" title="AbhisekBasu1"/></a> <a href="https://github.com/emanuelst"><img src="https://avatars.githubusercontent.com/u/9994339?v=4&s=48" width="48" height="48" alt="emanuelst" title="emanuelst"/></a> <a href="https://github.com/osolmaz"><img src="https://avatars.githubusercontent.com/u/2453968?v=4&s=48" width="48" height="48" alt="osolmaz" title="osolmaz"/></a> <a href="https://github.com/kiranjd"><img src="https://avatars.githubusercontent.com/u/25822851?v=4&s=48" width="48" height="48" alt="kiranjd" title="kiranjd"/></a> <a href="https://github.com/wstock"><img src="https://avatars.githubusercontent.com/u/1394687?v=4&s=48" width="48" height="48" alt="wstock" title="wstock"/></a> <a href="https://github.com/CashWilliams"><img src="https://avatars.githubusercontent.com/u/613573?v=4&s=48" width="48" height="48" alt="CashWilliams" title="CashWilliams"/></a> <a href="https://github.com/ManuelHettich"><img src="https://avatars.githubusercontent.com/u/17690367?v=4&s=48" width="48" height="48" alt="ManuelHettich" title="ManuelHettich"/></a> <a href="https://github.com/minghinmatthewlam"><img src="https://avatars.githubusercontent.com/u/14224566?v=4&s=48" width="48" height="48" alt="minghinmatthewlam" title="minghinmatthewlam"/></a> <a href="https://github.com/buddyh"><img src="https://avatars.githubusercontent.com/u/31752869?v=4&s=48" width="48" height="48" alt="buddyh" title="buddyh"/></a>
|
||||
<a href="https://github.com/timkrase"><img src="https://avatars.githubusercontent.com/u/38947626?v=4&s=48" width="48" height="48" alt="timkrase" title="timkrase"/></a> <a href="https://github.com/gupsammy"><img src="https://avatars.githubusercontent.com/u/20296019?v=4&s=48" width="48" height="48" alt="gupsammy" title="gupsammy"/></a> <a href="https://github.com/imfing"><img src="https://avatars.githubusercontent.com/u/5097752?v=4&s=48" width="48" height="48" alt="imfing" title="imfing"/></a> <a href="https://github.com/RandyVentures"><img src="https://avatars.githubusercontent.com/u/149904821?v=4&s=48" width="48" height="48" alt="RandyVentures" title="RandyVentures"/></a> <a href="https://github.com/Iamadig"><img src="https://avatars.githubusercontent.com/u/102129234?v=4&s=48" width="48" height="48" alt="Iamadig" title="Iamadig"/></a> <a href="https://github.com/VACInc"><img src="https://avatars.githubusercontent.com/u/3279061?v=4&s=48" width="48" height="48" alt="VACInc" title="VACInc"/></a> <a href="https://github.com/djangonavarro220"><img src="https://avatars.githubusercontent.com/u/251162586?v=4&s=48" width="48" height="48" alt="djangonavarro220" title="djangonavarro220"/></a> <a href="https://github.com/erikpr1994"><img src="https://avatars.githubusercontent.com/u/6299331?v=4&s=48" width="48" height="48" alt="erikpr1994" title="erikpr1994"/></a> <a href="https://github.com/jayhickey"><img src="https://avatars.githubusercontent.com/u/1676460?v=4&s=48" width="48" height="48" alt="jayhickey" title="jayhickey"/></a>
|
||||
</p>
|
||||
|
||||
40
scripts/clawtributors-map.json
Normal file
40
scripts/clawtributors-map.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"ensureLogins": [
|
||||
"jdrhyne",
|
||||
"manmal"
|
||||
],
|
||||
"displayName": {
|
||||
"jdrhyne": "Jonathan D. Rhyne (DJ-D)"
|
||||
},
|
||||
"nameToLogin": {
|
||||
"azade": "azade-c",
|
||||
"eng. juan combetto": "omniwired",
|
||||
"mariano belinky": "mbelinky",
|
||||
"kit": "kitze",
|
||||
"vasanth rao naik sabavat": "vsabavat",
|
||||
"tobias bischoff": "tobiasbischoff",
|
||||
"tu nombre real": "nachx639",
|
||||
"william stock": "wstock",
|
||||
"abhisekbasu1": "AbhisekBasu1",
|
||||
"manuelhettich": "manuelhettich",
|
||||
"iamadig": "Iamadig",
|
||||
"django navarro": "djangonavarro220",
|
||||
"erik": "erikpr1994",
|
||||
"jonathan d. rhyne": "jdrhyne",
|
||||
"jonathan rhyne": "jdrhyne",
|
||||
"manuel maly": "manmal",
|
||||
"manuel mali": "manmal"
|
||||
},
|
||||
"emailToLogin": {
|
||||
"manuel.maly@gmail.com": "manmal",
|
||||
"omniwired@gmail.com": "omniwired",
|
||||
"mbelinky@gmail.com": "mbelinky",
|
||||
"vsabavat@nvidia.com": "vsabavat",
|
||||
"nacho639@gmail.com": "nachx639",
|
||||
"w.stock@yahoo.com": "wstock",
|
||||
"rltorres26+github@gmail.com": "RandyVentures",
|
||||
"hixvac@gmail.com": "VACInc",
|
||||
"djangonavarro220@gmail.com": "djangonavarro220",
|
||||
"erikpastorrios1994@gmail.com": "erikpr1994"
|
||||
}
|
||||
}
|
||||
272
scripts/update-clawtributors.ts
Normal file
272
scripts/update-clawtributors.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const REPO = "clawdbot/clawdbot";
|
||||
const PER_LINE = 10;
|
||||
|
||||
type MapConfig = {
|
||||
ensureLogins?: string[];
|
||||
displayName?: Record<string, string>;
|
||||
nameToLogin?: Record<string, string>;
|
||||
emailToLogin?: Record<string, string>;
|
||||
};
|
||||
|
||||
type User = {
|
||||
login: string;
|
||||
html_url: string;
|
||||
avatar_url: string;
|
||||
};
|
||||
|
||||
type Entry = {
|
||||
login: string;
|
||||
display: string;
|
||||
html_url: string;
|
||||
avatar_url: string;
|
||||
lines: number;
|
||||
};
|
||||
|
||||
const mapPath = resolve("scripts/clawtributors-map.json");
|
||||
const mapConfig = JSON.parse(readFileSync(mapPath, "utf8")) as MapConfig;
|
||||
|
||||
const displayName = mapConfig.displayName ?? {};
|
||||
const nameToLogin = normalizeMap(mapConfig.nameToLogin ?? {});
|
||||
const emailToLogin = normalizeMap(mapConfig.emailToLogin ?? {});
|
||||
const ensureLogins = (mapConfig.ensureLogins ?? []).map((login) => login.toLowerCase());
|
||||
|
||||
const raw = run(`gh api "repos/${REPO}/contributors?per_page=100&anon=1" --paginate`);
|
||||
const contributors = parsePaginatedJson(raw);
|
||||
const apiByLogin = new Map<string, User>();
|
||||
|
||||
for (const item of contributors) {
|
||||
if (!item?.login || !item?.html_url || !item?.avatar_url) {
|
||||
continue;
|
||||
}
|
||||
apiByLogin.set(item.login.toLowerCase(), {
|
||||
login: item.login,
|
||||
html_url: item.html_url,
|
||||
avatar_url: normalizeAvatar(item.avatar_url),
|
||||
});
|
||||
}
|
||||
|
||||
for (const login of ensureLogins) {
|
||||
if (!apiByLogin.has(login)) {
|
||||
const user = fetchUser(login);
|
||||
if (user) {
|
||||
apiByLogin.set(user.login.toLowerCase(), user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const log = run("git log --format=%aN%x7c%aE --numstat");
|
||||
const linesByLogin = new Map<string, number>();
|
||||
|
||||
let currentName: string | null = null;
|
||||
let currentEmail: string | null = null;
|
||||
|
||||
for (const line of log.split("\n")) {
|
||||
if (!line.trim()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.includes("|") && !/^[0-9-]/.test(line)) {
|
||||
const [name, email] = line.split("|", 2);
|
||||
currentName = name?.trim() ?? null;
|
||||
currentEmail = email?.trim().toLowerCase() ?? null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!currentName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const parts = line.split("\t");
|
||||
if (parts.length < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const adds = parseCount(parts[0]);
|
||||
const dels = parseCount(parts[1]);
|
||||
const total = adds + dels;
|
||||
if (!total) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let login = resolveLogin(currentName, currentEmail, apiByLogin, nameToLogin, emailToLogin);
|
||||
if (!login) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = login.toLowerCase();
|
||||
linesByLogin.set(key, (linesByLogin.get(key) ?? 0) + total);
|
||||
}
|
||||
|
||||
for (const login of ensureLogins) {
|
||||
if (!linesByLogin.has(login)) {
|
||||
linesByLogin.set(login, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const entries: Entry[] = [];
|
||||
for (const [login, lines] of linesByLogin.entries()) {
|
||||
let user = apiByLogin.get(login);
|
||||
if (!user) {
|
||||
user = fetchUser(login);
|
||||
}
|
||||
if (!user || !user.avatar_url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.push({
|
||||
login: user.login,
|
||||
display: displayName[user.login.toLowerCase()] ?? user.login,
|
||||
html_url: user.html_url,
|
||||
avatar_url: normalizeAvatar(user.avatar_url),
|
||||
lines,
|
||||
});
|
||||
}
|
||||
|
||||
entries.sort((a, b) => {
|
||||
if (b.lines !== a.lines) {
|
||||
return b.lines - a.lines;
|
||||
}
|
||||
return a.display.localeCompare(b.display);
|
||||
});
|
||||
|
||||
const lines: string[] = [];
|
||||
for (let i = 0; i < entries.length; i += PER_LINE) {
|
||||
const chunk = entries.slice(i, i + PER_LINE);
|
||||
const parts = chunk.map((entry) => {
|
||||
return `<a href=\"${entry.html_url}\"><img src=\"${entry.avatar_url}\" width=\"48\" height=\"48\" alt=\"${entry.display}\" title=\"${entry.display}\"/></a>`;
|
||||
});
|
||||
lines.push(` ${parts.join(" ")}`);
|
||||
}
|
||||
|
||||
const block = `${lines.join("\n")}\n`;
|
||||
const readmePath = resolve("README.md");
|
||||
const readme = readFileSync(readmePath, "utf8");
|
||||
const start = readme.indexOf('<p align="left">');
|
||||
const end = readme.indexOf("</p>", start);
|
||||
|
||||
if (start === -1 || end === -1) {
|
||||
throw new Error("README.md missing clawtributors block");
|
||||
}
|
||||
|
||||
const next = `${readme.slice(0, start)}<p align=\"left\">\n${block}${readme.slice(end)}`;
|
||||
writeFileSync(readmePath, next);
|
||||
|
||||
console.log(`Updated README clawtributors: ${entries.length} entries`);
|
||||
|
||||
function run(cmd: string): string {
|
||||
return execSync(cmd, {
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
maxBuffer: 1024 * 1024 * 200,
|
||||
}).trim();
|
||||
}
|
||||
|
||||
function parsePaginatedJson(raw: string): any[] {
|
||||
const items: any[] = [];
|
||||
for (const line of raw.split("\n")) {
|
||||
if (!line.trim()) {
|
||||
continue;
|
||||
}
|
||||
const parsed = JSON.parse(line);
|
||||
if (Array.isArray(parsed)) {
|
||||
items.push(...parsed);
|
||||
} else {
|
||||
items.push(parsed);
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
function normalizeMap(map: Record<string, string>): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(map)) {
|
||||
out[normalizeName(key)] = value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function normalizeName(value: string): string {
|
||||
return value.trim().toLowerCase().replace(/\s+/g, " ");
|
||||
}
|
||||
|
||||
function parseCount(value: string): number {
|
||||
return /^\d+$/.test(value) ? Number(value) : 0;
|
||||
}
|
||||
|
||||
function normalizeAvatar(url: string): string {
|
||||
const lower = url.toLowerCase();
|
||||
if (lower.includes("s=") || lower.includes("size=")) {
|
||||
return url;
|
||||
}
|
||||
const sep = url.includes("?") ? "&" : "?";
|
||||
return `${url}${sep}s=48`;
|
||||
}
|
||||
|
||||
function fetchUser(login: string): User | null {
|
||||
try {
|
||||
const data = execSync(`gh api users/${login}`, {
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
const parsed = JSON.parse(data);
|
||||
if (!parsed?.login || !parsed?.html_url || !parsed?.avatar_url) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
login: parsed.login,
|
||||
html_url: parsed.html_url,
|
||||
avatar_url: normalizeAvatar(parsed.avatar_url),
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveLogin(
|
||||
name: string,
|
||||
email: string | null,
|
||||
apiByLogin: Map<string, User>,
|
||||
nameToLogin: Record<string, string>,
|
||||
emailToLogin: Record<string, string>
|
||||
): string | null {
|
||||
if (email && emailToLogin[email]) {
|
||||
return emailToLogin[email];
|
||||
}
|
||||
|
||||
if (email && email.endsWith("@users.noreply.github.com")) {
|
||||
const local = email.split("@", 1)[0];
|
||||
const login = local.includes("+") ? local.split("+")[1] : local;
|
||||
return login || null;
|
||||
}
|
||||
|
||||
if (email && email.endsWith("@github.com")) {
|
||||
const login = email.split("@", 1)[0];
|
||||
if (apiByLogin.has(login.toLowerCase())) {
|
||||
return login;
|
||||
}
|
||||
}
|
||||
|
||||
const normalized = normalizeName(name);
|
||||
if (nameToLogin[normalized]) {
|
||||
return nameToLogin[normalized];
|
||||
}
|
||||
|
||||
const compact = normalized.replace(/\s+/g, "");
|
||||
if (nameToLogin[compact]) {
|
||||
return nameToLogin[compact];
|
||||
}
|
||||
|
||||
if (apiByLogin.has(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
if (apiByLogin.has(compact)) {
|
||||
return compact;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user