diff --git a/cli.py b/cli.py index 09cb47e384..18d61ea772 100644 --- a/cli.py +++ b/cli.py @@ -5391,6 +5391,8 @@ class HermesCLI: self._show_usage() elif canonical == "insights": self._show_insights(cmd_original) + elif canonical == "debug": + self._handle_debug_command() elif canonical == "paste": self._handle_paste_command() elif canonical == "image": @@ -6305,6 +6307,14 @@ class HermesCLI: except Exception as e: print(f" ❌ Compression failed: {e}") + def _handle_debug_command(self): + """Handle /debug — upload debug report + logs and print paste URLs.""" + from hermes_cli.debug import run_debug_share + from types import SimpleNamespace + + args = SimpleNamespace(lines=200, expire=7, local=False) + run_debug_share(args) + def _show_usage(self): """Show rate limits (if available) and session token usage.""" if not self.agent: diff --git a/gateway/run.py b/gateway/run.py index 0b778e2f67..372cd474bb 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -2757,6 +2757,9 @@ class GatewayRunner: if canonical == "update": return await self._handle_update_command(event) + if canonical == "debug": + return await self._handle_debug_command(event) + if canonical == "title": return await self._handle_title_command(event) @@ -6428,6 +6431,61 @@ class GatewayRunner: Platform.FEISHU, Platform.WECOM, Platform.WECOM_CALLBACK, Platform.WEIXIN, Platform.BLUEBUBBLES, Platform.LOCAL, }) + async def _handle_debug_command(self, event: MessageEvent) -> str: + """Handle /debug — upload debug report + logs and return paste URLs.""" + import asyncio + from hermes_cli.debug import ( + _capture_dump, collect_debug_report, _read_full_log, + upload_to_pastebin, + ) + + loop = asyncio.get_running_loop() + + # Run blocking I/O (dump capture, log reads, uploads) in a thread. + def _collect_and_upload(): + dump_text = _capture_dump() + report = collect_debug_report(log_lines=200, dump_text=dump_text) + agent_log = _read_full_log("agent") + gateway_log = _read_full_log("gateway") + + if agent_log: + agent_log = dump_text + "\n\n--- full agent.log ---\n" + agent_log + if gateway_log: + gateway_log = dump_text + "\n\n--- full gateway.log ---\n" + gateway_log + + urls = {} + failures = [] + + try: + urls["Report"] = upload_to_pastebin(report) + except Exception as exc: + return f"✗ Failed to upload debug report: {exc}" + + if agent_log: + try: + urls["agent.log"] = upload_to_pastebin(agent_log) + except Exception: + failures.append("agent.log") + + if gateway_log: + try: + urls["gateway.log"] = upload_to_pastebin(gateway_log) + except Exception: + failures.append("gateway.log") + + lines = ["**Debug report uploaded:**", ""] + label_width = max(len(k) for k in urls) + for label, url in urls.items(): + lines.append(f"`{label:<{label_width}}` {url}") + + if failures: + lines.append(f"\n_(failed to upload: {', '.join(failures)})_") + + lines.append("\nShare these links with the Hermes team for support.") + return "\n".join(lines) + + return await loop.run_in_executor(None, _collect_and_upload) + async def _handle_update_command(self, event: MessageEvent) -> str: """Handle /update command — update Hermes Agent to the latest version. diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index 1c5a298d1e..b44a8aa8f0 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -154,6 +154,7 @@ COMMAND_REGISTRY: list[CommandDef] = [ cli_only=True, args_hint=""), CommandDef("update", "Update Hermes Agent to the latest version", "Info", gateway_only=True), + CommandDef("debug", "Upload debug report (system info + logs) and get shareable links", "Info"), # Exit CommandDef("quit", "Exit the CLI", "Exit",