From 436104b944365830155e4a38766db84652699164 Mon Sep 17 00:00:00 2001 From: Kristian Vastveit Date: Sun, 12 Apr 2026 15:01:30 +0200 Subject: [PATCH] feat: add sitecustomize import hook --- sitecustomize_hook.py | 91 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 sitecustomize_hook.py diff --git a/sitecustomize_hook.py b/sitecustomize_hook.py new file mode 100644 index 0000000..4686c09 --- /dev/null +++ b/sitecustomize_hook.py @@ -0,0 +1,91 @@ +""" +sitecustomize hook — Claude Code OAuth bypass for hermes-agent. +=============================================================== + +This file is installed into the hermes-agent venv's site-packages as +``sitecustomize.py`` by ``install.sh``. It runs once at Python interpreter +startup (before any user code) and hooks the import of +``agent.anthropic_adapter`` so that the billing bypass patch is applied +immediately after the module loads. + +To disable: run ``uninstall.sh`` or delete the sitecustomize.py from the +venv's site-packages and restart hermes-gateway. + +DO NOT EDIT THIS FILE IN THE VENV — it will be overwritten on next install. +Edit the source in the hermes-claude-auth repo instead. +""" +# hermes-claude-auth managed — do not remove this marker + +from __future__ import annotations + +import os +import sys + +_PATCHES_DIR = os.environ.get( + "HERMES_PATCHES_DIR", + os.path.expanduser("~/.hermes/patches"), +) +_TARGET_MODULE = "agent.anthropic_adapter" + +if os.path.isdir(_PATCHES_DIR) and _PATCHES_DIR not in sys.path: + sys.path.insert(0, _PATCHES_DIR) + + +def _install_hook() -> None: + try: + from importlib.abc import MetaPathFinder + from importlib.util import find_spec + except ImportError: + return + + class _ClaudeCodeBypassFinder(MetaPathFinder): + _patched = False + + def find_spec(self, fullname, path=None, target=None): # type: ignore[override] + if fullname != _TARGET_MODULE or self._patched: + return None + + # Temporarily remove ourselves to avoid recursion during find_spec. + if self in sys.meta_path: + sys.meta_path.remove(self) + try: + spec = find_spec(fullname) + finally: + if self not in sys.meta_path: + sys.meta_path.insert(0, self) + + if spec is None or spec.loader is None: + return None + + original_exec = getattr(spec.loader, "exec_module", None) + if not callable(original_exec): + return None + + finder = self + + def patched_exec(module): # type: ignore[no-untyped-def] + original_exec(module) + finder._patched = True + try: + import anthropic_billing_bypass + + anthropic_billing_bypass.apply_patches(module) + except Exception as exc: + import traceback + + sys.stderr.write( + f"[hermes-claude-auth] bypass failed: " + f"{type(exc).__name__}: {exc}\n" + ) + traceback.print_exc(file=sys.stderr) + + spec.loader.exec_module = patched_exec # type: ignore[attr-defined] + return spec + + sys.meta_path.insert(0, _ClaudeCodeBypassFinder()) + + +try: + _install_hook() +except Exception as _exc: + sys.stderr.write(f"[hermes-claude-auth] hook install failed: {_exc}\n")