fix(cli): escape exception text in agents-list error handler (#465)

`jarvis agents list` crashed with a secondary Rich MarkupError when the
underlying exception message contained markup metacharacters like
`[...]`: the error handler did `console.print(f"[red]Error: {exc}[/red]")`,
and Rich re-parsed the interpolated message as markup (#297).

Escape the dynamic message with rich.markup.escape and keep only the
static "Error:" label styled, so the original error surfaces cleanly
instead of a traceback. Adds a regression test that reproduces the
MarkupError via an exception message with brackets.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jon Saad-Falcon
2026-06-01 10:26:11 -07:00
committed by GitHub
co-authored by Claude Opus 4.8
parent bd1ab115ec
commit 3398e0c10b
2 changed files with 28 additions and 1 deletions
+7 -1
View File
@@ -88,7 +88,13 @@ def list_agents() -> None:
)
console.print(table)
except Exception as exc:
console.print(f"[red]Error: {exc}[/red]")
# Escape the dynamic exception text: Rich re-parses console.print
# arguments as markup, so an exception message containing "[...]"
# raises a secondary MarkupError (see #297). Keep the static
# "Error:" label styled; render the message literally.
from rich.markup import escape
console.print(f"[red]Error:[/red] {escape(str(exc))}")
@agent.command("create")
+21
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
from unittest.mock import patch
from click.testing import CliRunner
from openjarvis.cli import cli
@@ -12,6 +14,25 @@ class TestAgentCmd:
result = CliRunner().invoke(cli, ["agents", "list", "--help"])
assert result.exit_code == 0
def test_agent_list_error_with_markup_chars_does_not_crash(self) -> None:
"""Regression for #297.
When ``_get_manager()`` (or anything in the body) raises an
exception whose message contains Rich markup metacharacters like
``[...]``, the error handler must not re-parse that text as markup
and blow up with a secondary MarkupError traceback. The command
should print a clean one-line error instead.
"""
# A message with bracketed text is what triggers the MarkupError
# when fed to console.print() unescaped.
boom = RuntimeError("DB locked at [/var/run/x] not a [valid] tag")
with patch("openjarvis.cli.agent_cmd._get_manager", side_effect=boom):
result = CliRunner().invoke(cli, ["agents", "list"])
# No traceback / unhandled exception leaked through.
assert result.exception is None, result.output
# The raw message (brackets intact) is surfaced to the user.
assert "DB locked at [/var/run/x] not a [valid] tag" in result.output
def test_agent_info_help(self) -> None:
result = CliRunner().invoke(cli, ["agents", "info", "--help"])
assert result.exit_code == 0