feat(tui): add native terminal mode defaults

This commit is contained in:
brooklyn!
2026-09-23 23:38:21 -05:00
parent 9d81deb0f3
commit 93f7617406
5 changed files with 33 additions and 3 deletions

View File

@@ -205,6 +205,8 @@ def _add_top_level_flags(parser: argparse.ArgumentParser) -> None:
help="Troubleshooting mode: disable ALL customizations — user config, AGENTS.md/memory injection, plugins, and MCP servers (implies --ignore-user-config and --ignore-rules)")
inherited(parser, "--tui", action="store_true", default=False,
help="Launch the modern TUI instead of the classic REPL")
inherited(parser, "--native", "--tui-native", dest="tui_native", action="store_true", default=False,
help="With --tui: use native terminal scrollback and disable mouse tracking")
inherited(parser, "--cli", action="store_true", default=False,
help="Force the classic prompt_toolkit REPL (overrides display.interface=tui)")
inherited(parser, "--dev", dest="tui_dev", action="store_true", default=False,
@@ -308,6 +310,8 @@ def _build_chat_parser(subparsers) -> argparse.ArgumentParser:
help="Session source tag for filtering (default: cli). Use 'tool' for third-party integrations that should not appear in user session lists.")
inherited(chat_parser, "--tui", action="store_true", default=SUPPRESS,
help="Launch the modern TUI instead of the classic REPL")
inherited(chat_parser, "--native", "--tui-native", dest="tui_native", action="store_true", default=SUPPRESS,
help="Use native terminal scrollback and disable mouse tracking")
inherited(chat_parser, "--cli", action="store_true", default=SUPPRESS,
help="Force the classic prompt_toolkit REPL (overrides display.interface=tui)")
inherited(chat_parser, "--dev", dest="tui_dev", action="store_true", default=SUPPRESS,

View File

@@ -816,6 +816,9 @@ DEFAULT_CONFIG = {
# Interface bare `hermes`/`hermes chat` launches: "cli" (prompt_toolkit REPL) | "tui" (Ink).
# Flags win: `--cli` forces the REPL, `--tui` / HERMES_TUI=1 forces the TUI.
"interface": "cli",
# Native TUI uses the terminal's primary buffer and scrollback instead of the custom
# alternate-screen viewport. Flags win: `--native` / `--tui-native` and `--cli`.
"tui_native": False,
# `hermes --tui` auto-resumes the most recent human-facing session (like `hermes -c`).
# HERMES_TUI_RESUME=<id> always wins.
"tui_auto_resume_recent": False,

View File

@@ -289,7 +289,7 @@ def _wants_tui_early(argv: "list[str] | None" = None) -> bool:
argv = sys.argv[1:]
if "--cli" in argv:
return False
if os.environ.get("HERMES_TUI") == "1" or "--tui" in argv:
if os.environ.get("HERMES_TUI") == "1" or any(flag in argv for flag in ("--tui", "--native", "--tui-native")):
return True
try:
if not (sys.stdin.isatty() and sys.stdout.isatty()):
@@ -1841,6 +1841,7 @@ def cmd_chat(args):
_launch_tui(
passthrough.pop("resume"),
tui_dev=getattr(args, "tui_dev", False),
native_mode=True if getattr(args, "tui_native", False) else None,
model=getattr(args, "model", None),
accept_hooks=getattr(args, "accept_hooks", False),
**passthrough,

View File

@@ -343,7 +343,8 @@ def _setup_tui_worktree() -> dict:
def _launch_tui(
resume_session_id: Optional[str] = None, tui_dev: bool = False, model: Optional[str] = None,
resume_session_id: Optional[str] = None, tui_dev: bool = False, native_mode: Optional[bool] = None,
model: Optional[str] = None,
provider: Optional[str] = None, toolsets: object = None, skills: object = None,
verbose: Optional[bool] = None, quiet: bool = False, query: Optional[str] = None,
image: Optional[str] = None, worktree: bool = False, checkpoints: bool = False,
@@ -373,6 +374,15 @@ def _launch_tui(
os.close(active_session_fd)
env["HERMES_TUI_ACTIVE_SESSION_FILE"] = active_session_file
env.setdefault("NODE_ENV", "development" if tui_dev else "production")
if native_mode is None:
try:
from hermes_cli.config import load_config
from utils import is_truthy_value
display = load_config().get("display", {})
native_mode = is_truthy_value(display.get("tui_native", False)) if isinstance(display, dict) else False
except Exception:
native_mode = False
env["HERMES_TUI_NATIVE"] = "1" if native_mode else "0"
wt_info = None
if worktree:
@@ -479,7 +489,7 @@ def _resolve_use_tui(args) -> bool:
"""
if getattr(args, "cli", False):
return False
if getattr(args, "tui", False):
if getattr(args, "tui", False) or getattr(args, "tui_native", False):
return True
try:
if not (sys.stdin.isatty() and sys.stdout.isatty()):

View File

@@ -169,6 +169,11 @@ class TestParserFlags:
args = self._parser().parse_args(["chat", "--tui"])
assert args.tui is True
def test_native_flag_at_both_parser_levels(self):
parser = self._parser()
assert parser.parse_args(["--native"]).tui_native is True
assert parser.parse_args(["chat", "--tui-native"]).tui_native is True
def test_cli_and_tui_are_relaunch_inherited(self):
from hermes_cli.relaunch import _INHERITED_FLAGS_TABLE
@@ -176,6 +181,13 @@ class TestParserFlags:
assert "--cli" in inherited
assert "--tui" in inherited
def test_native_flag_is_relaunch_inherited(self):
from hermes_cli.relaunch import _INHERITED_FLAGS_TABLE
inherited = {flag for flag, _takes_value in _INHERITED_FLAGS_TABLE}
assert "--native" in inherited
assert "--tui-native" in inherited
# ---------------------------------------------------------------------------
# config default — shipped default preserves classic behavior