opentui(phase3): launcher integration — HERMES_TUI_ENGINE dual-engine

hermes --tui launches the native OpenTUI engine (Bun) when
HERMES_TUI_ENGINE=opentui (env) or display.tui_engine=opentui (config);
Ink stays the default and the shipping path is untouched.

- _resolve_tui_engine() (env > config > ink); refuses opentui on
  Windows/Termux (no Bun) -> falls back to ink with a notice.
- _make_opentui_argv() -> [bun, src/entry.real.tsx] (no build step).
- _bun_bin() with HERMES_BUN override.
- Branch at top of _make_tui_argv BEFORE _ensure_tui_node (Bun-only host
  must not bootstrap Node).
- Gate _launch_tui NODE_OPTIONS/--max-old-space-size on engine==ink (Bun
  is JSC; the V8 flag errors/ignores).

Verified end-to-end via tmux: real hermes --tui -> Bun -> OpenTUI ->
real Python gateway streamed a real reply. No-flag default still ink.
This commit is contained in:
alt-glitch
2026-06-08 11:11:54 +00:00
parent 24f74eb888
commit 2bd9c9b881
741 changed files with 17733 additions and 79889 deletions
+1 -65
View File
@@ -11,7 +11,6 @@ import subprocess
import threading
import time
from pathlib import Path
from urllib.parse import urlparse
from hermes_constants import get_hermes_home
from typing import TYPE_CHECKING, Dict, List, Optional
@@ -122,53 +121,6 @@ _UPDATE_CHECK_CACHE_SECONDS = 6 * 3600
UPDATE_AVAILABLE_NO_COUNT = -1
_UPSTREAM_REPO_URL = "https://github.com/NousResearch/hermes-agent.git"
_OFFICIAL_REPO_CANONICAL = "github.com/nousresearch/hermes-agent"
def _canonical_github_remote(url: str | None) -> str:
"""Return ``host/owner/repo`` for common GitHub remote URL forms."""
if not url:
return ""
value = url.strip()
if value.startswith("git@github.com:"):
value = "github.com/" + value[len("git@github.com:"):]
elif value.startswith("ssh://git@github.com/"):
value = "github.com/" + value[len("ssh://git@github.com/"):]
else:
parsed = urlparse(value)
if parsed.netloc and parsed.path:
value = f"{parsed.netloc}{parsed.path}"
value = value.strip().rstrip("/")
if value.endswith(".git"):
value = value[:-4]
return value.lower()
def _is_ssh_remote(url: str | None) -> bool:
if not url:
return False
value = url.strip().lower()
return value.startswith("git@") or value.startswith("ssh://")
def _is_official_ssh_remote(url: str | None) -> bool:
return _is_ssh_remote(url) and _canonical_github_remote(url) == _OFFICIAL_REPO_CANONICAL
def _git_stdout(args: list[str], *, cwd: Path, timeout: int = 5) -> Optional[str]:
try:
result = subprocess.run(
["git", *args],
capture_output=True,
text=True,
timeout=timeout,
cwd=str(cwd),
)
except Exception:
return None
if result.returncode != 0:
return None
return (result.stdout or "").strip()
def _check_via_rev(local_rev: str) -> Optional[int]:
@@ -194,11 +146,6 @@ def _check_via_rev(local_rev: str) -> Optional[int]:
def _check_via_local_git(repo_dir: Path) -> Optional[int]:
"""Count commits behind origin/main in a local checkout."""
origin_url = _git_stdout(["remote", "get-url", "origin"], cwd=repo_dir)
if _is_official_ssh_remote(origin_url):
head_rev = _git_stdout(["rev-parse", "HEAD"], cwd=repo_dir)
return _check_via_rev(head_rev) if head_rev else None
try:
subprocess.run(
["git", "fetch", "origin", "--quiet"],
@@ -693,27 +640,16 @@ def build_welcome_banner(console: "Console", model: str, cwd: str,
right_lines.append("")
right_lines.append(f"[bold {accent}]MCP Servers[/]")
for srv in mcp_status:
status = srv.get("status")
if srv["connected"]:
right_lines.append(
f"[dim {dim}]{srv['name']}[/] [{text}]({srv['transport']})[/] "
f"[dim {dim}]—[/] [{text}]{srv['tools']} tool(s)[/]"
)
elif srv.get("disabled") or status == "disabled":
elif srv.get("disabled"):
right_lines.append(
f"[dim {dim}]{srv['name']}[/] [dim]({srv['transport']})[/] "
f"[dim {dim}]— disabled[/]"
)
elif status == "connecting":
right_lines.append(
f"[dim {dim}]{srv['name']}[/] [dim]({srv['transport']})[/] "
f"[yellow]— connecting[/]"
)
elif status == "configured":
right_lines.append(
f"[dim {dim}]{srv['name']}[/] [dim]({srv['transport']})[/] "
f"[dim {dim}]— configured[/]"
)
else:
right_lines.append(
f"[red]{srv['name']}[/] [dim]({srv['transport']})[/] "