From 064dcda70604ac8c0b2ee9d059f00c329a299b5b Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 4 Sep 2026 01:33:40 -0700 Subject: [PATCH] compat(plugins): interactive CLI shows the banner notice only, not the raw per-name warnings Live PTY check: the banner block named the plugin correctly but was preceded by one stderr HermesPluginCompatWarning per moved name, duplicating it without the plugin name. warn_once now also logs at WARNING (agent.log/gateway.log keep the record); cli.main() appends an ignore filter for the category before plugin discovery. Appended, not overriding: -W error::...HermesPluginCompatWarning (tests, plugin authors' CI) still wins, verified with the strict test run. --- cli.py | 4 ++++ hermes_cli/plugin_compat.py | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cli.py b/cli.py index cbe2e9976f..01851a445d 100644 --- a/cli.py +++ b/cli.py @@ -4529,6 +4529,10 @@ def main( configure_windows_stdio() os.environ["HERMES_INTERACTIVE"] = "1" # terminal_tool: interactive sudo prompts with timeout + # The banner names affected plugins; the raw per-name compat warnings would only duplicate it on stderr. + with suppress(Exception): + from hermes_cli.plugin_compat import quiet_for_interactive + quiet_for_interactive() if gateway: _run_legacy_gateway() diff --git a/hermes_cli/plugin_compat.py b/hermes_cli/plugin_compat.py index d07b3f832a..f3cd758322 100644 --- a/hermes_cli/plugin_compat.py +++ b/hermes_cli/plugin_compat.py @@ -282,17 +282,28 @@ def summary_lines(report: Dict[str, List[Hit]], *, today: Optional[_dt.date] = N # ---------------------------------------------------------------------------------------------- runtime warn _seen: set = set() +_log = __import__("logging").getLogger(__name__) def warn_once(facade: str, name: str, target_module: str, target_name: str) -> None: + """Per-name record that a moved name was resolved through its old path: a ``HermesPluginCompatWarning`` + (so ``-W error`` catches it in tests and plugin authors' CI) plus a WARNING log line (agent.log / + gateway.log). The interactive CLI hides the warning category from stderr (:func:`quiet_for_interactive`) + because its banner carries the user-facing message with the plugin NAME, which this call site cannot know.""" key = (facade, name) if key in _seen: return _seen.add(key) new = f"{target_module}.{target_name}" if target_name != name else f"{target_module}.{name}" - warnings.warn( - f"hermes plugin compat: `{facade}.{name}` moved to `{new}`. The old path is kept only for external " - f"plugins and is removed on {COMPAT_REMOVAL}; update your import.", - HermesPluginCompatWarning, - stacklevel=3, - ) + msg = (f"hermes plugin compat: `{facade}.{name}` moved to `{new}`. The old path is kept only for external " + f"plugins and is removed on {COMPAT_REMOVAL}; update your import.") + _log.warning(msg) + warnings.warn(msg, HermesPluginCompatWarning, stacklevel=3) + + +def quiet_for_interactive() -> None: + """Called by the interactive CLI before plugin discovery: the banner notice replaces raw stderr warnings. + Appends (does not override) so an explicit ``-W error::...HermesPluginCompatWarning`` still wins.""" + if not any(a == "error" and c is not None and issubclass(HermesPluginCompatWarning, c) + for a, _m, c, _mod, _l in warnings.filters): + warnings.filterwarnings("ignore", category=HermesPluginCompatWarning, append=True)