mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-14 14:12:44 +00:00
Merge origin/main into ethie/oh-god (pluginify refactor reconciliation)
Reconciles the "pluginify everything" refactor (moving provider adapters, platform adapters, and terminal backends out of core into plugins/) with 267 commits of main. main had 515 edits across 635 files; our branch moved 98 files into plugins/. The dangerous class was main editing files at OLD paths that we relocated — handled below. STRUCTURAL DECISIONS - ai-gateway + vercel_sandbox: honored main's PR #33067 deletion. Dropped our orphaned plugins/terminals/vercel/ dir and all 3 stale vercel refs that survived in pyproject (workspace member, [all] entry, uv source). - tools/lazy_deps.py: kept main's version. Our branch deleted it incompletely (WIP) while main has 30 live callers + active maintenance. main's intent won. - agent/agent_runtime_helpers.py: COMBINED — main's atomic swap+rollback snapshot envelope wraps our pluginified registries-based anthropic imports. - agent/credential_pool.py: took our plugin-hook indirection AND ported main's api_key_path_explicit OAuth-masquerade security fix INTO the anthropic credential_pool_hook (it was pluginified from a pre-fix base and would have been silently dropped otherwise). - hermes_cli/model_switch.py, hermes_cli/models.py: took main's logic (cached_provider_model_ids, AI-gateway removal) then re-applied our pluginify import rewrites (agent.bedrock_adapter/anthropic_adapter -> registries namespace lookups) since those modules moved to plugins. - tools/terminal_tool.py: took main's version (vercel_sandbox deletion) then restored our lazy registry resolution for modal + daytona environments (both moved to plugins; main's direct imports would crash at runtime). - nix/checks.nix: kept both — our hermetic-boundary checks + main's messaging-variant discord.py guard. - pyproject.toml: plugin extras as workspace members (ours) + main's new wecom extra; vercel removed throughout. - uv.lock: regenerated with `uv lock` (not hand-merged); 233 packages. VERIFICATION - Zero conflict markers anywhere. - Exhaustive 17-moved-module grep: no dead imports of relocated modules in core. - Import smoke test: all hot core modules import clean. - Targeted tests (21 files incl. credential_pool, anthropic plugin, run_agent, project_metadata): pass. - 3 credential_pool security tests rewired to register the real plugin hook (core tests don't trigger plugin discovery): pass. - Full suite: remaining failures are pre-existing on premerge-oh-god (telegram collection error: setUpModule MagicMock __code__) or environmental (matrix DNS/e2ee-deps, network) — NOT introduced by this merge. See PR notes.
This commit is contained in:
commit
48a7e137b1
645 changed files with 107201 additions and 7944 deletions
|
|
@ -40,6 +40,7 @@ from tools.skills_hub import (
|
|||
ClawHubSource,
|
||||
ClaudeMarketplaceSource,
|
||||
LobeHubSource,
|
||||
BrowseShSource,
|
||||
SkillMeta,
|
||||
)
|
||||
import httpx
|
||||
|
|
@ -79,30 +80,27 @@ def crawl_source(source, source_name: str, limit: int) -> list:
|
|||
|
||||
|
||||
def crawl_skills_sh(source: SkillsShSource) -> list:
|
||||
"""Crawl skills.sh using popular queries for broad coverage."""
|
||||
print(" Crawling skills.sh (popular queries)...", flush=True)
|
||||
"""Crawl skills.sh via its sitemap to enumerate the full catalog (~20k entries).
|
||||
|
||||
Previously walked a hardcoded list of ~28 popular keywords (each capped at
|
||||
50 results) which yielded ~850 unique skills — about 4% of the real catalog.
|
||||
The SkillsShSource.search("") path now hits the sitemap directly, returning
|
||||
the full 20k-entry catalog deduplicated by canonical identifier.
|
||||
"""
|
||||
print(" Crawling skills.sh (sitemap)...", flush=True)
|
||||
start = time.time()
|
||||
|
||||
queries = [
|
||||
"", # featured
|
||||
"react", "python", "web", "api", "database", "docker",
|
||||
"testing", "scraping", "design", "typescript", "git",
|
||||
"aws", "security", "data", "ml", "ai", "devops",
|
||||
"frontend", "backend", "mobile", "cli", "documentation",
|
||||
"kubernetes", "terraform", "rust", "go", "java",
|
||||
]
|
||||
try:
|
||||
results = source.search("", limit=0) # 0 = no cap, return the whole catalog
|
||||
except Exception as e:
|
||||
print(f" Warning: skills.sh sitemap walk failed: {e}", file=sys.stderr)
|
||||
results = []
|
||||
|
||||
all_skills: dict[str, dict] = {}
|
||||
for query in queries:
|
||||
try:
|
||||
results = source.search(query, limit=50)
|
||||
for meta in results:
|
||||
entry = _meta_to_dict(meta)
|
||||
if entry["identifier"] not in all_skills:
|
||||
all_skills[entry["identifier"]] = entry
|
||||
except Exception as e:
|
||||
print(f" Warning: skills.sh search '{query}' failed: {e}",
|
||||
file=sys.stderr)
|
||||
for meta in results:
|
||||
entry = _meta_to_dict(meta)
|
||||
if entry["identifier"] not in all_skills:
|
||||
all_skills[entry["identifier"]] = entry
|
||||
|
||||
elapsed = time.time() - start
|
||||
print(f" skills.sh: {len(all_skills)} unique skills ({elapsed:.1f}s)",
|
||||
|
|
@ -260,6 +258,7 @@ def main():
|
|||
"clawhub": ClawHubSource(),
|
||||
"claude-marketplace": ClaudeMarketplaceSource(auth=auth),
|
||||
"lobehub": LobeHubSource(),
|
||||
"browse-sh": BrowseShSource(),
|
||||
}
|
||||
|
||||
all_skills: list[dict] = []
|
||||
|
|
@ -267,11 +266,28 @@ def main():
|
|||
# Crawl skills.sh
|
||||
all_skills.extend(crawl_skills_sh(skills_sh_source))
|
||||
|
||||
# Crawl other sources in parallel
|
||||
# Crawl other sources in parallel.
|
||||
# Per-source soft caps — sources stop returning when they run out, so these
|
||||
# are ceilings, not targets. ClawHub has 20k+ skills; bumping to 100k
|
||||
# (well above current catalog size) lets the full catalog land in the
|
||||
# index instead of being truncated at an arbitrary build-time limit.
|
||||
SOURCE_LIMITS = {
|
||||
# ClawHub had 49,698+ skills as of May 2026; 200k leaves headroom.
|
||||
"clawhub": 200_000,
|
||||
"lobehub": 100_000,
|
||||
"browse-sh": 5_000,
|
||||
"claude-marketplace": 5_000,
|
||||
"github": 5_000,
|
||||
"well-known": 5_000,
|
||||
"official": 5_000,
|
||||
}
|
||||
DEFAULT_SOURCE_LIMIT = 500
|
||||
|
||||
with ThreadPoolExecutor(max_workers=4) as pool:
|
||||
futures = {}
|
||||
for name, source in sources.items():
|
||||
futures[pool.submit(crawl_source, source, name, 500)] = name
|
||||
limit = SOURCE_LIMITS.get(name, DEFAULT_SOURCE_LIMIT)
|
||||
futures[pool.submit(crawl_source, source, name, limit)] = name
|
||||
for future in as_completed(futures):
|
||||
try:
|
||||
all_skills.extend(future.result())
|
||||
|
|
@ -292,7 +308,7 @@ def main():
|
|||
# Sort
|
||||
source_order = {"official": 0, "skills-sh": 1, "skills.sh": 1,
|
||||
"github": 2, "well-known": 3, "clawhub": 4,
|
||||
"claude-marketplace": 5, "lobehub": 6}
|
||||
"browse-sh": 5, "claude-marketplace": 6, "lobehub": 7}
|
||||
deduped.sort(key=lambda s: (source_order.get(s["source"], 99), s["name"]))
|
||||
|
||||
# Build index
|
||||
|
|
@ -320,6 +336,58 @@ def main():
|
|||
extra = f" ({resolved} resolved)" if resolved else ""
|
||||
print(f" {src}: {count}{extra}")
|
||||
|
||||
# Health check: catch silent breakage early. Every source listed below
|
||||
# has historically returned at least `floor` entries; a zero (or near-
|
||||
# zero) result almost certainly means a tap path moved, an API changed,
|
||||
# or rate limiting kicked in. Failing here forces a human look before
|
||||
# the broken index reaches the live docs.
|
||||
EXPECTED_FLOORS = {
|
||||
# skills.sh now uses the sitemap walker (~20k catalog as of May 2026).
|
||||
# Anything under 10k means the sitemap shape changed or fetches failed
|
||||
# — better to fail loudly than ship a regression to the 858-skill
|
||||
# popular-queries era.
|
||||
"skills.sh": 10000,
|
||||
"lobehub": 100,
|
||||
# ClawHub had 49,698+ skills as of May 2026 — anything under 20k means
|
||||
# pagination broke or the API surface changed. Fail loudly rather
|
||||
# than ship a degenerate index (we shipped 200/50000 silently for
|
||||
# weeks because the floor was 50).
|
||||
"clawhub": 20000,
|
||||
"official": 50,
|
||||
"github": 30, # collapsed across all GitHub taps
|
||||
"browse-sh": 50,
|
||||
}
|
||||
health_errors = []
|
||||
for src, floor in EXPECTED_FLOORS.items():
|
||||
# 'skills-sh' and 'skills.sh' are the same source; both labels exist.
|
||||
count = by_source.get(src, 0)
|
||||
if src == "skills.sh":
|
||||
count = by_source.get("skills.sh", 0) + by_source.get("skills-sh", 0)
|
||||
if count < floor:
|
||||
health_errors.append(f" {src}: {count} < expected floor {floor}")
|
||||
|
||||
MIN_TOTAL = 1500
|
||||
if len(deduped) < MIN_TOTAL:
|
||||
health_errors.append(
|
||||
f" total: {len(deduped)} < expected floor {MIN_TOTAL}"
|
||||
)
|
||||
|
||||
if health_errors:
|
||||
print(
|
||||
"\nERROR: skills index health check failed — refusing to ship "
|
||||
"a degenerate index. Investigate the following sources:",
|
||||
file=sys.stderr,
|
||||
)
|
||||
for line in health_errors:
|
||||
print(line, file=sys.stderr)
|
||||
print(
|
||||
"\nIf the drop is expected (e.g. a hub is genuinely shutting "
|
||||
"down), lower the floor in scripts/build_skills_index.py "
|
||||
"EXPECTED_FLOORS in the same PR.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ IGNORED_PATTERNS = [
|
|||
re.compile(r"^Copilot$", re.IGNORECASE),
|
||||
re.compile(r"^Cursor(\s+Agent)?$", re.IGNORECASE),
|
||||
re.compile(r"^GitHub\s*Actions?$", re.IGNORECASE),
|
||||
re.compile(r"^github-actions(\[bot\])?$", re.IGNORECASE),
|
||||
re.compile(r"^dependabot", re.IGNORECASE),
|
||||
re.compile(r"^renovate", re.IGNORECASE),
|
||||
re.compile(r"^Hermes\s+(Agent|Audit)$", re.IGNORECASE),
|
||||
|
|
@ -51,10 +52,12 @@ IGNORED_PATTERNS = [
|
|||
IGNORED_EMAILS = {
|
||||
"noreply@anthropic.com",
|
||||
"noreply@github.com",
|
||||
"noreply@nousresearch.com",
|
||||
"cursoragent@cursor.com",
|
||||
"hermes@nousresearch.com",
|
||||
"hermes-audit@example.com",
|
||||
"hermes@habibilabs.dev",
|
||||
"omx@oh-my-codex.dev",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -268,10 +268,18 @@ resolve_install_layout() {
|
|||
fi
|
||||
INSTALL_DIR="/usr/local/lib/hermes-agent"
|
||||
ROOT_FHS_LAYOUT=true
|
||||
# Place uv-managed Python under /usr/local/share so the venv interpreter
|
||||
# is world-readable. Default uv paths land in /root/.local/share/uv,
|
||||
# which non-root users can't traverse — leaving the shared
|
||||
# /usr/local/bin/hermes wrapper unable to exec the bad-interpreter venv
|
||||
# python. See #21457.
|
||||
export UV_PYTHON_INSTALL_DIR="${UV_PYTHON_INSTALL_DIR:-/usr/local/share/uv/python}"
|
||||
export UV_PYTHON_BIN_DIR="${UV_PYTHON_BIN_DIR:-/usr/local/share/uv/bin}"
|
||||
log_info "Root install on Linux — using FHS layout"
|
||||
log_info " Code: $INSTALL_DIR"
|
||||
log_info " Command: /usr/local/bin/hermes"
|
||||
log_info " Data: $HERMES_HOME (unchanged)"
|
||||
log_info " uv Python: $UV_PYTHON_INSTALL_DIR (world-readable)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -27,21 +27,22 @@ import argparse
|
|||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
|
||||
# Pin a version we know patches cleanly. Update when a newer psutil
|
||||
# changes the marker line shape and we need to follow upstream.
|
||||
PSUTIL_URL = (
|
||||
"https://files.pythonhosted.org/packages/aa/c6/"
|
||||
"d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/"
|
||||
"psutil-7.2.2.tar.gz"
|
||||
# Keep sibling imports working when invoked as
|
||||
# ``python scripts/install_psutil_android.py`` from the repo checkout.
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from hermes_cli.psutil_android import (
|
||||
PSUTIL_URL,
|
||||
PsutilAndroidInstallError,
|
||||
prepare_patched_psutil_sdist,
|
||||
)
|
||||
|
||||
MARKER = 'LINUX = sys.platform.startswith("linux")'
|
||||
REPLACEMENT = 'LINUX = sys.platform.startswith(("linux", "android"))'
|
||||
|
||||
|
||||
def _resolve_install_cmd(pip_arg: str | None, prefer_uv: bool) -> list[str]:
|
||||
|
|
@ -82,26 +83,10 @@ def main() -> int:
|
|||
tmp_path = Path(tmp)
|
||||
archive = tmp_path / "psutil.tar.gz"
|
||||
urllib.request.urlretrieve(PSUTIL_URL, archive)
|
||||
with tarfile.open(archive) as tar:
|
||||
tar.extractall(tmp_path)
|
||||
|
||||
try:
|
||||
src_root = next(
|
||||
p for p in tmp_path.iterdir()
|
||||
if p.is_dir() and p.name.startswith("psutil-")
|
||||
)
|
||||
except StopIteration:
|
||||
sys.exit("psutil sdist did not contain a psutil-* directory")
|
||||
|
||||
common_py = src_root / "psutil" / "_common.py"
|
||||
content = common_py.read_text(encoding="utf-8")
|
||||
if MARKER not in content:
|
||||
sys.exit(
|
||||
"psutil Android compatibility patch marker not found — "
|
||||
"upstream may have changed the LINUX detection line. "
|
||||
"Update MARKER/REPLACEMENT in this script."
|
||||
)
|
||||
common_py.write_text(content.replace(MARKER, REPLACEMENT), encoding="utf-8")
|
||||
src_root = prepare_patched_psutil_sdist(archive, tmp_path)
|
||||
except PsutilAndroidInstallError as exc:
|
||||
sys.exit(str(exc))
|
||||
|
||||
cmd = install_cmd_prefix + ["install", "--no-build-isolation", str(src_root)]
|
||||
print(f" $ {' '.join(cmd)}")
|
||||
|
|
|
|||
|
|
@ -46,10 +46,24 @@ ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
|||
# Auto-extracted from noreply emails + manual overrides
|
||||
AUTHOR_MAP = {
|
||||
"9592417+adam91holt@users.noreply.github.com": "adam91holt",
|
||||
"kchuang1015@users.noreply.github.com": "kchuang1015",
|
||||
"45688690+fujinice@users.noreply.github.com": "fujinice",
|
||||
"276689385+carltonawong@users.noreply.github.com": "carltonawong",
|
||||
"195255660+EvilHumphrey@users.noreply.github.com": "EvilHumphrey",
|
||||
"270604154+superearn-fisher@users.noreply.github.com": "superearn-fisher",
|
||||
"3540493+kpadilha@users.noreply.github.com": "kpadilha",
|
||||
"40378218+chaconne67@users.noreply.github.com": "chaconne67",
|
||||
"Pluviobyte@users.noreply.github.com": "Pluviobyte",
|
||||
"sanghyuk_seo@nexcubecorp.com": "sanghyuk-seo-nexcube",
|
||||
"subrtt@gmail.com": "Brixyy",
|
||||
"wangpuv@hotmail.com": "wangpuv",
|
||||
"202622897+ticketclosed-wontfix@users.noreply.github.com": "ticketclosed-wontfix",
|
||||
"wuxuebin1993@gmail.com": "victorGPT",
|
||||
# teknium (multiple emails)
|
||||
"teknium1@gmail.com": "teknium1",
|
||||
"kenyon1977@gmail.com": "kenyonxu",
|
||||
"cipherframe@users.noreply.github.com": "CipherFrame",
|
||||
"donovan-yohan@users.noreply.github.com": "donovan-yohan",
|
||||
"121752779+jacevys@users.noreply.github.com": "jacevys",
|
||||
"me@promplate.dev": "CNSeniorious000",
|
||||
"yichengqiao21@gmail.com": "YarrowQiao",
|
||||
|
|
@ -59,6 +73,9 @@ AUTHOR_MAP = {
|
|||
"schepers.zander1@gmail.com": "Strontvod",
|
||||
"ed@bebop.crew": "someaka",
|
||||
"anadi.jaggia@gmail.com": "Jaggia",
|
||||
"steve@steveonjava.com": "steveonjava",
|
||||
"steveonjava@gmail.com": "steveonjava",
|
||||
"squiddy@2rook.ai": "MoonRay305",
|
||||
"32201324+simpolism@users.noreply.github.com": "simpolism",
|
||||
"simpolism@gmail.com": "simpolism",
|
||||
"jake@nousresearch.com": "simpolism",
|
||||
|
|
@ -73,6 +90,7 @@ AUTHOR_MAP = {
|
|||
"omar@techdeveloper.site": "nycomar",
|
||||
"qiyin.zuo@pcitc.com": "qiyin-code",
|
||||
"mr.aashiz@gmail.com": "aashizpoudel",
|
||||
"adityargadgil@gmail.com": "AdityaRajeshGadgil",
|
||||
"70629228+shaun0927@users.noreply.github.com": "shaun0927",
|
||||
"soju06@users.noreply.github.com": "Soju06",
|
||||
"34199905+Soju06@users.noreply.github.com": "Soju06",
|
||||
|
|
@ -83,10 +101,13 @@ AUTHOR_MAP = {
|
|||
"kronexoi13@gmail.com": "kronexoi",
|
||||
"hua.zhong@kingsmith.com": "vgocoder",
|
||||
"hermes@marian.local": "Schrotti77",
|
||||
"david@memorilabs.ai": "devwdave",
|
||||
"dave@devwdave.com": "devwdave",
|
||||
"1920071390@campus.ouj.ac.jp": "zapabob",
|
||||
"gaia@gaia.local": "jfuenmayor",
|
||||
"jiahuigu@users.noreply.github.com": "Jiahui-Gu",
|
||||
"openhands@all-hands.dev": "YLChen-007",
|
||||
"3153586+xzessmedia@users.noreply.github.com": "xzessmedia",
|
||||
"AdamPlatin123@outlook.com": "AdamPlatin123",
|
||||
"32711803+waefrebeorn@users.noreply.github.com": "waefrebeorn",
|
||||
"32869278+dusterbloom@users.noreply.github.com": "dusterbloom",
|
||||
|
|
@ -109,6 +130,7 @@ AUTHOR_MAP = {
|
|||
"buraysandro9@gmail.com": "ygd58",
|
||||
"108427749+buntingszn@users.noreply.github.com": "buntingszn",
|
||||
"yanglongwei06@gmail.com": "Alex-yang00",
|
||||
"yanghongda@jackyun.com": "yangguangjin",
|
||||
"teknium@nousresearch.com": "teknium1",
|
||||
"markuscontasul@gmail.com": "Glucksberg",
|
||||
"80581902+Glucksberg@users.noreply.github.com": "Glucksberg",
|
||||
|
|
@ -240,6 +262,8 @@ AUTHOR_MAP = {
|
|||
"jonathan.troyer@overmatch.com": "JTroyerOvermatch",
|
||||
"harryykyle1@gmail.com": "hharry11",
|
||||
"wysie@users.noreply.github.com": "wysie",
|
||||
"ronhi@buildabear1.localdomain": "RonHillDev", # PR #29523 salvage (machine-local commit email)
|
||||
"hello@nami4d.tech": "Nami4D", # PR #28490 salvage
|
||||
"jkausel@gmail.com": "jkausel-ai",
|
||||
"e.silacandmr@gmail.com": "Es1la",
|
||||
"51599529+stephen0110@users.noreply.github.com": "stephen0110",
|
||||
|
|
@ -249,10 +273,13 @@ AUTHOR_MAP = {
|
|||
"maciekczech@users.noreply.github.com": "maciekczech",
|
||||
"154585401+LeonSGP43@users.noreply.github.com": "LeonSGP43",
|
||||
"cine.dreamer.one@gmail.com": "LeonSGP43",
|
||||
"david@nutricraft.ca": "cyb0rgk1tty",
|
||||
"chris+dora@cmullins.io": "cmullins70",
|
||||
"zjtan1@gmail.com": "zeejaytan",
|
||||
"asslaenn5@gmail.com": "Aslaaen",
|
||||
"trae.anderson17@icloud.com": "Tkander1715",
|
||||
"beardthelion@users.noreply.github.com": "beardthelion",
|
||||
"orkunozturk@gmail.com": "orcool",
|
||||
"tangyuanjc@JCdeAIfenshendeMac-mini.local": "tangyuanjc",
|
||||
"leon@agentlinker.ai": "agentlinker",
|
||||
"santoshhumagain1887@gmail.com": "npmisantosh",
|
||||
|
|
@ -548,7 +575,7 @@ AUTHOR_MAP = {
|
|||
"ruzzgarcn@gmail.com": "Ruzzgar",
|
||||
"yukipukikedy@gmail.com": "Yukipukii1",
|
||||
"alireza78.crypto@gmail.com": "alireza78a",
|
||||
"brooklyn.bb.nicholson@gmail.com": "brooklynnicholson",
|
||||
"brooklyn.bb.nicholson@gmail.com": "OutThisLife",
|
||||
"withapurpose37@gmail.com": "StefanIsMe",
|
||||
"4317663+helix4u@users.noreply.github.com": "helix4u",
|
||||
"ifkellx@users.noreply.github.com": "Ifkellx",
|
||||
|
|
@ -1267,6 +1294,8 @@ AUTHOR_MAP = {
|
|||
"rudi193@gmail.com": "rudi193-cmd",
|
||||
"86684667+sadiksaifi@users.noreply.github.com": "sadiksaifi", # PR #27982 salvage (kanban horiz scroll)
|
||||
"mail@sadiksaifi.dev": "sadiksaifi",
|
||||
"231588442+vynxevainglory-ai@users.noreply.github.com": "vynxevainglory-ai", # PR #29233 salvage (kanban scrollbar + body overflow)
|
||||
"vynxevainglory@gmail.com": "vynxevainglory-ai",
|
||||
# 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)
|
||||
|
|
@ -1275,6 +1304,10 @@ AUTHOR_MAP = {
|
|||
"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)
|
||||
"33547839+sir-ad@users.noreply.github.com": "sir-ad", # PR #31941 salvage (compaction noise)
|
||||
"adarsh.agrahari26@gmail.com": "sir-ad",
|
||||
"269599864+rdasilva1016-ui@users.noreply.github.com": "rdasilva1016-ui", # PR #31098 salvage (Telegram /start ping)
|
||||
"rdasilva1016-ui@users.noreply.github.com": "rdasilva1016-ui",
|
||||
"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",
|
||||
|
|
@ -1312,6 +1345,29 @@ AUTHOR_MAP = {
|
|||
"66773372+Tranquil-Flow@users.noreply.github.com": "Tranquil-Flow", # PR #27518 (bracketed-paste timeout)
|
||||
"8bit64k@pm.me": "8bit64k", # PR #14681 (TUI /q alias from quit to queue)
|
||||
"chenglunhu@gmail.com": "hclsys", # PR #31985 (TUI /q alias regression test)
|
||||
"dearmayo@localhost": "ffr31mr", # PR #32103 (SubdirectoryHintTracker workspace boundary)
|
||||
"TheOnlyMika@users.noreply.github.com": "TheOnlyMika", # PR #32155 (dashboard XSS + defusedxml)
|
||||
"krislidimo@gmail.com": "krislidimo", # PR #29775 (tighten Telegram table row-group spacing; drop redundant first bullet)
|
||||
"timothy.b.dixon@gmail.com": "Codename-11", # PR #29302 (API server session controls — sessions/chat/fork/stream)
|
||||
"jpschwartz2@uwalumni.com": "Schwartz10", # PR #29302 sub-PR (multimodal media in session chat API)
|
||||
"JohnC1009@users.noreply.github.com": "JohnC1009", # PR #32020 salvage (auth: global auth.json fallback in _load_provider_state)
|
||||
"biser@bisko.be": "bisko", # PR #33784 salvage (re-pad reasoning_content on cross-provider fallback to require-side providers)
|
||||
# v0.15.0 additions
|
||||
"glen@workmanfirearms.com": "sgtworkman",
|
||||
"jorge.fuenmayort@gmail.com": "jfuenmayor",
|
||||
"mordred@inaugust.com": "emonty",
|
||||
"rodrigoeq@hotmail.com": "rodrigoeqnit",
|
||||
"soliva.johnpaul@icloud.com": "jonpol01",
|
||||
"2182712990@qq.com": "yu-xin-c", # PR #32122 (Docker audio bridge notes)
|
||||
"baxter@bitreserve.ai": "BaxBit", # PR #30200 (Svix webhook signature validation)
|
||||
"chris.eth@qq.com": "duyua9", # PR #10949 (render object config values structurally)
|
||||
"ethie@nous": "ethernet8023", # PR #29342 (TUI clipboard copy on linux/wayland)
|
||||
"jiahuigu@sjtu.edu.cn": "Jiahui-Gu", # PR #29276 (guard pickle.loads in darwinian-evolver)
|
||||
"justinccdev@gmail.com": "justincc", # PR #28914 (set tool_name on tool-result messages)
|
||||
"kdkcfp@gmail.com": "slowtokki0409", # PR #29025 (ignore local Hermes runtime files)
|
||||
"peter.yuqin@gmail.com": "WuKongAI-CMU", # PR #10082 (reject symlinked audio inputs)
|
||||
"sunil.nitie@gmail.com": "Sunil123135", # PR #31031 (Windows Docker Desktop compose)
|
||||
"weichangyuwcy@gmail.com": "ChyuWei", # PR #30987 (TUI TTS env var on voice off)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue