From 7afc6a1b3350974541a6d03c90887789d49efede Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Sun, 23 Aug 2026 00:18:32 +0800 Subject: [PATCH] docs: refresh team and contributor credits --- README.md | 19 +++++-- scripts/update_readme_contributors.py | 79 +++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 scripts/update_readme_contributors.py diff --git a/README.md b/README.md index 716241d0e..a735b5887 100644 --- a/README.md +++ b/README.md @@ -328,15 +328,24 @@ Use nanobot for a real task, report what broke, and then pick a focused improvem - Browse [open issues](https://github.com/HKUDS/nanobot/issues) for problems to investigate. - Open a [pull request](https://github.com/HKUDS/nanobot/pulls) for a focused fix or integration. -## Contact +## Team -Nanobot was started by [Xubin Ren](https://github.com/re-bin) as a personal open-source project and is now maintained collaboratively with contributors from the open-source community. Feel free to contact [xubinrencs@gmail.com](mailto:xubinrencs@gmail.com) for questions, ideas, or collaboration. +Nanobot was started by [Xubin Ren](https://github.com/re-bin) as a personal open-source project. Today, Xubin, [Yongru Chen](https://github.com/chengyongru), and contributors from the open-source community maintain it voluntarily. Feel free to contact [xubinrencs@gmail.com](mailto:xubinrencs@gmail.com) for questions, ideas, or collaboration. ### Contributors - - Contributors - + +Re-binchengyongruAthemisaxelray-devyorkhellen04cbsanthrealyu-xin-cxcosmosboxkunalk16
+chaohuang-aizayfodnikolasdehorJiajunBernoulliflobo3hamb1ySergioSV96KDB-Windmorandotcoldxiangyu163
+boogieLingmichaelxeraiguozhi123456pinhua33pixan-aihussein1362alekwohaosenwang1018IlyaGusevT3chC0wb0y
+VITOHJLmacroadsterHinotoi-agentkingassunegoodtiding5kiplangatkorirelkaixKimGLeem11yLingaoM
+DaryeDevCJWTRUSTxzq-xupikaxingearcdrake22JackLuguibinHaisamAbbasanunay999flaviovsC-Li
+Ho1yShifpjhobermannghiahsgsBahtyatangtaizong666XJPeng12yanghan-cyberZhouJ-shYuxin-LouLeoFYH
+claudechris-alexanderbenlenartsoutlook84Mrartramonpaolohuhu-tigertangjiabinyeyitechFlinn-X
+bingqilinweimaotaiQinnnnnnHengWeiBinwaelantartanishraolgagagamasterlyjxgzlucariodzydzydzy7dajiaohuang
+concertypinWangCheng0116yarikopticlukemilbygongpx20069tobrienShinieseshawnWXNsbyininnne998
+lahumanhlgonefranciscomaestrefat-operatorshixi-liwho96cyzlmhzhuzhhzpljd258 +

Thanks for visiting ✨ nanobot!

diff --git a/scripts/update_readme_contributors.py b/scripts/update_readme_contributors.py new file mode 100644 index 000000000..644a8c4ed --- /dev/null +++ b/scripts/update_readme_contributors.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +"""Refresh the native contributor avatar wall in README.md.""" + +from __future__ import annotations + +import argparse +import json +import os +from pathlib import Path +from urllib.request import Request, urlopen + +REPOSITORY = "HKUDS/nanobot" +README = Path(__file__).resolve().parents[1] / "README.md" +START = "" +END = "" +MAX_CONTRIBUTORS = 100 +AVATARS_PER_ROW = 10 + + +def fetch_contributors() -> list[dict[str, str]]: + headers = { + "Accept": "application/vnd.github+json", + "User-Agent": "nanobot-readme", + "X-GitHub-Api-Version": "2022-11-28", + } + if token := os.environ.get("GITHUB_TOKEN"): + headers["Authorization"] = f"Bearer {token}" + + url = f"https://api.github.com/repos/{REPOSITORY}/contributors?per_page={MAX_CONTRIBUTORS}" + with urlopen(Request(url, headers=headers), timeout=30) as response: # noqa: S310 + contributors = json.load(response) + + return [ + contributor + for contributor in contributors + if contributor.get("login") + and contributor.get("type") != "Bot" + and not contributor["login"].lower().endswith("[bot]") + ] + + +def render_wall(contributors: list[dict[str, str]]) -> str: + avatars = [ + ( + f'' + f'{contributor[' + ) + for contributor in contributors + ] + rows = [ + "".join(avatars[index : index + AVATARS_PER_ROW]) + for index in range(0, len(avatars), AVATARS_PER_ROW) + ] + wall = "
\n".join(rows) + return f"{START}\n{wall}\n{END}" + + +def update_readme(*, check: bool) -> bool: + current = README.read_text() + before, separator, tail = current.partition(START) + if not separator or END not in tail: + raise SystemExit("README contributor markers are missing") + + _, _, after = tail.partition(END) + updated = f"{before}{render_wall(fetch_contributors())}{after}" + if updated == current: + return False + if check: + raise SystemExit("README contributor wall is out of date") + README.write_text(updated) + return True + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check", action="store_true", help="fail when README.md is out of date") + args = parser.parse_args() + print("Updated README.md" if update_readme(check=args.check) else "README.md is current")