mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
PR #6656 added rel_path + \x00 prefixing to ``bundle_content_hash`` so a filename swap between two files in a bundle changes the digest. But it only patched the in-memory side — ``content_hash`` in ``tools/skills_guard.py`` (the on-disk equivalent) still hashed file contents only. These two functions need to stay symmetric: ``check_for_skill_updates`` compares the disk hash of an installed skill against the bundle hash of the upstream copy. With the asymmetric fix, every clean install showed as drifted because the digests no longer matched (2 existing tests in ``test_skills_hub.py`` started failing as soon as the contributor's change landed). Apply the same ``rel_path + \x00 + content`` shape to the disk-side function. Both functions now produce the same digest for the same skill content laid out two ways. Documented the symmetry invariant in the docstring so a future change to either function knows to touch both. Also adds tests/tools/test_pr_6656_regressions.py with 10 regression tests covering all three fixes salvaged in PR #6656: - uninstall_skill path traversal (4 cases: parent segments, absolute paths, symlink escape, legitimate skill) - bundle_content_hash filename swap detection (4 cases: in-memory swap, identity, disk-side swap, bundle↔disk symmetry) - list_pending lock contract (2 cases: source-grep contract, smoke) Also fixes AUTHOR_MAP entry for @aaronlab — their commit email (1115117931@qq.com) maps to "aaronagent" which isn't a real GitHub login, so changelog @mentions would 404.
1864 lines
88 KiB
Python
Executable file
1864 lines
88 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Hermes Agent Release Script
|
|
|
|
Generates changelogs and creates GitHub releases with CalVer tags.
|
|
|
|
Usage:
|
|
# Preview changelog (dry run)
|
|
python scripts/release.py
|
|
|
|
# Preview with semver bump
|
|
python scripts/release.py --bump minor
|
|
|
|
# Create the release
|
|
python scripts/release.py --bump minor --publish
|
|
|
|
# First release (no previous tag)
|
|
python scripts/release.py --bump minor --publish --first-release
|
|
|
|
# Override CalVer date (e.g. for a belated release)
|
|
python scripts/release.py --bump minor --publish --date 2026.3.15
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from collections import defaultdict
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
VERSION_FILE = REPO_ROOT / "hermes_cli" / "__init__.py"
|
|
PYPROJECT_FILE = REPO_ROOT / "pyproject.toml"
|
|
|
|
# ACP Registry manifest must stay version-locked with pyproject.toml.
|
|
# tests/acp/test_registry_manifest.py enforces this lockstep so the release
|
|
# bump touches both files atomically.
|
|
ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# Git email → GitHub username mapping
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
|
|
# Auto-extracted from noreply emails + manual overrides
|
|
AUTHOR_MAP = {
|
|
# teknium (multiple emails)
|
|
"teknium1@gmail.com": "teknium1",
|
|
"cipherframe@users.noreply.github.com": "CipherFrame",
|
|
"me@promplate.dev": "CNSeniorious000",
|
|
"yichengqiao21@gmail.com": "YarrowQiao",
|
|
"erhanyasarx@gmail.com": "erhnysr",
|
|
"30366221+WorldWriter@users.noreply.github.com": "WorldWriter",
|
|
"dafeng@DafengdeMacBook-Pro.local": "WorldWriter",
|
|
"anadi.jaggia@gmail.com": "Jaggia",
|
|
"32201324+simpolism@users.noreply.github.com": "simpolism",
|
|
"simpolism@gmail.com": "simpolism",
|
|
"jake@nousresearch.com": "simpolism",
|
|
"mgongzai@gmail.com": "vKongv",
|
|
"0x.badfriend@gmail.com": "discodirector",
|
|
"altriatree@gmail.com": "TruaShamu",
|
|
"contact-me@stark-x.cn": "Stark-X",
|
|
"nat@nthrow.io": "nthrow",
|
|
"m@mobrienv.dev": "mikeyobrien",
|
|
"saeed919@pm.me": "falasi",
|
|
"chrisdlc119@outlook.com": "chdlc",
|
|
"omar@techdeveloper.site": "nycomar",
|
|
"qiyin.zuo@pcitc.com": "qiyin-code",
|
|
"mr.aashiz@gmail.com": "aashizpoudel",
|
|
"70629228+shaun0927@users.noreply.github.com": "shaun0927",
|
|
"98262967+Bihruze@users.noreply.github.com": "Bihruze",
|
|
"189280367+Lempkey@users.noreply.github.com": "Lempkey",
|
|
"leovillalbajr@gmail.com": "Lempkey",
|
|
"nidhi2894@gmail.com": "nidhi-singh02",
|
|
"30312689+aashizpoudel@users.noreply.github.com": "aashizpoudel",
|
|
"oleksii.lisikh@gmail.com": "olisikh",
|
|
"jithendranaidunara@gmail.com": "JithendraNara",
|
|
"jeremy@geocaching.com": "outdoorsea",
|
|
"leone.parise@gmail.com": "leoneparise",
|
|
"mr@shu.io": "mrshu",
|
|
"adam.manning@gmail.com": "am423",
|
|
"buraysandro9@gmail.com": "ygd58",
|
|
"108427749+buntingszn@users.noreply.github.com": "buntingszn",
|
|
"yanglongwei06@gmail.com": "Alex-yang00",
|
|
"teknium@nousresearch.com": "teknium1",
|
|
"markuscontasul@gmail.com": "Glucksberg",
|
|
"piyushvp1@gmail.com": "thelumiereguy",
|
|
"dskwelmcy@163.com": "dskwe",
|
|
"421774554@qq.com": "wuli666",
|
|
"twebefy@gmail.com": "tw2818",
|
|
"harish.kukreja@gmail.com": "counterposition",
|
|
"korkyzer@gmail.com": "Korkyzer",
|
|
"1046611633@qq.com": "zhengyn0001",
|
|
"1095245867@qq.com": "littlewwwhite",
|
|
"db@project-aeon.com": "db-aeon",
|
|
"ahmed@abadr.net": "ahmedbadr3",
|
|
"63822243+CoinTheHat@users.noreply.github.com": "CoinTheHat",
|
|
"cleo@edaphic.xyz": "curiouscleo",
|
|
"hirokazu.ogawa@kwansei.ac.jp": "hrkzogw",
|
|
"datapod.k@gmail.com": "dandacompany",
|
|
"treydong.zh@gmail.com": "TreyDong",
|
|
"phil.thomas@gametime.co": "explainanalyze",
|
|
"kyanam.preetham@gmail.com": "pkyanam",
|
|
"zhizhong.xu@shopee.com": "1000Delta",
|
|
"30397170+1000Delta@users.noreply.github.com": "1000Delta",
|
|
"szymonclawd@mac.home": "szymonclawd",
|
|
"257759490+szymonclawd@users.noreply.github.com": "szymonclawd",
|
|
"101180447+worlldz@users.noreply.github.com": "worlldz",
|
|
"zhanganzhe@tenclass.com": "luoyuctl",
|
|
"51604064+luoyuctl@users.noreply.github.com": "luoyuctl",
|
|
"127238744+teknium1@users.noreply.github.com": "teknium1",
|
|
"tolle.lege+github@gmail.com": "InB4DevOps",
|
|
"73686890+InB4DevOps@users.noreply.github.com": "InB4DevOps",
|
|
"147827411+EloquentBrush@users.noreply.github.com": "AhmetArif0",
|
|
"97489706+purzbeats@users.noreply.github.com": "purzbeats",
|
|
"hugosequier@gmail.com": "Hugo-SEQUIER",
|
|
"kylejeong21@gmail.com": "Kylejeong2",
|
|
"128259593+Gutslabs@users.noreply.github.com": "Gutslabs",
|
|
"50326054+nocturnum91@users.noreply.github.com": "nocturnum91",
|
|
"52470719+gianfrancopiana@users.noreply.github.com": "gianfrancopiana",
|
|
"223003280+Abd0r@users.noreply.github.com": "Abd0r",
|
|
"HuangYuChuh@users.noreply.github.com": "HuangYuChuh",
|
|
"aaronwong1989@gmail.com": "hrygo",
|
|
"26729613+hrygo@users.noreply.github.com": "hrygo",
|
|
"erenkar950@gmail.com": "eren-karakus0",
|
|
"aubrey@freeman-wisco.com": "Freeman-Consulting",
|
|
"don.rhm@gmail.com": "rahimsais",
|
|
"40222899+rahimsais@users.noreply.github.com": "rahimsais",
|
|
"alfred@Alfreds-Mac-mini.local": "NivOO5",
|
|
"231191380+NivOO5@users.noreply.github.com": "NivOO5",
|
|
"jameshuang@gmail.com": "kjames2001",
|
|
"62420081+kjames2001@users.noreply.github.com": "kjames2001",
|
|
"132184373+wilsen0@users.noreply.github.com": "wilsen0",
|
|
"ra2157218@gmail.com": "Abd0r",
|
|
"oswaldb22@users.noreply.github.com": "oswaldb22",
|
|
"abdielv@proton.me": "AJV20",
|
|
"mason@growagainorchids.com": "masonjames",
|
|
"108541149+amethystani@users.noreply.github.com": "amethystani",
|
|
"ytchen0719@gmail.com": "liquidchen",
|
|
"am@studio1.tailb672fe.ts.net": "subtract0",
|
|
"mike@grossmann.at": "ReqX",
|
|
"axmaiqiu@gmail.com": "qWaitCrypto",
|
|
"44045911+kidonng@users.noreply.github.com": "kidonng",
|
|
"daniellsmarta@gmail.com": "DanielLSM",
|
|
"264291321+v1b3coder@users.noreply.github.com": "v1b3coder",
|
|
"silverchris@foxmail.com": "ming1523",
|
|
"maksesipov@gmail.com": "Qwinty",
|
|
"denisamania@gmail.com": "CalmProton",
|
|
"308068+mbac@users.noreply.github.com": "mbac",
|
|
"nicoechaniz@altermundi.net": "nicoechaniz",
|
|
"ninso112@proton.me": "Ninso112",
|
|
"wesleysimplicio@live.com": "wesleysimplicio",
|
|
"matthew.dean.cater@gmail.com": "SiliconID",
|
|
"xieniu@proton.me": "xieNniu",
|
|
"rw8143a@american.edu": "wali-reheman",
|
|
"egitimviscara@gmail.com": "uzunkuyruk",
|
|
"zhekinmaksim@gmail.com": "Zhekinmaksim",
|
|
"obafemiferanmi1999@gmail.com": "KvnGz",
|
|
"159539633+MottledShadow@users.noreply.github.com": "MottledShadow",
|
|
"aludwin+gh@gmail.com": "adamludwin",
|
|
"ngusev@astralinux.ru": "NikolayGusev-astra",
|
|
"liuguangyong201@hellobike.com": "liuguangyong93",
|
|
"2093036+exiao@users.noreply.github.com": "exiao",
|
|
"20nik.nosov21@gmail.com": "nik1t7n",
|
|
"thunderggnn@gmail.com": "ggnnggez",
|
|
"haozhe4547@gmail.com": "ehz0ah",
|
|
"eloklam2002@gmail.com": "eloklam",
|
|
"kevyan1998@gmail.com": "kyan12",
|
|
"rylen.anil@gmail.com": "rylena",
|
|
"godnanijatin@gmail.com": "jatingodnani",
|
|
"252811164+adybag14-cyber@users.noreply.github.com": "adybag14-cyber",
|
|
"14046872+tmimmanuel@users.noreply.github.com": "tmimmanuel",
|
|
"112875006+donramon77@users.noreply.github.com": "donramon77",
|
|
"657290301@qq.com": "IMHaoyan",
|
|
"revar@users.noreply.github.com": "revaraver",
|
|
"dengtaoyuan@dengtaoyuandeMac-mini.local": "dengtaoyuan450-a11y",
|
|
"ysfalweshcan@gmail.com": "Junass1",
|
|
"bartokmagic@proton.me": "Bartok9",
|
|
"bartok9@users.noreply.github.com": "Bartok9",
|
|
"erhanyasarx@gmail.com": "erhnysr", # PR #25198 salvage (tool-progress flood-control)
|
|
"cryptobyz.airdrop@gmail.com": "CryptoByz", # PR #25630 salvage (polling conflict Stage 1+2)
|
|
"fabioxxx@gmail.com": "fabiosiqueira", # PR #27212 salvage (bg-process notif anchor)
|
|
"lordfalcon.exe@gmail.com": "falconexe", # PR #24511 salvage (sticky-IP reset)
|
|
"fonhal@gmail.com": "fonhal", # PR #27865/#27861 salvage (mention entities / typing fallback)
|
|
"zyrixtrex@gmail.com": "Zyrixtrex", # PR #26754 salvage (avoid duplicate text after auto-TTS)
|
|
"264138787+nftpoetrist@users.noreply.github.com": "nftpoetrist", # PR #25856 salvage (escape slash-confirm preview)
|
|
"197455947+samahn0601@users.noreply.github.com": "samahn0601", # PR #27887 salvage (retry wrapped connect timeouts)
|
|
"gonzes7@gmail.com": "aqilaziz", # PR #26406 salvage (preserve native audio outside Telegram)
|
|
"karthikeyann@users.noreply.github.com": "karthikeyann", # PR #26609 salvage (DM-topic routing pin)
|
|
"rino.alpin@gmail.com": "kunci115", # PR #27098 salvage (thread-not-found retry)
|
|
"237601532+chromalinx@users.noreply.github.com": "chromalinx", # PR #27014 salvage (commands for groups+DM)
|
|
"booker1207@gmail.com": "booker1207", # PR #25132 salvage (gate profile bots by allowed topics)
|
|
"kiranvk2011@gmail.com": "kiranvk-2011", # PR #24815 salvage (image documents → vision)
|
|
"kosmonaut-t@centrum.cz": "rak135", # PR #25960 salvage (Windows /restart)
|
|
"bot.chi.online@gmail.com": "B0Tch1", # PR #27634 salvage (disable_topic_auto_rename)
|
|
"1037461232@qq.com": "jackjin1997", # PR #27239 salvage (restore DM topic thread_id after split)
|
|
"soynchuux@gmail.com": "soynchux", # PR #27806 salvage (chat-scoped auth without user_id)
|
|
"psikonetik@gmail.com": "el-analista", # PR #25368 salvage (cron topic fallback report)
|
|
"75435655+khungate@users.noreply.github.com": "khungate", # PR #25829 salvage (gmail-triage gt: callbacks)
|
|
"stevehq26-bot@users.noreply.github.com": "stevehq26-bot", # PR #28015 salvage (quick-command-only menus)
|
|
"seaverb@icloud.com": "brndnsvr", # PR #25327 salvage (channel post updates)
|
|
"oracle@jarviss-mbp.home": "houenyang-momo", # PR #24014 salvage (quiet noisy errors)
|
|
"57119977+OCWC22@users.noreply.github.com": "OCWC22", # PR #24581 salvage (multi-bot exclusive mentions)
|
|
"ai-hana-ai@users.noreply.github.com": "ai-hana-ai", # PR #23928 salvage (ignore_root_dm)
|
|
"mx.indigo.karasu@gmail.com": "indigokarasu", # PR #26636 salvage (pin user message)
|
|
"516972+alber70g@users.noreply.github.com": "alber70g", # PR #25280 salvage (skip-STT + 2GB cap)
|
|
"282919977+eliteworkstation94-ai@users.noreply.github.com": "eliteworkstation94-ai", # PR #28157 salvage (group reply session splits)
|
|
"androidhtml@yandex.com": "hllqkb",
|
|
"25840394+Bongulielmi@users.noreply.github.com": "Bongulielmi",
|
|
"jonathan.troyer@overmatch.com": "JTroyerOvermatch",
|
|
"harryykyle1@gmail.com": "hharry11",
|
|
"wysie@users.noreply.github.com": "wysie",
|
|
"jkausel@gmail.com": "jkausel-ai",
|
|
"e.silacandmr@gmail.com": "Es1la",
|
|
"51599529+stephen0110@users.noreply.github.com": "stephen0110",
|
|
"265632032+sonic-netizen@users.noreply.github.com": "sonic-netizen",
|
|
"82531659+mwnickerson@users.noreply.github.com": "mwnickerson",
|
|
"sandrohub013@gmail.com": "SandroHub013",
|
|
"maciekczech@users.noreply.github.com": "maciekczech",
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
|
"zjtan1@gmail.com": "zeejaytan",
|
|
"asslaenn5@gmail.com": "Aslaaen",
|
|
"trae.anderson17@icloud.com": "Tkander1715",
|
|
"beardthelion@users.noreply.github.com": "beardthelion",
|
|
"tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc",
|
|
"leon@agentlinker.ai": "agentlinker",
|
|
"santoshhumagain1887@gmail.com": "npmisantosh",
|
|
"39641663+luarss@users.noreply.github.com": "luarss",
|
|
"16263913+zccyman@users.noreply.github.com": "zccyman",
|
|
"zccyman@users.noreply.github.com": "zccyman", # PR #26998 (auxiliary fallback chain)
|
|
"ahmetosrak@Ahmet-MacBook-Air.local": "Osraka",
|
|
"98612432+Osraka@users.noreply.github.com": "Osraka",
|
|
"112634774+ryptotalent@users.noreply.github.com": "ryptotalent",
|
|
"270097726+hookinglau@users.noreply.github.com": "hookinglau",
|
|
"5029547+AllynSheep@users.noreply.github.com": "AllynSheep",
|
|
"allyn0306@gmail.com": "AllynSheep",
|
|
"46887634+aqilaziz@users.noreply.github.com": "aqilaziz",
|
|
"gonzes7@gmail.com": "aqilaziz",
|
|
"6966326+laoli-no1@users.noreply.github.com": "laoli-no1",
|
|
"laoli_no1@163.com": "laoli-no1",
|
|
"39730900+NorethSea@users.noreply.github.com": "NorethSea",
|
|
"963979204@qq.com": "NorethSea",
|
|
"2283389+JamesX88@users.noreply.github.com": "JamesX88",
|
|
"JamesX88@users.noreply.github.com": "JamesX88",
|
|
"novax635@gmail.com": "novax635",
|
|
"krionex1@gmail.com": "Krionex",
|
|
"rxdxxxx@users.noreply.github.com": "rxdxxxx",
|
|
"ma.haohao2@xydigit.com": "MaHaoHao-ch",
|
|
"29756950+revaraver@users.noreply.github.com": "revaraver",
|
|
"nexus@eptic.me": "TheEpTic",
|
|
"74554762+wmagev@users.noreply.github.com": "wmagev",
|
|
"ashermorse@icloud.com": "ashermorse",
|
|
"happy5318@users.noreply.github.com": "happy5318",
|
|
"anatoliygranichenko@gmail.com": "wabrent",
|
|
"cash.williams@acquia.com": "CashWilliams",
|
|
"chengoak@users.noreply.github.com": "chengoak",
|
|
"mrhanoi@outlook.com": "qxxaa",
|
|
"guillaume.meyer@outlook.com": "guillaumemeyer",
|
|
"emelyanenko.kirill@gmail.com": "EmelyanenkoK",
|
|
"lazycat.manatee@gmail.com": "manateelazycat",
|
|
"bzarnitz13@gmail.com": "Beandon13",
|
|
"tony@tonysimons.dev": "asimons81",
|
|
"jetha@google.com": "jethac",
|
|
"jani@0xhoneyjar.xyz": "deep-name",
|
|
# LINE messaging plugin (synthesis PR)
|
|
"32443648+leepoweii@users.noreply.github.com": "leepoweii",
|
|
"openclaw@liyangchen.me": "liyoungc",
|
|
"charles@perng.com": "perng",
|
|
"soichiro0111.dev@gmail.com": "soichiyo",
|
|
"0xde@pieverse.io": "David-0x221Eight",
|
|
"77736378+David-0x221Eight@users.noreply.github.com": "David-0x221Eight",
|
|
"74749461+yuga-hashimoto@users.noreply.github.com": "yuga-hashimoto",
|
|
"xiangyong@zspace.cn": "CES4751",
|
|
"harish.kukreja@gmail.com": "counterposition",
|
|
"nidhi2894@gmail.com": "nidhi-singh02",
|
|
"35294173+Fearvox@users.noreply.github.com": "Fearvox",
|
|
"hypnus.yuan@gmail.com": "Hypnus-Yuan",
|
|
"15558128926@qq.com": "xsfX20",
|
|
"binhnt.ht.92@gmail.com": "binhnt92",
|
|
"johnny@Jons-MBA-M4.local": "acesjohnny",
|
|
"1581133593@qq.com": "liu-collab",
|
|
"haidaoe@proton.me": "haidao1919",
|
|
"50561768+zhanggttry@users.noreply.github.com": "zhanggttry",
|
|
"formulahendry@gmail.com": "formulahendry",
|
|
"93757150+bogerman1@users.noreply.github.com": "bogerman1",
|
|
"132852777+rob-maron@users.noreply.github.com": "rob-maron",
|
|
# Matrix parity salvage batch (April 2026)
|
|
"sr@samirusani": "samrusani",
|
|
"angelclaw@AngelMacBook.local": "angel12",
|
|
"charles@cryptoassetrecovery.com": "charles-brooks",
|
|
# DeepSeek v4 + Kimi thinking-mode reasoning_content salvage (April 2026)
|
|
"luwinyang@deepseek.com": "lsdsjy",
|
|
"season.saw@gmail.com": "season179",
|
|
"heathley@Heathley-MacBook-Air.local": "heathley",
|
|
"maliyldzhn@gmail.com": "heathley",
|
|
"vlad19@gmail.com": "dandaka",
|
|
"adamrummer@gmail.com": "cyclingwithelephants",
|
|
# Temporary tool-progress cleanup salvage (May 2026)
|
|
"Mrcharlesiv@gmail.com": "mrcharlesiv",
|
|
"nbot@liizfq.top": "liizfq",
|
|
"274096618+hermes-agent-dhabibi@users.noreply.github.com": "dhabibi",
|
|
"dejie.guo@gmail.com": "JayGwod",
|
|
"133716830+0xKingBack@users.noreply.github.com": "0xKingBack",
|
|
"daixin1204@gmail.com": "SimbaKingjoe",
|
|
"maxence@groine.fr": "MaxyMoos",
|
|
"61830395+leprincep35700@users.noreply.github.com": "leprincep35700",
|
|
# OpenViking viking_read salvage (April 2026)
|
|
"hitesh@gmail.com": "htsh",
|
|
"pty819@outlook.com": "pty819",
|
|
"pty819@users.noreply.github.com": "pty819",
|
|
"14341805+pty819@users.noreply.github.com": "pty819",
|
|
"517024110@qq.com": "chennest",
|
|
# Curator fixes (Apr 30 2026)
|
|
"yuxiangl490@gmail.com": "y0shua1ee",
|
|
"manmit0x@gmail.com": "0xDevNinja",
|
|
"stevekelly622@gmail.com": "steezkelly",
|
|
"brian@dralth.com": "btorresgil",
|
|
"momowind@gmail.com": "momowind",
|
|
"clockwork-codex@users.noreply.github.com": "misery-hl",
|
|
"207811921+misery-hl@users.noreply.github.com": "misery-hl",
|
|
"20nik.nosov21@gmail.com": "nik1t7n",
|
|
"90299797+nik1t7n@users.noreply.github.com": "nik1t7n",
|
|
"suncokret@protonmail.com": "suncokret12",
|
|
"mio.imoto.ai@gmail.com": "mioimotoai-lgtm",
|
|
"aamirjawaid@microsoft.com": "heyitsaamir",
|
|
"johnnncenaaa77@gmail.com": "johnncenae",
|
|
"thomasjhon6666@gmail.com": "ThomassJonax",
|
|
"focusflow.app.help@gmail.com": "yes999zc",
|
|
"rob@atlas.lan": "rmoen",
|
|
# Slack ephemeral slash-ack salvage (May 2026)
|
|
"probepark@users.noreply.github.com": "probepark",
|
|
# Slack batch salvage (May 2026)
|
|
"280484231+prive-fe-bot@users.noreply.github.com": "priveperfumes",
|
|
"amr@ghanem.sa": "amroessam",
|
|
"paperlantern.agent@gmail.com": "Hinotoi-agent",
|
|
"valda@underscore.jp": "valda",
|
|
"162235745+0z1-ghb@users.noreply.github.com": "0z1-ghb",
|
|
"yes999zc@163.com": "yes999zc",
|
|
"343873859@qq.com": "DrStrangerUJN",
|
|
"252818347@qq.com": "hejuntt1014",
|
|
"uzmpsk.dilekakbas@gmail.com": "dlkakbs",
|
|
"beliefanx@gmail.com": "BeliefanX",
|
|
"changchun989@proton.me": "changchun989",
|
|
"jefferson@heimdallstrategy.com": "Mind-Dragon",
|
|
"44753291+Nanako0129@users.noreply.github.com": "Nanako0129",
|
|
"steve.westerhouse@origami-analytics.com": "westers",
|
|
"yeyitech@users.noreply.github.com": "yeyitech",
|
|
"260878550+beenherebefore@users.noreply.github.com": "beenherebefore",
|
|
"79389617+txbxxx@users.noreply.github.com": "txbxxx",
|
|
"liuhao03@bilibili.com": "liuhao1024",
|
|
"130918800+devorun@users.noreply.github.com": "devorun",
|
|
"surat.s@itm.kmutnb.ac.th": "beesrsj2500",
|
|
"beesr@bee.localdomain": "beesrsj2500",
|
|
"mind-dragon@nous.research": "Mind-Dragon",
|
|
"juntingpublic@gmail.com": "JustinUssuri",
|
|
"mtf201013@gmail.com": "ma-pony",
|
|
"sonoyuncudmr@gmail.com": "Sonoyunchu",
|
|
"43525405+yatesjalex@users.noreply.github.com": "yatesjalex",
|
|
"maks.mir@yahoo.com": "say8hi",
|
|
"27719690+Mirac1eSky@users.noreply.github.com": "Mirac1eSky",
|
|
"web3blind@users.noreply.github.com": "web3blind",
|
|
"julia@alexland.us": "alexg0bot",
|
|
"christian@scheid.tech": "scheidti",
|
|
# Moonshot schema anyOf+enum salvage (May 2026)
|
|
"git@local.invalid": "hendrixfreire",
|
|
"1060770+benjaminsehl@users.noreply.github.com": "benjaminsehl",
|
|
"nerijusn76@gmail.com": "Nerijusas",
|
|
# Compaction salvage batch (May 2026)
|
|
"MacroAnarchy@users.noreply.github.com": "MacroAnarchy",
|
|
"itonov@proton.me": "Ito-69",
|
|
"glesstech@gmail.com": "georgeglessner",
|
|
"maxim.smetanin@gmail.com": "maxims-oss",
|
|
# Codex Spark restoration salvage (May 2026)
|
|
"olegwn@gmail.com": "nederev",
|
|
"vesper@askclaw.dev": "askclaw-vesper",
|
|
"nazirulhafiy@gmail.com": "nazirulhafiy",
|
|
"CREWorx@users.noreply.github.com": "BadTechBandit",
|
|
"yoimexex@gmail.com": "Yoimex",
|
|
"6548898+romanornr@users.noreply.github.com": "romanornr",
|
|
"foxion37@gmail.com": "foxion37",
|
|
"bloodcarter@gmail.com": "bloodcarter",
|
|
"scott@scotttrinh.com": "scotttrinh",
|
|
"quocanh261997@gmail.com": "quocanh261997",
|
|
"savanne.kham@protonmail.com": "savanne-kham", # PR #28958 salvage (strip tool_name for strict providers)
|
|
# contributors (from noreply pattern)
|
|
"david.vv@icloud.com": "davidvv",
|
|
"wangqiang@wangqiangdeMac-mini.local": "xiaoqiang243",
|
|
"snreynolds2506@gmail.com": "snreynolds",
|
|
"35742124+0xbyt4@users.noreply.github.com": "0xbyt4",
|
|
"71184274+MassiveMassimo@users.noreply.github.com": "MassiveMassimo",
|
|
"massivemassimo@users.noreply.github.com": "MassiveMassimo",
|
|
"82637225+kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
|
"keifergu@tencent.com": "keifergu",
|
|
"kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
|
"SHL0MS@users.noreply.github.com": "SHL0MS",
|
|
"abner.the.foreman@agentmail.to": "Abnertheforeman",
|
|
"adam.manning@pro-serveinc.com": "amanning3390",
|
|
"thomasgeorgevii09@gmail.com": "tochukwuada",
|
|
"sb@wmc.sh": "zicochaos",
|
|
"harryykyle1@gmail.com": "hharry11",
|
|
"kshitijk4poor@gmail.com": "kshitijk4poor",
|
|
"1294707+Tosko4@users.noreply.github.com": "Tosko4",
|
|
"keira.voss94@gmail.com": "keiravoss94",
|
|
"16443023+stablegenius49@users.noreply.github.com": "stablegenius49",
|
|
"fqsy1416@gmail.com": "EKKOLearnAI",
|
|
"octo-patch@github.com": "octo-patch",
|
|
"math0r-be@github.com": "math0r-be",
|
|
"simbamax99@gmail.com": "simbam99",
|
|
"iris@growthpillars.co": "irispillars",
|
|
"185121704+stablegenius49@users.noreply.github.com": "stablegenius49",
|
|
"101283333+batuhankocyigit@users.noreply.github.com": "batuhankocyigit",
|
|
"255305877+ismell0992-afk@users.noreply.github.com": "ismell0992-afk",
|
|
"cyprian@ironin.pl": "iRonin",
|
|
"valdi.jorge@gmail.com": "jvcl",
|
|
"q19dcp@gmail.com": "aj-nt",
|
|
"ebukau84@gmail.com": "UgwujaGeorge",
|
|
"francip@gmail.com": "francip",
|
|
"omni@comelse.com": "omnissiah-comelse",
|
|
"oussama.redcode@gmail.com": "mavrickdeveloper",
|
|
"126368201+vilkasdev@users.noreply.github.com": "vilkasdev",
|
|
"137614867+cutepawss@users.noreply.github.com": "cutepawss",
|
|
"96793918+memosr@users.noreply.github.com": "memosr",
|
|
"mehmet.sr35@gmail.com": "memosr",
|
|
"milkoor@users.noreply.github.com": "milkoor",
|
|
"xuerui911@gmail.com": "Fatty911",
|
|
"131039422+SHL0MS@users.noreply.github.com": "SHL0MS",
|
|
"77628552+raulvidis@users.noreply.github.com": "raulvidis",
|
|
"145567217+Aum08Desai@users.noreply.github.com": "Aum08Desai",
|
|
"256820943+kshitij-eliza@users.noreply.github.com": "kshitij-eliza",
|
|
"jiechengwu@pony.ai": "Jason2031",
|
|
"44278268+shitcoinsherpa@users.noreply.github.com": "shitcoinsherpa",
|
|
"104278804+Sertug17@users.noreply.github.com": "Sertug17",
|
|
"112503481+caentzminger@users.noreply.github.com": "caentzminger",
|
|
"258577966+voidborne-d@users.noreply.github.com": "voidborne-d",
|
|
"3820588+ddupont808@users.noreply.github.com": "ddupont808",
|
|
"liusway405@gmail.com": "voidborne-d",
|
|
"xydarcher@uestc.edu.cn": "Readon",
|
|
"sir_even@icloud.com": "sirEven",
|
|
"36056348+sirEven@users.noreply.github.com": "sirEven",
|
|
"70424851+insecurejezza@users.noreply.github.com": "insecurejezza",
|
|
"jezzahehn@gmail.com": "JezzaHehn",
|
|
"barnacleboy.jezzahehn@agentmail.to": "JezzaHehn",
|
|
"254021826+dodo-reach@users.noreply.github.com": "dodo-reach",
|
|
"259807879+Bartok9@users.noreply.github.com": "Bartok9",
|
|
"270082434+crayfish-ai@users.noreply.github.com": "crayfish-ai",
|
|
"241404605+MestreY0d4-Uninter@users.noreply.github.com": "MestreY0d4-Uninter",
|
|
"268667990+Roy-oss1@users.noreply.github.com": "Roy-oss1",
|
|
"27917469+nosleepcassette@users.noreply.github.com": "nosleepcassette",
|
|
"241404605+MestreY0d4-Uninter@users.noreply.github.com": "MestreY0d4-Uninter",
|
|
"109555139+davetist@users.noreply.github.com": "davetist",
|
|
"39405770+yyq4193@users.noreply.github.com": "yyq4193",
|
|
"Asunfly@users.noreply.github.com": "Asunfly",
|
|
"2500400+honghua@users.noreply.github.com": "honghua",
|
|
"462836+jplew@users.noreply.github.com": "jplew",
|
|
"nish3451@users.noreply.github.com": "nish3451",
|
|
"Mibayy@users.noreply.github.com": "Mibayy",
|
|
"mibayy@users.noreply.github.com": "Mibayy",
|
|
"mibay@clawhub.io": "Mibayy",
|
|
"louismichalot@hotmail.com": "Mibayy",
|
|
"135070653+sgaofen@users.noreply.github.com": "sgaofen",
|
|
"lzy.dev@gmail.com": "zhiyanliu",
|
|
"me@janstepanovsky.cz": "hhhonzik",
|
|
"139848623+hhuang91@users.noreply.github.com": "hhuang91",
|
|
"s.ozaki@ebinou.net": "Satoshi-agi",
|
|
"10774721+kunlabs@users.noreply.github.com": "kunlabs",
|
|
"110560187+Wang-tianhao@users.noreply.github.com": "Wang-tianhao",
|
|
"170458616+ghostmfr@users.noreply.github.com": "ghostmfr",
|
|
"1848670+mewwts@users.noreply.github.com": "mewwts",
|
|
"1930707+haru398801@users.noreply.github.com": "haru398801",
|
|
"rapabelias@gmail.com": "badgerbees",
|
|
"xnb888@proton.me": "xnbi",
|
|
"xiahu889889@proton.me": "xiahu88988",
|
|
"nocoo@users.noreply.github.com": "nocoo",
|
|
"30841158+n-WN@users.noreply.github.com": "n-WN",
|
|
"tsuijinglei@gmail.com": "hiddenpuppy",
|
|
"buraysandro9@gmail.com": "ygd58",
|
|
"jerome@clawwork.ai": "HiddenPuppy",
|
|
"jerome.benoit@sap.com": "jerome-benoit",
|
|
"wysie@users.noreply.github.com": "Wysie",
|
|
"leoyuan0099@gmail.com": "keyuyuan",
|
|
"bxzt2006@163.com": "Only-Code-A",
|
|
"i@troy-y.org": "TroyMitchell911",
|
|
"mygamez@163.com": "zhongyueming1121",
|
|
"hansnow@users.noreply.github.com": "hansnow",
|
|
"134848055+UNLINEARITY@users.noreply.github.com": "UNLINEARITY",
|
|
"ben.burtenshaw@gmail.com": "burtenshaw",
|
|
"roopaknijhara@gmail.com": "rnijhara",
|
|
"josephzcan@gmail.com": "j0sephz",
|
|
# contributors (manual mapping from git names)
|
|
"ahmedsherif95@gmail.com": "asheriif",
|
|
"dyxushuai@gmail.com": "dyxushuai",
|
|
"33860762+etcircle@users.noreply.github.com": "etcircle",
|
|
"liujinkun@bytedance.com": "liujinkun2025",
|
|
"dmayhem93@gmail.com": "dmahan93",
|
|
"fr@tecompanytea.com": "ifrederico",
|
|
"cdanis@gmail.com": "cdanis",
|
|
"samherring99@gmail.com": "samherring99",
|
|
"desaiaum08@gmail.com": "Aum08Desai",
|
|
"shannon.sands.1979@gmail.com": "shannonsands",
|
|
"shannon@nousresearch.com": "shannonsands",
|
|
"abdi.moya@gmail.com": "AxDSan",
|
|
"eri@plasticlabs.ai": "Erosika",
|
|
"hjcpuro@gmail.com": "hjc-puro",
|
|
"xaydinoktay@gmail.com": "aydnOktay",
|
|
"abdullahfarukozden@gmail.com": "Farukest",
|
|
"lovre.pesut@gmail.com": "rovle",
|
|
"xjtumj@gmail.com": "mengjian-github",
|
|
"kevinskysunny@gmail.com": "kevinskysunny",
|
|
"xiewenxuan462@gmail.com": "yule975",
|
|
"yiweimeng.dlut@hotmail.com": "meng93",
|
|
"hakanerten02@hotmail.com": "teyrebaz33",
|
|
"linux2010@users.noreply.github.com": "Linux2010",
|
|
"elmatadorgh@users.noreply.github.com": "elmatadorgh",
|
|
"coktinbaran5@gmail.com": "elmatadorgh",
|
|
"alexazzjjtt@163.com": "alexzhu0",
|
|
"1180176+Swift42@users.noreply.github.com": "Swift42",
|
|
"ruzzgarcn@gmail.com": "Ruzzgar",
|
|
"yukipukikedy@gmail.com": "Yukipukii1",
|
|
"alireza78.crypto@gmail.com": "alireza78a",
|
|
"brooklyn.bb.nicholson@gmail.com": "brooklynnicholson",
|
|
"withapurpose37@gmail.com": "StefanIsMe",
|
|
"4317663+helix4u@users.noreply.github.com": "helix4u",
|
|
"ifkellx@users.noreply.github.com": "Ifkellx",
|
|
"331214+counterposition@users.noreply.github.com": "counterposition",
|
|
"blspear@gmail.com": "BrennerSpear",
|
|
"akhater@gmail.com": "akhater",
|
|
"Cos_Admin@PTG-COS.lodluvup4uaudnm3ycd14giyug.xx.internal.cloudapp.net": "akhater",
|
|
"239876380+handsdiff@users.noreply.github.com": "handsdiff",
|
|
"hesapacicam112@gmail.com": "etherman-os",
|
|
"mark.ramsell@rivermounts.com": "mark-ramsell",
|
|
"taeng02@icloud.com": "taeng0204",
|
|
"gpickett00@gmail.com": "gpickett00",
|
|
"mcosma@gmail.com": "wakamex",
|
|
"clawdia.nash@proton.me": "clawdia-nash",
|
|
"pickett.austin@gmail.com": "austinpickett",
|
|
"dangtc94@gmail.com": "dieutx",
|
|
"jaisehgal11299@gmail.com": "jaisup",
|
|
"percydikec@gmail.com": "PercyDikec",
|
|
"noonou7@gmail.com": "HenkDz",
|
|
# Azure Foundry salvage (PRs #9029, #4599, #10086, #8766)
|
|
"tech@smartlogics.net": "TechPrototyper",
|
|
"637186+HangGlidersRule@users.noreply.github.com": "HangGlidersRule",
|
|
"pein892@gmail.com": "pein892",
|
|
"dean.kerr@gmail.com": "deankerr",
|
|
"socrates1024@gmail.com": "socrates1024",
|
|
"seanalt555@gmail.com": "Salt-555",
|
|
"satelerd@gmail.com": "satelerd",
|
|
"dan@danlynn.com": "danklynn",
|
|
"mattmaximo@hotmail.com": "MattMaximo",
|
|
"MatthewRHardwick@gmail.com": "mrhwick",
|
|
"149063006+j3ffffff@users.noreply.github.com": "j3ffffff",
|
|
"A-FdL-Prog@users.noreply.github.com": "A-FdL-Prog",
|
|
"l0hde@users.noreply.github.com": "l0hde",
|
|
"difujia@users.noreply.github.com": "difujia",
|
|
"vominh1919@gmail.com": "vominh1919",
|
|
"yue.gu2023@gmail.com": "YueLich",
|
|
"51783311+andyylin@users.noreply.github.com": "andyylin",
|
|
"me@jakubkrcmar.cz": "jakubkrcmar",
|
|
"prasadus92@gmail.com": "prasadus92",
|
|
"michael@make.software": "mssteuer",
|
|
"der@konsi.org": "konsisumer",
|
|
"abogale2@gmail.com": "amanuel2",
|
|
"alexazzjjtt@163.com": "alexzhu0",
|
|
"pub_forgreatagent@antgroup.com": "AntAISecurityLab",
|
|
"252620095+briandevans@users.noreply.github.com": "briandevans",
|
|
"danielrpike9@gmail.com": "Bartok9",
|
|
"skozyuk@cruxexperts.com": "CruxExperts",
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
"12250313+Kailigithub@users.noreply.github.com": "Kailigithub",
|
|
"mgparkprint@gmail.com": "vlwkaos",
|
|
"1317078257maroon@gmail.com": "Oxidane-bot",
|
|
"tranquil_flow@protonmail.com": "Tranquil-Flow",
|
|
"LyleLengyel@gmail.com": "mcndjxlefnd",
|
|
"wangshengyang2004@163.com": "Wangshengyang2004",
|
|
"hasan.ali13381@gmail.com": "H-Ali13381",
|
|
"xienb@proton.me": "XieNBi",
|
|
"139681654+maymuneth@users.noreply.github.com": "maymuneth",
|
|
"zengwei@nightq.cn": "nightq",
|
|
"1434494126@qq.com": "5park1e",
|
|
"158153005+5park1e@users.noreply.github.com": "5park1e",
|
|
"innocarpe@gmail.com": "innocarpe",
|
|
"noreply@ked.com": "qike-ms",
|
|
"andrekurait@gmail.com": "AndreKurait",
|
|
"bsgdigital@users.noreply.github.com": "bsgdigital",
|
|
"numman.ali@gmail.com": "nummanali",
|
|
"rohithsaimidigudla@gmail.com": "whitehatjr1001",
|
|
"0xNyk@users.noreply.github.com": "0xNyk",
|
|
"0xnykcd@googlemail.com": "0xNyk",
|
|
"buraysandro9@gmail.com": "buray",
|
|
"contact@jomar.fr": "joshmartinelle",
|
|
"camilo@tekelala.com": "tekelala",
|
|
"vincentcharlebois@gmail.com": "vincentcharlebois",
|
|
"aryan@synvoid.com": "aryansingh",
|
|
"johnsonblake1@gmail.com": "voteblake",
|
|
"hcn518@gmail.com": "pedh",
|
|
"haileymarshall005@gmail.com": "haileymarshall",
|
|
"bennet.yr.wang@gmail.com": "BennetYrWang",
|
|
"greer.guthrie@gmail.com": "g-guthrie",
|
|
"kennyx102@gmail.com": "bobashopcashier",
|
|
"77253505+bobashopcashier@users.noreply.github.com": "bobashopcashier",
|
|
"25355950+megastary@users.noreply.github.com": "megastary", # PR #18325
|
|
"shokatalishaikh95@gmail.com": "areu01or00",
|
|
"bryan@intertwinesys.com": "bryanyoung",
|
|
"christo.mitov@gmail.com": "christomitov",
|
|
"hermes@nousresearch.com": "NousResearch",
|
|
"reginaldasr@gmail.com": "ReginaldasR",
|
|
"ntconguit@gmail.com": "0xharryriddle",
|
|
"agent@wildcat.local": "ericnicolaides",
|
|
"georgex8001@gmail.com": "georgex8001",
|
|
"stefan@dimagents.ai": "dimitrovi",
|
|
"hermes@noushq.ai": "benbarclay",
|
|
"chinmingcock@gmail.com": "ChimingLiu",
|
|
"allard.quek@singtel.com": "AllardQuek",
|
|
"openclaw@sparklab.ai": "openclaw",
|
|
"semihcvlk53@gmail.com": "Himess",
|
|
"erenkar950@gmail.com": "erenkarakus",
|
|
"adavyasharma@gmail.com": "adavyas",
|
|
"acaayush1111@gmail.com": "aayushchaudhary",
|
|
"jason@outland.art": "jasonoutland",
|
|
"73175452+Magaav@users.noreply.github.com": "Magaav",
|
|
"mrflu1918@proton.me": "SPANISHFLU",
|
|
"morganemoss@gmai.com": "mormio",
|
|
"kopjop926@gmail.com": "cesareth",
|
|
"fuleinist@gmail.com": "fuleinist",
|
|
"jack.47@gmail.com": "JackTheGit",
|
|
"jack@jackyang.com": "0xjackyang",
|
|
"dalvidjr2022@gmail.com": "Jr-kenny",
|
|
"m@statecraft.systems": "mbierling",
|
|
"balyan.sid@gmail.com": "alt-glitch",
|
|
"52913345+alt-glitch@users.noreply.github.com": "alt-glitch",
|
|
"oluwadareab12@gmail.com": "oluwadareab12",
|
|
"simon@simonmarcus.org": "simon-marcus",
|
|
"xowiekk@gmail.com": "Xowiek",
|
|
"1243352777@qq.com": "zons-zhaozhy",
|
|
"e.silacandmr@gmail.com": "Es1la",
|
|
"51599529+stephen0110@users.noreply.github.com": "stephen0110",
|
|
"265632032+sonic-netizen@users.noreply.github.com": "sonic-netizen",
|
|
"82531659+mwnickerson@users.noreply.github.com": "mwnickerson",
|
|
"sandrohub013@gmail.com": "SandroHub013",
|
|
"maciekczech@users.noreply.github.com": "maciekczech",
|
|
"h3057183414@gmail.com": "CoreyNoDream",
|
|
"franksong2702@gmail.com": "franksong2702",
|
|
"673088860@qq.com": "ambition0802",
|
|
"beibei1988@proton.me": "beibi9966",
|
|
# ── bulk addition: 75 emails resolved via API, PR salvage bodies, noreply
|
|
# crossref, and GH contributor list matching (April 2026 audit) ──
|
|
"1115117931@qq.com": "aaronlab",
|
|
"1506751656@qq.com": "hqhq1025",
|
|
"364939526@qq.com": "luyao618",
|
|
"hgk324@gmail.com": "houziershi",
|
|
"176644217+PStarH@users.noreply.github.com": "PStarH",
|
|
"51058514+Sanjays2402@users.noreply.github.com": "Sanjays2402",
|
|
"16577466+andy825@user.noreply.gitee.com": "Andy283",
|
|
"906014227@qq.com": "bingo906",
|
|
"aaronwong1999@icloud.com": "AaronWong1999",
|
|
"agents@kylefrench.dev": "DeployFaith",
|
|
"angelos@oikos.lan.home.malaiwah.com": "angelos",
|
|
"aptx4561@gmail.com": "cokemine",
|
|
"arilotter@gmail.com": "ethernet8023",
|
|
"ben@nousresearch.com": "benbarclay",
|
|
"birdiegyal@gmail.com": "yyovil",
|
|
"boschi1997@gmail.com": "nicoloboschi",
|
|
"chef.ya@gmail.com": "cherifya",
|
|
"chlqhdtn98@gmail.com": "BongSuCHOI",
|
|
"coffeemjj@gmail.com": "Cafexss",
|
|
"dalianmao0107@gmail.com": "dalianmao000",
|
|
"der@konsi.org": "konsisumer",
|
|
"dgrieco@redhat.com": "DomGrieco",
|
|
"dhicham.pro@gmail.com": "spideystreet",
|
|
"dipp.who@gmail.com": "dippwho",
|
|
"don.rhm@gmail.com": "donrhmexe",
|
|
"dorukardahan@hotmail.com": "dorukardahan",
|
|
"dsocolobsky@gmail.com": "dsocolobsky",
|
|
"dylan.socolobsky@lambdaclass.com": "dsocolobsky",
|
|
"ignacio.avecilla@lambdaclass.com": "IAvecilla",
|
|
"duerzy@gmail.com": "duerzy",
|
|
"emozilla@nousresearch.com": "emozilla",
|
|
"fancydirty@gmail.com": "fancydirty",
|
|
"farion1231@gmail.com": "farion1231",
|
|
"floptopbot33@gmail.com": "flobo3",
|
|
"fontana.pedro93@gmail.com": "pefontana",
|
|
"francis.x.fitzpatrick@gmail.com": "fxfitz",
|
|
"frank@helmschrott.de": "Helmi",
|
|
"gaixg94@gmail.com": "gaixianggeng",
|
|
"geoff.wellman@gmail.com": "geoffwellman",
|
|
"han.shan@live.cn": "jamesarch",
|
|
"haolong@microsoft.com": "LongOddCode",
|
|
"glennc@microsoft.com": "glennc",
|
|
"hata1234@gmail.com": "hata1234",
|
|
"hmbown@gmail.com": "Hmbown",
|
|
"iacobs@m0n5t3r.info": "m0n5t3r",
|
|
"jiayuw794@gmail.com": "JiayuuWang",
|
|
"jonny@nousresearch.com": "yoniebans",
|
|
"jake@nousresearch.com": "simpolism",
|
|
"juan.ovalle@mistral.ai": "jjovalle99",
|
|
"julien.talbot@ergonomia.re": "Julientalbot",
|
|
"kagura.chen28@gmail.com": "kagura-agent",
|
|
"1342088860@qq.com": "youngDoo",
|
|
"kamil@gwozdz.me": "kamil-gwozdz",
|
|
"skmishra1991@gmail.com": "bugkill3r",
|
|
"karamusti912@gmail.com": "MustafaKara7",
|
|
"kira@ariaki.me": "kira-ariaki",
|
|
"kira.ops@proton.me": "KiraKatana",
|
|
"knopki@duck.com": "knopki",
|
|
"limars874@gmail.com": "limars874",
|
|
"lisicheng168@gmail.com": "lesterli",
|
|
"mingjwan@microsoft.com": "MagicRay1217",
|
|
"orangeko@gmail.com": "GenKoKo",
|
|
"82095453+iacker@users.noreply.github.com": "iacker",
|
|
"sontianye@users.noreply.github.com": "sontianye",
|
|
"jackjin1997@users.noreply.github.com": "jackjin1997",
|
|
"1037461232@qq.com": "jackjin1997",
|
|
"danieldoderlein@users.noreply.github.com": "danieldoderlein",
|
|
"lrawnsley@users.noreply.github.com": "lrawnsley",
|
|
"taeuk178@users.noreply.github.com": "taeuk178",
|
|
"ogzerber@users.noreply.github.com": "ogzerber",
|
|
"cola-runner@users.noreply.github.com": "cola-runner",
|
|
"ygd58@users.noreply.github.com": "ygd58",
|
|
"45554392+warabe1122@users.noreply.github.com": "warabe1122",
|
|
"187001140+willy-scr@users.noreply.github.com": "willy-scr",
|
|
"vominh1919@users.noreply.github.com": "vominh1919",
|
|
"iamagenius00@users.noreply.github.com": "iamagenius00",
|
|
"9219265+cresslank@users.noreply.github.com": "cresslank",
|
|
"trevmanthony@gmail.com": "trevthefoolish",
|
|
"ziliangpeng@users.noreply.github.com": "ziliangpeng",
|
|
"ziliangdotme@gmail.com": "ziliangpeng",
|
|
"centripetal-star@users.noreply.github.com": "centripetal-star",
|
|
"LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
|
"Lubrsy706@users.noreply.github.com": "Lubrsy706",
|
|
"niyant@spicefi.xyz": "spniyant",
|
|
"olafthiele@gmail.com": "olafthiele",
|
|
"oncuevtv@gmail.com": "sprmn24",
|
|
"programming@olafthiele.com": "olafthiele",
|
|
"r2668940489@gmail.com": "r266-tech",
|
|
"s5460703@gmail.com": "BlackishGreen33",
|
|
"saul.jj.wu@gmail.com": "SaulJWu",
|
|
"shenhaocheng19990111@gmail.com": "hcshen0111",
|
|
"sjtuwbh@gmail.com": "Cygra",
|
|
"srhtsrht17@gmail.com": "Sertug17",
|
|
"stephenschoettler@gmail.com": "stephenschoettler",
|
|
"tanishq231003@gmail.com": "yyovil",
|
|
"taosiyuan163@153.com": "taosiyuan163",
|
|
"tesseracttars@gmail.com": "tesseracttars-creator",
|
|
"tianliangjay@gmail.com": "xingkongliang",
|
|
"1317078257maroon@gmail.com": "Oxidane-bot",
|
|
"tranquil_flow@protonmail.com": "Tranquil-Flow",
|
|
"LyleLengyel@gmail.com": "mcndjxlefnd",
|
|
"unayung@gmail.com": "Unayung",
|
|
"vorvul.danylo@gmail.com": "WorldInnovationsDepartment",
|
|
"win4r@outlook.com": "win4r",
|
|
"xush@xush.org": "KUSH42",
|
|
"yangzhi.see@gmail.com": "SeeYangZhi",
|
|
"yongtenglei@gmail.com": "yongtenglei",
|
|
"young@YoungdeMacBook-Pro.local": "YoungYang963",
|
|
"ysfalweshcan@gmail.com": "Junass1",
|
|
"ysfwaxlycan@gmail.com": "WAXLYY",
|
|
"yusufalweshdemir@gmail.com": "Dusk1e",
|
|
"zhouboli@gmail.com": "zhouboli",
|
|
"zqiao@microsoft.com": "tomqiaozc",
|
|
"zzn+pa@zzn.im": "xinbenlv",
|
|
"zaynjarvis@gmail.com": "ZaynJarvis",
|
|
"zhiheng.liu@bytedance.com": "ZaynJarvis",
|
|
"izhaolongfei@gmail.com": "loongfay",
|
|
"296659110@qq.com": "lrt4836",
|
|
"fe.daniel91@gmail.com": "beforeload",
|
|
"libo1106@foxmail.com": "libo1106",
|
|
"295367131@qq.com": "295367131",
|
|
"295367132@qq.com": "IxAres",
|
|
"danieldliu@tencent.com": "danieldliu",
|
|
"loongzhao@tencent.com": "loongzhao",
|
|
"Bartok9@users.noreply.github.com": "Bartok9",
|
|
"LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
"kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
|
"mbelleau@Michels-MacBook-Pro.local": "malaiwah",
|
|
"michel.belleau@malaiwah.com": "malaiwah",
|
|
"gnanasekaran.sekareee@gmail.com": "gnanam1990",
|
|
"jz.pentest@gmail.com": "0xyg3n",
|
|
"7093928+0xyg3n@users.noreply.github.com": "0xyg3n",
|
|
"nftpoetrist@gmail.com": "nftpoetrist", # PR #18982
|
|
"millerc79@users.noreply.github.com": "millerc79", # PR #19033
|
|
"hermes@example.com": "shellybotmoyer", # PR #18915 (bot-committed)
|
|
"exx@example.com": "exxmen", # PR #19555
|
|
"hypnosis.mda@gmail.com": "Hypn0sis",
|
|
"ywt000818@gmail.com": "OwenYWT",
|
|
"dhandhalyabhavik@gmail.com": "v1k22",
|
|
"rucchizhao@zhaochenfeideMacBook-Pro.local": "RucchiZ",
|
|
"tannerfokkens@Mac.attlocal.net": "tannerfokkens-maker",
|
|
"lehaolin98@outlook.com": "LehaoLin",
|
|
"yuewang1@microsoft.com": "imink",
|
|
"1736355688@qq.com": "hedgeho9X",
|
|
"bernylinville@devopsthink.org": "bernylinville",
|
|
"brian@bde.io": "briandevans",
|
|
"hubin_ll@qq.com": "LLQWQ",
|
|
"memosr_email@gmail.com": "memosr",
|
|
"jperlow@gmail.com": "perlowja",
|
|
"jasonpette1783@gmail.com": "web-dev0521",
|
|
"bjianhang@gmail.com": "bjianhang",
|
|
"tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc",
|
|
"harryplusplus@gmail.com": "harryplusplus",
|
|
"anthhub@163.com": "anthhub",
|
|
"vmphuongit@gmail.com": "phuongvm",
|
|
"allard.quek@singtel.com": "AllardQuek",
|
|
"shenuu@gmail.com": "shenuu",
|
|
"xiayh17@gmail.com": "xiayh0107",
|
|
"zhujianxyz@gmail.com": "opriz",
|
|
"tuancanhnguyen706@gmail.com": "xxxigm",
|
|
"54813621+xxxigm@users.noreply.github.com": "xxxigm",
|
|
"asurla@nvidia.com": "anniesurla",
|
|
"kchantharuan@nvidia.com": "nv-kasikritc",
|
|
"limkuan24@gmail.com": "WideLee",
|
|
"aviralarora002@gmail.com": "AviArora02-commits",
|
|
"draixagent@gmail.com": "draix",
|
|
"junminliu@gmail.com": "JimLiu",
|
|
"jarvischer@gmail.com": "maxchernin",
|
|
"levantam.98.2324@gmail.com": "LVT382009",
|
|
"zhurongcheng@rcrai.com": "heykb",
|
|
"withapurpose37@gmail.com": "StefanIsMe",
|
|
"261797239+lumenradley@users.noreply.github.com": "lumenradley",
|
|
"166376523+sjz-ks@users.noreply.github.com": "sjz-ks",
|
|
"haileymarshall005@gmail.com": "haileymarshall",
|
|
"aniruddhaadak80@users.noreply.github.com": "aniruddhaadak80",
|
|
"zheng.jerilyn@gmail.com": "jerilynzheng",
|
|
"asslaenn5@gmail.com": "Aslaaen",
|
|
"shalompmc0505@naver.com": "pinion05",
|
|
"105142614+VTRiot@users.noreply.github.com": "VTRiot",
|
|
"vivien000812@gmail.com": "iamagenius00",
|
|
"89228157+Feranmi10@users.noreply.github.com": "Feranmi10",
|
|
"oluwadareferanmi11@gmail.com": "Feranmi10",
|
|
"simon@gtcl.us": "simon-gtcl",
|
|
"suzukaze.haduki@gmail.com": "houko",
|
|
"cliff@cigii.com": "cgarwood82",
|
|
"anna@oa.ke": "anna-oake",
|
|
"jaffarkeikei@gmail.com": "jaffarkeikei",
|
|
"hxp@hxp.plus": "hxp-plus",
|
|
"3580442280@qq.com": "Tianworld",
|
|
"wujianxu91@gmail.com": "wujhsu",
|
|
"zhrh120@gmail.com": "niyoh120",
|
|
"vrinek@hey.com": "vrinek",
|
|
"268198004+xandersbell@users.noreply.github.com": "xandersbell",
|
|
"somme4096@gmail.com": "Somme4096",
|
|
"brian@tiuxo.com": "brianclemens",
|
|
"25944632+yudaiyan@users.noreply.github.com": "yudaiyan",
|
|
"chayton@sina.com": "ycbai",
|
|
"longsizhuo@gmail.com": "longsizhuo",
|
|
"chenb19870707@gmail.com": "ms-alan",
|
|
"agorgianitisj@hotmail.com": "johnisag",
|
|
"phil.thomas@gametime.co": "explainanalyze",
|
|
"276886827+WuTianyi123@users.noreply.github.com": "WuTianyi123",
|
|
"22549957+li0near@users.noreply.github.com": "li0near",
|
|
"guoyu801@gmail.com": "li0near",
|
|
"ty@tmrtn.com": "tymrtn",
|
|
"elitovsky@zenproject.net": "kallidean",
|
|
"5463986+baocin@users.noreply.github.com": "baocin",
|
|
"107296821+princepal9120@users.noreply.github.com": "princepal9120",
|
|
"gufo0125@gmail.com": "guglielmofonda",
|
|
"102474490+yehuosi@users.noreply.github.com": "yehuosi",
|
|
"yehuosi@users.noreply.github.com": "yehuosi",
|
|
"31932854+jelrod27@users.noreply.github.com": "jelrod27",
|
|
"11262660+konsisumer@users.noreply.github.com": "konsisumer",
|
|
"23434080+sicnuyudidi@users.noreply.github.com": "sicnuyudidi",
|
|
"haimu0x0@proton.me": "haimu0x",
|
|
"abdelmajidnidnasser1@gmail.com": "NIDNASSER-Abdelmajid",
|
|
"projectadmin@wit.id": "projectadmin-dev",
|
|
"mrigankamondal10@gmail.com": "Dev-Mriganka",
|
|
"132275809+shushuzn@users.noreply.github.com": "shushuzn",
|
|
"ibrahimozsarac@gmail.com": "iborazzi",
|
|
"130149563+A-afflatus@users.noreply.github.com": "A-afflatus",
|
|
"huangkwell@163.com": "huangke19",
|
|
"tanishq@exa.ai": "10ishq",
|
|
"363708+christopherwoodall@users.noreply.github.com": "christopherwoodall",
|
|
"zhang9w0v5@qq.com": "zhang9w0v5",
|
|
"fuleinist@outlook.com": "fuleinist",
|
|
"43494187+Llugaes@users.noreply.github.com": "Llugaes",
|
|
"fengtianyu88@users.noreply.github.com": "fengtianyu88",
|
|
"l.moncany@gmail.com": "lmoncany",
|
|
"fatinghenji@users.noreply.github.com": "fatinghenji",
|
|
"xin.peng.dr@gmail.com": "xinpengdr",
|
|
"mike@mikewaters.net": "mikewaters",
|
|
"65117428+WadydX@users.noreply.github.com": "WadydX",
|
|
"216480837+isaachuangGMICLOUD@users.noreply.github.com": "isaachuangGMICLOUD",
|
|
"isaac.h@gmicloud.ai": "isaachuangGMICLOUD",
|
|
"nukuom976228@gmail.com": "hsy5571616",
|
|
"11462216+Nan93@users.noreply.github.com": "Nan93",
|
|
"l973401489@126.com": "zhouxiaoya12",
|
|
"373119611@qq.com": "roytian1217",
|
|
"brett@brettbrewer.com": "minorgod",
|
|
"67779267+wenhao7@users.noreply.github.com": "wenhao7",
|
|
"git@yzx9.xyz": "yzx9",
|
|
"nilesh@cloudgeni.us": "lvnilesh",
|
|
"63502660+azhengbot@users.noreply.github.com": "azhengbot",
|
|
"sharvil.saxena@gmail.com": "sharziki",
|
|
"yuanhe@minimaxi.com": "RyanLee-Dev",
|
|
"curtis992250@gmail.com": "TaroballzChen",
|
|
"92638503+Lind3ey@users.noreply.github.com": "Lind3ey",
|
|
"1352808998@qq.com": "phpoh",
|
|
"caliberoviv@gmail.com": "vivganes",
|
|
"michaelfackerell@gmail.com": "MikeFac",
|
|
"18024642@qq.com": "GuyCui",
|
|
"eumael.mkt@gmail.com": "maelrx",
|
|
# v0.11.0 additions
|
|
"benbarclay@gmail.com": "benbarclay",
|
|
"lijiawen@umich.edu": "Jiawen-lee",
|
|
"oleksiy@kovyrin.net": "kovyrin",
|
|
"kovyrin.claw@gmail.com": "kovyrin",
|
|
"kaiobarb@gmail.com": "liftaris",
|
|
"me@arihantsethia.com": "arihantsethia",
|
|
"zhuofengwang2003@gmail.com": "coekfung",
|
|
"teknium@noreply.github.com": "teknium1",
|
|
"2114364329@qq.com": "cuyua9",
|
|
"2557058999@qq.com": "Disaster-Terminator",
|
|
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
|
"zyprothh@gmail.com": "Zyproth",
|
|
"amitgaur@gmail.com": "amitgaur",
|
|
"albuquerque.abner@gmail.com": "mrbob-git",
|
|
"kiala@users.noreply.github.com": "kiala9",
|
|
"alanxchen@gmail.com": "alanxchen85",
|
|
"clawbot@clawbots-Mac-mini.local": "John-tip",
|
|
"der@konsi.org": "konsisumer",
|
|
"cirwel@The-CIRWEL-Group.local": "CIRWEL",
|
|
"molvikar8@gmail.com": "molvikar",
|
|
"nftpoetrist@gmail.com": "nftpoetrist",
|
|
"dodofun@126.com": "colorcross",
|
|
"1615063567@qq.com": "zhao0112",
|
|
"ethanguo.2003@gmail.com": "EthanGuo-coder",
|
|
"dev0jsh@gmail.com": "tmdgusya",
|
|
"leavr@163.com": "leavrcn",
|
|
"17683456+wanazhar@users.noreply.github.com": "wanazhar",
|
|
"26782336+cixuuz@users.noreply.github.com": "cixuuz",
|
|
"aleksandr.pasevin@openzeppelin.com": "pasevin",
|
|
"ubuntu@localhost.localdomain": "holynn-q",
|
|
"holynn@placeholder.local": "holynn-q",
|
|
"agent@hermes.local": "jacdevos",
|
|
"sunsky.lau@gmail.com": "liuhao1024",
|
|
"fabianoeq@gmail.com": "rodrigoeqnit",
|
|
"178342791+sgtworkman@users.noreply.github.com": "sgtworkman",
|
|
"qiuqfang98@qq.com": "keepcalmqqf",
|
|
"261867348+ai-ag2026@users.noreply.github.com": "ai-ag2026",
|
|
"yanzh.su@gmail.com": "YanzhongSu",
|
|
"wanderwang@users.noreply.github.com": "WanderWang",
|
|
"yueheime@gmail.com": "yuehei",
|
|
"emidomh@gmail.com": "Emidomenge",
|
|
"2642448440@qq.com": "BlackJulySnow",
|
|
"4317663+helix4u@users.noreply.github.com": "helix4u",
|
|
"floptopbot33@gmail.com": "flobo3",
|
|
"dpaluy@users.noreply.github.com": "dpaluy",
|
|
"psikonetik@gmail.com": "el-analista",
|
|
"chenb19870707@gmail.com": "ms-alan",
|
|
"agorgianitisj@hotmail.com": "johnisag",
|
|
"phil.thomas@gametime.co": "explainanalyze",
|
|
"hex-clawd@users.noreply.github.com": "hex-clawd",
|
|
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
|
"barteq@hacknotes.local": "barteqpl",
|
|
"pama0227@gmail.com": "pama0227",
|
|
"52785845+ee-blog@users.noreply.github.com": "ee-blog",
|
|
"simplenamebox@gmail.com": "simplenamebox-ops",
|
|
"balyan.sid@gmail.com": "alt-glitch",
|
|
"xdord@xdorddeMac-mini.local": "foreverxdord",
|
|
"k2767567815@gmail.com": "QifengKuang",
|
|
"88077783+jjjojoj@users.noreply.github.com": "jjjojoj",
|
|
"valda@underscore.jp": "valda",
|
|
"lling486@163.com": "M3RCUR2Y",
|
|
"buraysandro9@gmail.com": "ygd58",
|
|
"ideathinklab01-source@users.noreply.github.com": "ideathinklab01-source",
|
|
"27987889@qq.com": "zng8418",
|
|
"daniuxie88@proton.me": "DaniuXie",
|
|
"panchanler@gmail.com": "ChanlerDev",
|
|
"252620095+briandevans@users.noreply.github.com": "briandevans",
|
|
"141889580+h0tp-ftw@users.noreply.github.com": "h0tp-ftw",
|
|
"chinadbo@foxmail.com": "chinadbo",
|
|
"82637225+kshitijk4poor@users.noreply.github.com": "kshitijk4poor",
|
|
"xyywtt@gmail.com": "xyiy001",
|
|
"charliekerfoot@gmail.com": "CharlieKerfoot",
|
|
"grey0202@users.noreply.github.com": "Grey0202",
|
|
"vominh1919@gmail.com": "vominh1919",
|
|
"giwavictor9@gmail.com": "giwaov",
|
|
"yoimexex@gmail.com": "Yoimex",
|
|
"76803960+atongrun@users.noreply.github.com": "atongrun",
|
|
"michaeldanko@icloud.com": "MichaelWDanko",
|
|
"xudavid429@gmail.com": "YX234",
|
|
"kathy@Kathy.local": "julysir",
|
|
"274902531@qq.com": "JanCong",
|
|
"225304168+e-shizz@users.noreply.github.com": "e-shizz",
|
|
"vincent_hh@users.noreply.github.com": "VinVC",
|
|
"1243352777@qq.com": "zons-zhaozhy",
|
|
"dejie.guo@gmail.com": "JayGwod",
|
|
"52840391+swithek@users.noreply.github.com": "swithek",
|
|
"raipratik0101@gmail.com": "PratikRai0101",
|
|
"code@sasha.id": "sasha-id",
|
|
"chen.yunbo@xydigit.com": "chenyunbo411",
|
|
"openclaw@local": "Asce66",
|
|
"59465365+0xsir0000@users.noreply.github.com": "0xsir0000",
|
|
"lisanhu2014@hotmail.com": "lisanhu",
|
|
"0668001438@zte.com.cn": "chenyunbo411",
|
|
"steven_chanin@alum.mit.edu": "stevenchanin",
|
|
"fiver@example.com": "halmisen",
|
|
"mayq0422@gmail.com": "yuqianma",
|
|
"yuqian@zmetasoft.com": "yuqianma",
|
|
"scott@bubble.local": "bassings",
|
|
"highland0971@users.noreply.github.com": "highland0971",
|
|
"sudolewis@gmail.com": "lewislulu",
|
|
"gaurav2301v@gmail.com": "Gaurav23V",
|
|
"tranquil_flow@protonmail.com": "Tranquil-Flow",
|
|
"albert748@gmail.com": "albert748",
|
|
"ntconguit@gmail.com": "0xharryriddle",
|
|
"lhysdl@gmail.com": "lhysdl",
|
|
"shemol@163.com": "SherlockShemol",
|
|
"enochlam2002@gmail.com": "eloklam",
|
|
"eloklam@eloklam-ubuntudesktop.tail21966c.ts.net": "eloklam",
|
|
"clawdia@fmercurio-macstudio.local": "fmercurio",
|
|
"ricardoporsche001@icloud.com": "Ricardo-M-L",
|
|
"leozeli@qq.com": "leozeli",
|
|
"linlehao@cuhk.edu.cn": "LehaoLin",
|
|
"liutong@isacas.ac.cn": "I3eg1nner",
|
|
"peterberthelsen@Peters-MacBook-Air.local": "PeterBerthelsen",
|
|
"root@debian.debian": "lengxii",
|
|
"roque@priveperfumeshn.com": "priveperfumes",
|
|
"shijianzhi@shijianzhideMacBook-Pro.local": "sjz-ks",
|
|
"topcheer@me.com": "topcheer",
|
|
"walli@tencent.com": "walli",
|
|
"zhuofengwang@tencent.com": "Zhuofeng-Wang",
|
|
"simonweng@tencent.com": "Contentment003111",
|
|
# April 2026 salvage-PR batch (#14920, #14986, #14966)
|
|
"mrunmayeerane17@gmail.com": "mrunmayee17",
|
|
"69489633+camaragon@users.noreply.github.com": "camaragon",
|
|
"shamork@outlook.com": "shamork",
|
|
# April 2026 Discord Copilot /model salvage (#15030)
|
|
"cshong2017@outlook.com": "Nicecsh",
|
|
# no-github-match — keep as display names
|
|
"clio-agent@sisyphuslabs.ai": "Sisyphus",
|
|
"marco@rutimka.de": "Marco Rutsch",
|
|
"paul@gamma.app": "Paul Bergeron",
|
|
"zhangxicen@example.com": "zhangxicen",
|
|
"codex@openai.invalid": "teknium1",
|
|
"screenmachine@gmail.com": "teknium1",
|
|
"chenzeshi@live.com": "chen1749144759",
|
|
"mor.aleksandr@yahoo.com": "MorAlekss",
|
|
"276649498+ztexydt-cqh@users.noreply.github.com": "ztexydt-cqh",
|
|
"ash@users.noreply.github.com": "ash",
|
|
"andrewho.sf@gmail.com": "andrewhosf",
|
|
# April 2026 Honcho bug-fix consolidation (#15381)
|
|
"HiddenPuppy@users.noreply.github.com": "HiddenPuppy",
|
|
"code@sasha.id": "sasha-id",
|
|
"dontcallmejames@users.noreply.github.com": "dontcallmejames",
|
|
"hekaru.agent@gmail.com": "hekaru-agent",
|
|
"jas9000@gmail.com": "twozle",
|
|
"r.filgueiras@apheris.com": "rfilgueiras",
|
|
"leihaibo1992@gmail.com": "Leihb",
|
|
# ACP streaming fix salvage (PR #9428 + #16273)
|
|
"nfb0408@163.com": "ningfangbin",
|
|
"164839249+Joseph19820124@users.noreply.github.com": "Joseph19820124",
|
|
"rugved@lmstudio.ai": "rugvedS07",
|
|
"44333070+Heltman@users.noreply.github.com": "Heltman",
|
|
# v0.12.0 additions
|
|
"ching@kachingappz.com": "ching-kaching",
|
|
"codezhujr@gmail.com": "Zjianru", # salvage chain: code by codez, PR #15749 author @Zjianru
|
|
"daimon@noreply.github.com": "Siddharth Balyan", # co-author only
|
|
"i@zkl2333.com": "zkl2333",
|
|
"isaachuang@Isaacs-MacBook-Pro.local": "isaachuangGMICLOUD",
|
|
"isaachuang@Mac.localdomain": "isaachuangGMICLOUD", # salvage of PR #11955 → #16663
|
|
"liyuan851277048@icloud.com": "Octopus", # co-author only
|
|
"me+github7604@versun.org": "Versun", # co-author only
|
|
"my.vesper.nine@gmail.com": "kevin-ho", # salvage: PR #15488 author @kevin-ho
|
|
"noreply@paperclip.ing": "Paperclip", # co-author only
|
|
"teknium@hermes-agent": "teknium1",
|
|
"web3blind@gmail.com": "web3blind",
|
|
"ztzheng@163.com": "chengoak", # PR #17467
|
|
"24110240104@m.fudan.edu.cn": "YuShu", # co-author only
|
|
"charliekerfoot@gmail.com": "CharlieKerfoot", # PR #18951
|
|
# Debug share upload-time redaction (May 2026)
|
|
"dhuysamen@gmail.com": "GodsBoy", # PR #19318
|
|
"mrcoferland@gmail.com": "mrcoferland", # PR #19023
|
|
"chenlinfeng@ruije.com.cn": "noOne-list", # PR #19050
|
|
"briansu@Mac-mini.attlocal.net": "likejudy", # PR #19052
|
|
"leosma@gmail.com": "leon7609", # PR #19069
|
|
"nouseman666@gmail.com": "nouseman666", # PR #19088
|
|
"ginwu05@gmail.com": "GinWU05", # PR #19093
|
|
"shashwatgokhe2@gmail.com": "shashwatgokhe", # PR #19196
|
|
"stevenchou.ai@gmail.com": "stevenchouai", # PR #19221
|
|
"leo.gong@phizchat.com": "agilejava", # PR #19346
|
|
"acc001k@pm.me": "acc001k", # PR #19358
|
|
"kowenhao@users.noreply.github.com": "kowenhaoai", # PR #19376
|
|
"hedirman@gmail.com": "hedirman", # PR #19410
|
|
"lucianopacheco@gmail.com": "LucianoSP", # PR #19412
|
|
"paultian.research@gmail.com": "paul-tian", # PR #19423
|
|
"info@glesperance.com": "glesperance", # PR #19443
|
|
"lxl694522264@gmail.com": "EvilDrag0n", # PR #20651
|
|
# v0.13.0 additions
|
|
"clode@clo5de.info": "jackey8616", # via PR salvage
|
|
"james.russo@heygen.com": "jrusso1020", # via PR salvage
|
|
"leon@sgp43.com": "LeonSGP43", # PR #18739 salvage of #14570
|
|
"miniding@miniding.home": "Foolafroos", # PR #20329 French locale
|
|
"montbra@gmail.com": "Montbra", # PR #20897 salvage of #16189 (TUI voice PTT)
|
|
"promptsiren@gmail.com": "firefly", # PR #18123 salvage of #16660 (ContextVars)
|
|
"wtyopenclaw@gmail.com": "WuTianyi123", # PR #20275 salvage of #13723 (feishu markdown)
|
|
"zhicheng.han@mathematik.uni-goettingen.de": "hanzckernel", # PR #20311 (api-server approval events)
|
|
"agentsmithlaor@gmail.com": "oferlaor", # PR #22356 salvage (cron origin sender identity)
|
|
"jhin.lee@unity3d.com": "leehack", # PR #22053 salvage (telegram DM topic reply fallback)
|
|
# pander: empty email, salvaged via PR #19665 from #16126 by @ms-alan
|
|
"ayman.a.kamal@hotmail.com": "A-kamal", # PR #18678 (xAI image resolution fix)
|
|
# Kanban bug-fix batch salvage (May 2026)
|
|
"frowte3k@gmail.com": "Frowtek", # salvage of #23206 (gateway --board auto-subscribe)
|
|
"sylw3st3rr@gmail.com": "Sylw3ster", # salvage of #23252 (HERMES_KANBAN_BOARD restore)
|
|
"hello@dominikh.com": "dmnkhorvath", # salvage of #23358 (kanban worker send_message)
|
|
"413011+smwbev@users.noreply.github.com": "smwbev", # salvage of #23659 (aria-label colLabel)
|
|
"58116817+TurgutKural@users.noreply.github.com": "TurgutKural", # salvage of #23356 (HERMES_HOME inject)
|
|
"openclaw@agent.local": "29206394", # PR #22194 salvage (sudo -S brute-force guard, #9590)
|
|
"freedemon@gmail.com": "fr33d3m0n", # PR #21128 salvage (sudo stdin/askpass DANGEROUS, #17873 cat 4)
|
|
"zhaowh3613@outlook.com": "VinceZcrikl", # PR #23647 salvage (npm UTF-8 decode on GBK Windows)
|
|
"abcdjmm970703@gmail.com": "JabberELF", # PR #20238 seed (session_search dual-mode, evolved into single-shape)
|
|
"anton.kuenzi@gmail.com": "ZeterMordio", # PR #11754 salvage (zsh completion compdef + _arguments syntax)
|
|
"23yntong@stu.edu.cn": "iuyup", # PR #6155 salvage (shell=True hardening)
|
|
"86501179+1RB@users.noreply.github.com": "1RB", # PR #25462 salvage (discord forwarded messages)
|
|
"44045943+ayushere@users.noreply.github.com": "ayushere", # PR #25342 salvage (memory teardown leak)
|
|
"15791290+domtriola@users.noreply.github.com": "domtriola", # PR #25424 salvage (docs tirith link)
|
|
"284216128+ephron-ren@users.noreply.github.com": "ephron-ren", # PR #25358 salvage (MiMo reasoning echo-back)
|
|
"96843562+freqyfreqy@users.noreply.github.com": "freqyfreqy", # PR #25423 salvage (docs LSP worktree -> repo)
|
|
"54306477+fu576@users.noreply.github.com": "fu576", # PR #25369 salvage (api_mode not inherited cross-provider)
|
|
"258095375+kfa-ai@users.noreply.github.com": "kfa-ai", # PR #25398 salvage (whatsapp quoted reply metadata)
|
|
"99181308+magic524@users.noreply.github.com": "magic524", # PR #25361 salvage (QQBot reconnect loop)
|
|
"9150277+PaTTeeL@users.noreply.github.com": "PaTTeeL", # PR #25359 salvage (custom_providers in compression length)
|
|
"1700913+pearjelly@users.noreply.github.com": "pearjelly", # PR #25388 salvage (feishu ws connect override sync)
|
|
"100820567+raymaylee@users.noreply.github.com": "raymaylee", # PR #25394 salvage (context compaction status)
|
|
"122434621+Tianyu199509@users.noreply.github.com": "Tianyu199509", # PR #25421 salvage (gateway PID Windows)
|
|
"58224596+HxT9@users.noreply.github.com": "HxT9", # PR #25760 salvage (web sync-assets cross-platform)
|
|
"120411712+evgyur@users.noreply.github.com": "evgyur", # PR #25651 salvage (docs media session context)
|
|
"36507055+AsoTora@users.noreply.github.com": "AsoTora", # PR #25624 salvage (MCP auth no-retry)
|
|
"98992931+oxngon@users.noreply.github.com": "oxngon", # PR #25603 salvage (forward image attachments to bg tasks)
|
|
"37467487+yifengingit@users.noreply.github.com": "yifengingit", # PR #25589 salvage (AUTOINCREMENT id ordering)
|
|
"89525629+vanthinh6886@users.noreply.github.com": "vanthinh6886", # PR #25562 salvage (.env 0600 perms)
|
|
"16034932+Arkmusn@users.noreply.github.com": "Arkmusn", # PR #25559 salvage (approvals.timeout from config)
|
|
"nidhi2894@gmail.com": "nidhi-singh02", # PR #2752 salvage (slack whitespace-only IndexError guard)
|
|
"38173192+nidhi-singh02@users.noreply.github.com": "nidhi-singh02",
|
|
"Jaaneek@users.noreply.github.com": "Jaaneek", # PR #26457 (xAI Grok OAuth provider)
|
|
# v0.14.0 additions
|
|
"chuang.guo@hopechart.com": "wuwuzhijing", # PR #21063 salvage (gateway docs mention Weixin)
|
|
"nightcityblade@gmail.com": "nightcityblade", # PR #24138 (docs voice/tts table)
|
|
"pol.kuijken@gmail.com": "polkn", # PR #6136 salvage (skill_view collision refusal)
|
|
"robin@soal.org": "rewbs",
|
|
# batch salvage (May 2026 LHF run)
|
|
"sauravsejal40@gmail.com": "Saurav0989", # PR #27071 (docs: hermes-eval community link)
|
|
"220110965+Saurav0989@users.noreply.github.com": "Saurav0989",
|
|
"aviarchi1994@gmail.com": "avifenesh", # PR #25902 (docs: computer-use-linux MCP)
|
|
"55848801+avifenesh@users.noreply.github.com": "avifenesh",
|
|
"279959838+BROCCOLO1D@users.noreply.github.com": "BROCCOLO1D", # PR #26796 (docs: spotify + HA)
|
|
"m@matthewlai.ca": "matthewlai", # PR #25293 (feat: gemma 4 reasoning allowlist)
|
|
"4296245+matthewlai@users.noreply.github.com": "matthewlai",
|
|
"109617724+0xchainer@users.noreply.github.com": "0xchainer", # PR #27154/27138/27147 salvage
|
|
"201800237+kronexoi@users.noreply.github.com": "kronexoi", # PR #27167 salvage (Teams port fallback)
|
|
"283442588+EloquentBrush0x@users.noreply.github.com": "EloquentBrush0x", # PR #26642 salvage (post_setup parity)
|
|
# batch salvage (May 2026 LHF run, group 2)
|
|
"shellybotmoyer@example.com": "shellybotmoyer", # PR #26661 (kanban --severity >=)
|
|
"coulson@shellybotmoyer.com": "shellybotmoyer", # PR #25576 (credential_pool ISO rehydrate)
|
|
"258858106+shellybotmoyer@users.noreply.github.com": "shellybotmoyer",
|
|
"33156212+ether-btc@users.noreply.github.com": "ether-btc", # PR #26632 (memory provider whitespace guard)
|
|
"Bloomtonjovish@gmail.com": "LifeJiggy", # PR #26516 (paste collapse logging)
|
|
"141562589+LifeJiggy@users.noreply.github.com": "LifeJiggy",
|
|
"192385615+LifeJiggy@users.noreply.github.com": "LifeJiggy", # stale salvage commit alias (PR #28315)
|
|
"beastant1@gmail.com": "nekwo", # PR #26481 (PS5.1 UTF-8 BOM)
|
|
"43717185+nekwo@users.noreply.github.com": "nekwo",
|
|
"9785479+stepanov1975@users.noreply.github.com": "stepanov1975", # PR #22074 (setup config picker writes)
|
|
"67979730+flooryyyy@users.noreply.github.com": "flooryyyy", # PR #26374 (tool_trace error detection)
|
|
"188585318+dgians@users.noreply.github.com": "dgians", # PR #26034 (.ts/.py/.sh docs types)
|
|
"zealy@tz.co": "dgians", # PR #26034 (bot-committed by zealy-tzco under dgians' PR)
|
|
"mottei.survive@gmail.com": "flanny7", # PR #27030 (setup_open_webui python var)
|
|
"20530505+flanny7@users.noreply.github.com": "flanny7",
|
|
"hermesagent26@gmail.com": "hermesagent26", # PR #26438 (kimi model-name reasoning pad)
|
|
"276067471+hermesagent26@users.noreply.github.com": "hermesagent26",
|
|
"71590782+kriscolab@users.noreply.github.com": "kriscolab", # PR #26926 (deepseek default_aux_model)
|
|
# batch salvage (May 2026 LHF run, group 3)
|
|
"darvsum@users.noreply.github.com": "darvsum", # PR #26766 (preserve discover_models in normalize)
|
|
"peter@Peters-Mac-mini.local": "hueilau", # PR #26498 (strip image parts for non-vision)
|
|
"33933019+hueilau@users.noreply.github.com": "hueilau",
|
|
"32297275+Timur00Kh@users.noreply.github.com": "Timur00Kh", # PR #27114 (telegram DM topic for synthetic events)
|
|
"al.bellemare@gmail.com": "Grogger", # PR #27061 (windows console flash suppress)
|
|
"7065068+Grogger@users.noreply.github.com": "Grogger",
|
|
"18091625+Grogger@users.noreply.github.com": "Grogger", # stale salvage commit alias (PR #28330)
|
|
"clement@nousresearch.com": "lemassykoi", # PR #27042 (model-switch probe keyless providers)
|
|
"16377344+lemassykoi@users.noreply.github.com": "lemassykoi",
|
|
"draplater@icloud.com": "draplater", # PR #26707 (goal judge current time)
|
|
"6349758+draplater@users.noreply.github.com": "draplater",
|
|
"pr7426@users.noreply.github.com": "pr7426", # PR #27048 (cron parallel job loss)
|
|
"rahulnilvan43@gmail.com": "therahul-yo", # PR #26215 (mock keychain in tests)
|
|
"kingsleyemeka117@gmail.com": "flamiinngo", # PR #27205 (UnicodeEncodeError footgun checker)
|
|
# batch salvage (May 2026 LHF run, group 4)
|
|
"283442588+EloquentBrush0x@users.noreply.github.com": "EloquentBrush0x", # PR #26657 (trust_env aiohttp)
|
|
"205509009+subtract0@users.noreply.github.com": "subtract0", # PR #25658 (zsh $status -> $rc)
|
|
"patryk@jarmakowicz.me": "zwolniony", # PR #26961 (gemini x-goog-api-key)
|
|
"12735938+zwolniony@users.noreply.github.com": "zwolniony",
|
|
"ambuj@dodopayments.com": "that-ambuj", # PR #26582 (preserve underscores)
|
|
"zccyman@163.com": "zccyman", # PR #25294 (custom provider api_key_env alias)
|
|
# xAI cluster batch salvage (May 2026)
|
|
"lgndscntn@gmail.com": "Fewmanism", # PR #27420 (threaded xAI OAuth callback)
|
|
"slimydog@Faisals-Mac-mini.local": "Slimydog21", # PR #28021 (strip slash enums xAI Responses)
|
|
"194121339+Slimydog21@users.noreply.github.com": "Slimydog21", # PR #28021 salvage (noreply form)
|
|
"bitkyc08@gmail.com": "lidge-jun", # PR #26814 (api server browser security headers)
|
|
"sp_ps@Mac-mini.lan": "phoenixshen", # PR #26768 (respect user-configured vision model)
|
|
"1594534+phoenixshen@users.noreply.github.com": "phoenixshen",
|
|
"147827411+AhmetArif0@users.noreply.github.com": "AhmetArif0", # PR #26635 (line proxy env vars)
|
|
# batch salvage (May 2026 LHF run, group 5)
|
|
"hari@Hariharans-MacBook-Air-8.local": "haran2001", # PR #27070 (i18n catalog test)
|
|
"hariharan15151@gmail.com": "haran2001", # PR #27068 (qwen3.6-plus 1M context)
|
|
"56040092+haran2001@users.noreply.github.com": "haran2001",
|
|
"1472110+ms-alan@users.noreply.github.com": "ms-alan", # PR #26443 (reload-skills tab completion)
|
|
"ganlinbupt@gmail.com": "godlin-gh", # PR #26118 (ACP polished tools)
|
|
"wesley.simplicio.ext@siemens-energy.com": "wesleysimplicio", # PR #25777 (xterm.js native selection)
|
|
"6108320+wesleysimplicio@users.noreply.github.com": "wesleysimplicio",
|
|
"carryzuo00@gmail.com": "Carry00", # PR #26851 (doctor SSH env vars)
|
|
"alaamohanad169-ship-it@users.noreply.github.com": "alaamohanad169-ship-it", # PR #26036 (telegram typing after send)
|
|
"vigo@hermes": "hawknewton", # PR #26294 (bedrock boto3 lazy_deps)
|
|
"211668+hawknewton@users.noreply.github.com": "hawknewton",
|
|
"quenvix00@gmail.com": "QuenVix", # PR #26761/26772 salvage
|
|
"164776164+QuenVix@users.noreply.github.com": "QuenVix",
|
|
"262945885+Mind-Dragon@users.noreply.github.com": "Mind-Dragon", # PR #26966 salvage
|
|
"soynchuux@gmail.com": "soynchux", # PR #27060 salvage
|
|
"209694554+soynchux@users.noreply.github.com": "soynchux",
|
|
# batch salvage (May 2026 LHF run, group 6 — final)
|
|
"6666242+bird@users.noreply.github.com": "bird", # PR #25219 (gateway docker exit-75 restart)
|
|
"david@loadmagic.ai": "davidcampbelldc", # PR #26834 (web_server proxy_headers=False)
|
|
"165905879+davidcampbelldc@users.noreply.github.com": "davidcampbelldc",
|
|
"hoangv.pham0803@gmail.com": "hehehe0803", # PR #26212 salvage (codex kanban writable root)
|
|
"26063003+hehehe0803@users.noreply.github.com": "hehehe0803",
|
|
"38348871+vaddisrinivas@users.noreply.github.com": "vaddisrinivas", # PR #26394 salvage (Docker messaging extra)
|
|
# batch salvage (May 2026 LHF run, group 7)
|
|
"198679067+02356abc@users.noreply.github.com": "02356abc", # PR #28286 salvage (wecom CLOSING)
|
|
"1743117+burjorjee@users.noreply.github.com": "burjorjee", # PR #28201 salvage (inline-shell timeout guard)
|
|
"keki@MacBookPro.attlocal.net": "burjorjee",
|
|
"264690993+oseftg@users.noreply.github.com": "oseftg", # PR #28168 salvage (natural ending emoji/caret)
|
|
"hex.hermes@agentmail.to": "oseftg",
|
|
"236912655+rudi193-cmd@users.noreply.github.com": "rudi193-cmd", # PR #28241 salvage (empty credential pool)
|
|
"rudi193@gmail.com": "rudi193-cmd",
|
|
"86684667+sadiksaifi@users.noreply.github.com": "sadiksaifi", # PR #27982 salvage (kanban horiz scroll)
|
|
"mail@sadiksaifi.dev": "sadiksaifi",
|
|
# batch salvage (May 2026 LHF run, group 8)
|
|
"266824395+AceWattGit@users.noreply.github.com": "AceWattGit", # PR #28159 salvage (_pool_may_recover NameError)
|
|
"57024493+YuanHanzhong@users.noreply.github.com": "YuanHanzhong", # PR #28032 salvage (x.com status link-like)
|
|
"24368158+colin-chang@users.noreply.github.com": "colin-chang", # PR #28245/#28249/#28251 salvage
|
|
"zhangcheng5468@gmail.com": "colin-chang",
|
|
"172729123+felix-windsor@users.noreply.github.com": "felix-windsor", # PR #28019 salvage (cron asterisks)
|
|
"felixwindsor3344@gmail.com": "felix-windsor",
|
|
"259054917+houenyang-momo@users.noreply.github.com": "houenyang-momo", # PR #28205 salvage (charizard contrast)
|
|
"35931201+iqdoctor@users.noreply.github.com": "iqdoctor", # PR #28095 salvage (windows installer docs)
|
|
"29513231+joe102084@users.noreply.github.com": "joe102084", # PR #28151 salvage (whitespace cron responses)
|
|
"joe102084@gmail.com": "joe102084",
|
|
"4139778+jvinals@users.noreply.github.com": "jvinals", # PR #27936 salvage (Slack U-IDs)
|
|
"3001335+maxmilian@users.noreply.github.com": "maxmilian", # PR #28267 salvage (Change Model portal)
|
|
"maxmilian@gmail.com": "maxmilian",
|
|
"41468846+samggggflynn@users.noreply.github.com": "samggggflynn", # PR #27952 salvage (dingtalk pre_start)
|
|
"abc401011721@gmail.com": "samggggflynn",
|
|
"yannsunn@users.noreply.github.com": "yannsunn", # PR #28064 salvage (xai proxy upstream)
|
|
"yannsunn1116@gmail.com": "yannsunn",
|
|
"asdlem@users.noreply.github.com": "asdlem", # PR #27852 salvage (clarify full text in body)
|
|
# batch salvage (May 2026 LHF run, group 9)
|
|
"1779909+jdelmerico@users.noreply.github.com": "jdelmerico", # PR #28278 salvage (signal require_mention)
|
|
"20639347+justemu@users.noreply.github.com": "justemu", # PR #27996 salvage (matrix thread_require_mention)
|
|
"justemu@users.noreply.github.com": "justemu",
|
|
"57024493+YuanHanzhong@users.noreply.github.com": "YuanHanzhong", # PR #28029 salvage (dashboard scrollback)
|
|
"YuanHanzhong@users.noreply.github.com": "YuanHanzhong",
|
|
"1663402+noctilust@users.noreply.github.com": "noctilust", # PR #28080 salvage (stale TUI resume env)
|
|
"1663402+freeurmind@users.noreply.github.com": "noctilust",
|
|
"35164907+MoonJuhan@users.noreply.github.com": "MoonJuhan", # PR #28288 salvage (unreadable JSONL transcripts)
|
|
"codemike@naver.com": "MoonJuhan",
|
|
"201563152+outsourc-e@users.noreply.github.com": "outsourc-e", # PR #28164 salvage (cron emoji ZWJ)
|
|
"201803425+Zyrixtrex@users.noreply.github.com": "Zyrixtrex", # PR #28275 salvage (Google OAuth timeout)
|
|
"zyrixtrex@gmail.com": "Zyrixtrex",
|
|
"120500656+ooovenenoso@users.noreply.github.com": "ooovenenoso", # PR #28256 salvage (tool loop recovery hints)
|
|
"120500656+oooindefatigable@users.noreply.github.com": "ooovenenoso",
|
|
"vanthinh6886@gmail.com": "vanthinh6886", # PR #28018 salvage (yaml/flock/atomic write guards)
|
|
"erik.engervall@gmail.com": "erikengervall", # PR #28774 (firecrawl integration tag)
|
|
}
|
|
|
|
|
|
def git(*args, cwd=None):
|
|
"""Run a git command and return stdout."""
|
|
result = subprocess.run(
|
|
["git"] + list(args),
|
|
capture_output=True, text=True,
|
|
cwd=cwd or str(REPO_ROOT),
|
|
)
|
|
if result.returncode != 0:
|
|
print(f"git {' '.join(args)} failed: {result.stderr}", file=sys.stderr)
|
|
return ""
|
|
return result.stdout.strip()
|
|
|
|
|
|
def git_result(*args, cwd=None):
|
|
"""Run a git command and return the full CompletedProcess."""
|
|
return subprocess.run(
|
|
["git"] + list(args),
|
|
capture_output=True,
|
|
text=True,
|
|
cwd=cwd or str(REPO_ROOT),
|
|
)
|
|
|
|
|
|
def get_last_tag():
|
|
"""Get the most recent CalVer tag."""
|
|
tags = git("tag", "--list", "v20*", "--sort=-v:refname")
|
|
if tags:
|
|
return tags.split("\n")[0]
|
|
return None
|
|
|
|
|
|
def next_available_tag(base_tag: str) -> tuple[str, str]:
|
|
"""Return a tag/calver pair, suffixing same-day releases when needed."""
|
|
if not git("tag", "--list", base_tag):
|
|
return base_tag, base_tag.removeprefix("v")
|
|
|
|
suffix = 2
|
|
while git("tag", "--list", f"{base_tag}.{suffix}"):
|
|
suffix += 1
|
|
tag_name = f"{base_tag}.{suffix}"
|
|
return tag_name, tag_name.removeprefix("v")
|
|
|
|
|
|
def get_current_version():
|
|
"""Read current semver from __init__.py."""
|
|
content = VERSION_FILE.read_text()
|
|
match = re.search(r'__version__\s*=\s*"([^"]+)"', content)
|
|
return match.group(1) if match else "0.0.0"
|
|
|
|
|
|
def bump_version(current: str, part: str) -> str:
|
|
"""Bump a semver version string."""
|
|
parts = current.split(".")
|
|
if len(parts) != 3:
|
|
parts = ["0", "0", "0"]
|
|
major, minor, patch = int(parts[0]), int(parts[1]), int(parts[2])
|
|
|
|
if part == "major":
|
|
major += 1
|
|
minor = 0
|
|
patch = 0
|
|
elif part == "minor":
|
|
minor += 1
|
|
patch = 0
|
|
elif part == "patch":
|
|
patch += 1
|
|
else:
|
|
raise ValueError(f"Unknown bump part: {part}")
|
|
|
|
return f"{major}.{minor}.{patch}"
|
|
|
|
|
|
def update_version_files(semver: str, calver_date: str):
|
|
"""Update version strings in source files."""
|
|
# Update __init__.py
|
|
content = VERSION_FILE.read_text()
|
|
content = re.sub(
|
|
r'__version__\s*=\s*"[^"]+"',
|
|
f'__version__ = "{semver}"',
|
|
content,
|
|
)
|
|
content = re.sub(
|
|
r'__release_date__\s*=\s*"[^"]+"',
|
|
f'__release_date__ = "{calver_date}"',
|
|
content,
|
|
)
|
|
VERSION_FILE.write_text(content)
|
|
|
|
# Update pyproject.toml
|
|
pyproject = PYPROJECT_FILE.read_text()
|
|
pyproject = re.sub(
|
|
r'^version\s*=\s*"[^"]+"',
|
|
f'version = "{semver}"',
|
|
pyproject,
|
|
flags=re.MULTILINE,
|
|
)
|
|
PYPROJECT_FILE.write_text(pyproject)
|
|
|
|
# Update ACP Registry manifest + npm launcher (must stay version-locked
|
|
# with pyproject — enforced by tests/acp/test_registry_manifest.py).
|
|
_update_acp_registry_versions(semver)
|
|
|
|
|
|
def _update_acp_registry_versions(semver: str) -> None:
|
|
"""Bump the ACP Registry manifest's version + uvx package pin in lockstep
|
|
with pyproject.
|
|
|
|
Skips silently if the manifest is missing — older release branches predate
|
|
the ACP Registry assets.
|
|
"""
|
|
if ACP_REGISTRY_MANIFEST.exists():
|
|
manifest = json.loads(ACP_REGISTRY_MANIFEST.read_text(encoding="utf-8"))
|
|
manifest["version"] = semver
|
|
uvx = manifest.get("distribution", {}).get("uvx", {})
|
|
if "package" in uvx:
|
|
uvx["package"] = f"hermes-agent[acp]=={semver}"
|
|
# Preserve trailing newline + 2-space indent the file already uses.
|
|
ACP_REGISTRY_MANIFEST.write_text(
|
|
json.dumps(manifest, indent=2) + "\n", encoding="utf-8"
|
|
)
|
|
|
|
|
|
def build_release_artifacts(semver: str) -> list[Path]:
|
|
"""Build sdist/wheel artifacts for the current release.
|
|
|
|
Tries ``uv build`` first (matching the CI workflow), falls back to
|
|
``python -m build`` if uv is unavailable.
|
|
"""
|
|
dist_dir = REPO_ROOT / "dist"
|
|
shutil.rmtree(dist_dir, ignore_errors=True)
|
|
|
|
# Prefer uv build (matches CI workflow), fall back to python -m build.
|
|
uv_bin = shutil.which("uv")
|
|
if uv_bin:
|
|
cmd = [uv_bin, "build", "--sdist", "--wheel"]
|
|
else:
|
|
cmd = [sys.executable, "-m", "build", "--sdist", "--wheel"]
|
|
|
|
result = subprocess.run(
|
|
cmd,
|
|
cwd=str(REPO_ROOT),
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
if result.returncode != 0:
|
|
print(" ⚠ Could not build Python release artifacts.")
|
|
stderr = result.stderr.strip()
|
|
stdout = result.stdout.strip()
|
|
if stderr:
|
|
print(f" {stderr.splitlines()[-1]}")
|
|
elif stdout:
|
|
print(f" {stdout.splitlines()[-1]}")
|
|
print(" Install uv or the 'build' package to attach sdist/wheel assets.")
|
|
return []
|
|
|
|
artifacts = sorted(p for p in dist_dir.iterdir() if p.is_file())
|
|
matching = [p for p in artifacts if semver in p.name]
|
|
if not matching:
|
|
print(" ⚠ Built artifacts did not match the expected release version.")
|
|
return []
|
|
return matching
|
|
|
|
|
|
def resolve_author(name: str, email: str) -> str:
|
|
"""Resolve a git author to a GitHub @mention."""
|
|
# Try email lookup first
|
|
gh_user = AUTHOR_MAP.get(email)
|
|
if gh_user:
|
|
return f"@{gh_user}"
|
|
|
|
# Try noreply pattern
|
|
noreply_match = re.match(r"(\d+)\+(.+)@users\.noreply\.github\.com", email)
|
|
if noreply_match:
|
|
return f"@{noreply_match.group(2)}"
|
|
|
|
# Try username@users.noreply.github.com
|
|
noreply_match2 = re.match(r"(.+)@users\.noreply\.github\.com", email)
|
|
if noreply_match2:
|
|
return f"@{noreply_match2.group(1)}"
|
|
|
|
# Fallback to git name
|
|
return name
|
|
|
|
|
|
def categorize_commit(subject: str) -> str:
|
|
"""Categorize a commit by its conventional commit prefix."""
|
|
subject_lower = subject.lower()
|
|
|
|
# Match conventional commit patterns
|
|
patterns = {
|
|
"breaking": [r"^breaking[\s:(]", r"^!:", r"BREAKING CHANGE"],
|
|
"features": [r"^feat[\s:(]", r"^feature[\s:(]", r"^add[\s:(]"],
|
|
"fixes": [r"^fix[\s:(]", r"^bugfix[\s:(]", r"^bug[\s:(]", r"^hotfix[\s:(]"],
|
|
"improvements": [r"^improve[\s:(]", r"^perf[\s:(]", r"^enhance[\s:(]",
|
|
r"^refactor[\s:(]", r"^cleanup[\s:(]", r"^clean[\s:(]",
|
|
r"^update[\s:(]", r"^optimize[\s:(]"],
|
|
"docs": [r"^doc[\s:(]", r"^docs[\s:(]"],
|
|
"tests": [r"^test[\s:(]", r"^tests[\s:(]"],
|
|
"chore": [r"^chore[\s:(]", r"^ci[\s:(]", r"^build[\s:(]",
|
|
r"^deps[\s:(]", r"^bump[\s:(]"],
|
|
}
|
|
|
|
for category, regexes in patterns.items():
|
|
for regex in regexes:
|
|
if re.match(regex, subject_lower):
|
|
return category
|
|
|
|
# Heuristic fallbacks
|
|
if any(w in subject_lower for w in ["add ", "new ", "implement", "support "]):
|
|
return "features"
|
|
if any(w in subject_lower for w in ["fix ", "fixed ", "resolve", "patch "]):
|
|
return "fixes"
|
|
if any(w in subject_lower for w in ["refactor", "cleanup", "improve", "update "]):
|
|
return "improvements"
|
|
|
|
return "other"
|
|
|
|
|
|
def clean_subject(subject: str) -> str:
|
|
"""Clean up a commit subject for display."""
|
|
# Remove conventional commit prefix
|
|
cleaned = re.sub(r"^(feat|fix|docs|chore|refactor|test|perf|ci|build|improve|add|update|cleanup|hotfix|breaking|enhance|optimize|bugfix|bug|feature|tests|deps|bump)[\s:(!]+\s*", "", subject, flags=re.IGNORECASE)
|
|
# Remove trailing issue refs that are redundant with PR links
|
|
cleaned = cleaned.strip()
|
|
# Capitalize first letter
|
|
if cleaned:
|
|
cleaned = cleaned[0].upper() + cleaned[1:]
|
|
return cleaned
|
|
|
|
|
|
def parse_coauthors(body: str) -> list:
|
|
"""Extract Co-authored-by trailers from a commit message body.
|
|
|
|
Returns a list of {'name': ..., 'email': ...} dicts.
|
|
Filters out AI assistants and bots (Claude, Copilot, Cursor, etc.).
|
|
"""
|
|
if not body:
|
|
return []
|
|
# AI/bot emails to ignore in co-author trailers
|
|
_ignored_emails = {"noreply@anthropic.com", "noreply@github.com",
|
|
"cursoragent@cursor.com", "hermes@nousresearch.com"}
|
|
_ignored_names = re.compile(r"^(Claude|Copilot|Cursor Agent|GitHub Actions?|dependabot|renovate)", re.IGNORECASE)
|
|
pattern = re.compile(r"Co-authored-by:\s*(.+?)\s*<([^>]+)>", re.IGNORECASE)
|
|
results = []
|
|
for m in pattern.finditer(body):
|
|
name, email = m.group(1).strip(), m.group(2).strip()
|
|
if email in _ignored_emails or _ignored_names.match(name):
|
|
continue
|
|
results.append({"name": name, "email": email})
|
|
return results
|
|
|
|
|
|
def get_commits(since_tag=None):
|
|
"""Get commits since a tag (or all commits if None)."""
|
|
if since_tag:
|
|
range_spec = f"{since_tag}..HEAD"
|
|
else:
|
|
range_spec = "HEAD"
|
|
|
|
# Format: hash<US>author_name<US>author_email<US>subject\0body
|
|
# Using %x1f (unit separator) to avoid conflict with | in author names
|
|
log = git(
|
|
"log", range_spec,
|
|
"--format=%H%x1f%an%x1f%ae%x1f%s%x00%b%x00",
|
|
"--no-merges",
|
|
)
|
|
|
|
if not log:
|
|
return []
|
|
|
|
commits = []
|
|
# Split on double-null to get each commit entry, since body ends with \0
|
|
# and format ends with \0, each record ends with \0\0 between entries
|
|
for entry in log.split("\0\0"):
|
|
entry = entry.strip()
|
|
if not entry:
|
|
continue
|
|
# Split on first null to separate "hash<US>name<US>email<US>subject" from "body"
|
|
if "\0" in entry:
|
|
header, body = entry.split("\0", 1)
|
|
body = body.strip()
|
|
else:
|
|
header = entry
|
|
body = ""
|
|
parts = header.split("\x1f", 3)
|
|
if len(parts) != 4:
|
|
continue
|
|
sha, name, email, subject = parts
|
|
coauthor_info = parse_coauthors(body)
|
|
coauthors = [resolve_author(ca["name"], ca["email"]) for ca in coauthor_info]
|
|
commits.append({
|
|
"sha": sha,
|
|
"short_sha": sha[:8],
|
|
"author_name": name,
|
|
"author_email": email,
|
|
"subject": subject,
|
|
"category": categorize_commit(subject),
|
|
"github_author": resolve_author(name, email),
|
|
"coauthors": coauthors,
|
|
})
|
|
|
|
return commits
|
|
|
|
|
|
def get_pr_number(subject: str) -> str | None:
|
|
"""Extract PR number from commit subject if present."""
|
|
match = re.search(r"#(\d+)", subject)
|
|
if match:
|
|
return match.group(1)
|
|
return None
|
|
|
|
|
|
def generate_changelog(commits, tag_name, semver, repo_url="https://github.com/NousResearch/hermes-agent",
|
|
prev_tag=None, first_release=False):
|
|
"""Generate markdown changelog from categorized commits."""
|
|
lines = []
|
|
|
|
# Header
|
|
now = datetime.now()
|
|
date_str = now.strftime("%B %d, %Y")
|
|
lines.append(f"# Hermes Agent v{semver} ({tag_name})")
|
|
lines.append("")
|
|
lines.append(f"**Release Date:** {date_str}")
|
|
lines.append("")
|
|
|
|
if first_release:
|
|
lines.append("> 🎉 **First official release!** This marks the beginning of regular weekly releases")
|
|
lines.append("> for Hermes Agent. See below for everything included in this initial release.")
|
|
lines.append("")
|
|
|
|
# Group commits by category
|
|
categories = defaultdict(list)
|
|
all_authors = set()
|
|
teknium_aliases = {"@teknium1"}
|
|
|
|
for commit in commits:
|
|
categories[commit["category"]].append(commit)
|
|
author = commit["github_author"]
|
|
if author not in teknium_aliases:
|
|
all_authors.add(author)
|
|
for coauthor in commit.get("coauthors", []):
|
|
if coauthor not in teknium_aliases:
|
|
all_authors.add(coauthor)
|
|
|
|
# Category display order and emoji
|
|
category_order = [
|
|
("breaking", "⚠️ Breaking Changes"),
|
|
("features", "✨ Features"),
|
|
("improvements", "🔧 Improvements"),
|
|
("fixes", "🐛 Bug Fixes"),
|
|
("docs", "📚 Documentation"),
|
|
("tests", "🧪 Tests"),
|
|
("chore", "🏗️ Infrastructure"),
|
|
("other", "📦 Other Changes"),
|
|
]
|
|
|
|
for cat_key, cat_title in category_order:
|
|
cat_commits = categories.get(cat_key, [])
|
|
if not cat_commits:
|
|
continue
|
|
|
|
lines.append(f"## {cat_title}")
|
|
lines.append("")
|
|
|
|
for commit in cat_commits:
|
|
subject = clean_subject(commit["subject"])
|
|
pr_num = get_pr_number(commit["subject"])
|
|
author = commit["github_author"]
|
|
|
|
# Build the line
|
|
parts = [f"- {subject}"]
|
|
if pr_num:
|
|
parts.append(f"([#{pr_num}]({repo_url}/pull/{pr_num}))")
|
|
else:
|
|
parts.append(f"([`{commit['short_sha']}`]({repo_url}/commit/{commit['sha']}))")
|
|
|
|
if author not in teknium_aliases:
|
|
parts.append(f"— {author}")
|
|
|
|
lines.append(" ".join(parts))
|
|
|
|
lines.append("")
|
|
|
|
# Contributors section
|
|
if all_authors:
|
|
# Sort contributors by commit count
|
|
author_counts = defaultdict(int)
|
|
for commit in commits:
|
|
author = commit["github_author"]
|
|
if author not in teknium_aliases:
|
|
author_counts[author] += 1
|
|
for coauthor in commit.get("coauthors", []):
|
|
if coauthor not in teknium_aliases:
|
|
author_counts[coauthor] += 1
|
|
|
|
sorted_authors = sorted(author_counts.items(), key=lambda x: -x[1])
|
|
|
|
lines.append("## 👥 Contributors")
|
|
lines.append("")
|
|
lines.append("Thank you to everyone who contributed to this release!")
|
|
lines.append("")
|
|
for author, count in sorted_authors:
|
|
commit_word = "commit" if count == 1 else "commits"
|
|
lines.append(f"- {author} ({count} {commit_word})")
|
|
lines.append("")
|
|
|
|
# Full changelog link
|
|
if prev_tag:
|
|
lines.append(f"**Full Changelog**: [{prev_tag}...{tag_name}]({repo_url}/compare/{prev_tag}...{tag_name})")
|
|
else:
|
|
lines.append(f"**Full Changelog**: [{tag_name}]({repo_url}/commits/{tag_name})")
|
|
lines.append("")
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Hermes Agent Release Tool")
|
|
parser.add_argument("--bump", choices=["major", "minor", "patch"],
|
|
help="Which semver component to bump")
|
|
parser.add_argument("--publish", action="store_true",
|
|
help="Actually create the tag and GitHub release (otherwise dry run)")
|
|
parser.add_argument("--date", type=str,
|
|
help="Override CalVer date (format: YYYY.M.D)")
|
|
parser.add_argument("--first-release", action="store_true",
|
|
help="Mark as first release (no previous tag expected)")
|
|
parser.add_argument("--output", type=str,
|
|
help="Write changelog to file instead of stdout")
|
|
args = parser.parse_args()
|
|
|
|
# Determine CalVer date
|
|
if args.date:
|
|
calver_date = args.date
|
|
else:
|
|
now = datetime.now()
|
|
calver_date = f"{now.year}.{now.month}.{now.day}"
|
|
|
|
base_tag = f"v{calver_date}"
|
|
tag_name, calver_date = next_available_tag(base_tag)
|
|
if tag_name != base_tag:
|
|
print(f"Note: Tag {base_tag} already exists, using {tag_name}")
|
|
|
|
# Determine semver
|
|
current_version = get_current_version()
|
|
if args.bump:
|
|
new_version = bump_version(current_version, args.bump)
|
|
else:
|
|
new_version = current_version
|
|
|
|
# Get previous tag
|
|
prev_tag = get_last_tag()
|
|
if not prev_tag and not args.first_release:
|
|
print("No previous tags found. Use --first-release for the initial release.")
|
|
print(f"Would create tag: {tag_name}")
|
|
print(f"Would set version: {new_version}")
|
|
return
|
|
|
|
# Get commits
|
|
commits = get_commits(since_tag=prev_tag)
|
|
if not commits:
|
|
print("No new commits since last tag.")
|
|
if not args.first_release:
|
|
return
|
|
|
|
print(f"{'='*60}")
|
|
print(f" Hermes Agent Release Preview")
|
|
print(f"{'='*60}")
|
|
print(f" CalVer tag: {tag_name}")
|
|
print(f" SemVer: v{current_version} → v{new_version}")
|
|
print(f" Previous tag: {prev_tag or '(none — first release)'}")
|
|
print(f" Commits: {len(commits)}")
|
|
print(f" Unique authors: {len({c['github_author'] for c in commits})}")
|
|
print(f" Mode: {'PUBLISH' if args.publish else 'DRY RUN'}")
|
|
print(f"{'='*60}")
|
|
print()
|
|
|
|
# Generate changelog
|
|
changelog = generate_changelog(
|
|
commits, tag_name, new_version,
|
|
prev_tag=prev_tag,
|
|
first_release=args.first_release,
|
|
)
|
|
|
|
if args.output:
|
|
Path(args.output).write_text(changelog, encoding="utf-8")
|
|
print(f"Changelog written to {args.output}")
|
|
else:
|
|
print(changelog)
|
|
|
|
if args.publish:
|
|
print(f"\n{'='*60}")
|
|
print(" Publishing release...")
|
|
print(f"{'='*60}")
|
|
|
|
# Update version files
|
|
if args.bump:
|
|
update_version_files(new_version, calver_date)
|
|
print(f" ✓ Updated version files to v{new_version} ({calver_date})")
|
|
|
|
# Commit version bump
|
|
add_files = [str(VERSION_FILE), str(PYPROJECT_FILE)]
|
|
if ACP_REGISTRY_MANIFEST.exists():
|
|
add_files.append(str(ACP_REGISTRY_MANIFEST))
|
|
add_result = git_result("add", *add_files)
|
|
if add_result.returncode != 0:
|
|
print(f" ✗ Failed to stage version files: {add_result.stderr.strip()}")
|
|
return
|
|
|
|
commit_result = git_result(
|
|
"commit", "-m", f"chore: bump version to v{new_version} ({calver_date})"
|
|
)
|
|
if commit_result.returncode != 0:
|
|
print(f" ✗ Failed to commit version bump: {commit_result.stderr.strip()}")
|
|
return
|
|
print(f" ✓ Committed version bump")
|
|
|
|
# Create annotated tag
|
|
tag_result = git_result(
|
|
"tag", "-a", tag_name, "-m",
|
|
f"Hermes Agent v{new_version} ({calver_date})\n\nWeekly release"
|
|
)
|
|
if tag_result.returncode != 0:
|
|
print(f" ✗ Failed to create tag {tag_name}: {tag_result.stderr.strip()}")
|
|
return
|
|
print(f" ✓ Created tag {tag_name}")
|
|
|
|
# Push
|
|
push_result = git_result("push", "origin", "HEAD", "--tags")
|
|
if push_result.returncode == 0:
|
|
print(f" ✓ Pushed to origin")
|
|
else:
|
|
print(f" ✗ Failed to push to origin: {push_result.stderr.strip()}")
|
|
print(" Continue manually after fixing access:")
|
|
print(" git push origin HEAD --tags")
|
|
|
|
# Build semver-named Python artifacts so downstream packagers
|
|
# (e.g. Homebrew) can target them without relying on CalVer tag names.
|
|
artifacts = build_release_artifacts(new_version)
|
|
if artifacts:
|
|
print(" ✓ Built release artifacts:")
|
|
for artifact in artifacts:
|
|
print(f" - {artifact.relative_to(REPO_ROOT)}")
|
|
|
|
# Create GitHub release
|
|
changelog_file = REPO_ROOT / ".release_notes.md"
|
|
changelog_file.write_text(changelog, encoding="utf-8")
|
|
|
|
gh_cmd = [
|
|
"gh", "release", "create", tag_name,
|
|
"--title", f"Hermes Agent v{new_version} ({calver_date})",
|
|
"--notes-file", str(changelog_file),
|
|
]
|
|
gh_cmd.extend(str(path) for path in artifacts)
|
|
|
|
gh_bin = shutil.which("gh")
|
|
if gh_bin:
|
|
result = subprocess.run(
|
|
gh_cmd,
|
|
capture_output=True, text=True,
|
|
cwd=str(REPO_ROOT),
|
|
)
|
|
else:
|
|
result = None
|
|
|
|
if result and result.returncode == 0:
|
|
changelog_file.unlink(missing_ok=True)
|
|
print(f" ✓ GitHub release created: {result.stdout.strip()}")
|
|
print(f"\n 🎉 Release v{new_version} ({tag_name}) published!")
|
|
else:
|
|
if result is None:
|
|
print(" ✗ GitHub release skipped: `gh` CLI not found.")
|
|
else:
|
|
print(f" ✗ GitHub release failed: {result.stderr.strip()}")
|
|
print(f" Release notes kept at: {changelog_file}")
|
|
print(f" Tag was created locally. Create the release manually:")
|
|
print(
|
|
f" gh release create {tag_name} --title 'Hermes Agent v{new_version} ({calver_date})' "
|
|
f"--notes-file .release_notes.md {' '.join(str(path) for path in artifacts)}"
|
|
)
|
|
print(f"\n ✓ Release artifacts prepared for manual publish: v{new_version} ({tag_name})")
|
|
else:
|
|
print(f"\n{'='*60}")
|
|
print(f" Dry run complete. To publish, add --publish")
|
|
print(f" Example: python scripts/release.py --bump minor --publish")
|
|
print(f"{'='*60}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|