From e7d7e0157f9638d686af525384f4f018210e458f Mon Sep 17 00:00:00 2001 From: alt-glitch Date: Mon, 8 Jun 2026 16:27:21 +0000 Subject: [PATCH] =?UTF-8?q?feat(opentui-v2):=20Phase=208=20=E2=80=94=20lau?= =?UTF-8?q?ncher=20cutover=20to=20the=20v4=20Solid=20engine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repoint hermes_cli/main.py `_make_opentui_argv` from the superseded React entry to the v4 Solid + Effect-at-boundary entry: it now prefers `ui-tui-opentui-v2/src/entry/main.tsx` (cwd ui-tui-opentui-v2) and falls back to `ui-tui-opentui/src/entry.real.tsx` only if the v2 package is absent (graceful during coexistence). The engine gate (_resolve_tui_engine: HERMES_TUI_ENGINE / display.tui_engine → opentui; Windows/Termux → Ink fallback) and the dual-engine dispatch in _make_tui_argv are unchanged; Ink (ui-tui/) is untouched. The spawned tui_gateway's source-root default lands on PROJECT_ROOT (package at /ui-tui-opentui-v2), so it loads Python from the same checkout, no extra env. So `HERMES_TUI_ENGINE=opentui hermes --tui` now launches the v4 engine — the exact `bun …/v2/src/entry/main.tsx` invocation live-smoked across P1–P5e, making every first-class surface reachable from the real CLI. Also: a consolidated 3-way acceptance summary (Ink ↔ opencode ↔ build) at the top of opentui-feature-map.md covering all 7 first-class surfaces + the foundation + the launcher, each ✅ + tested + smoked. Verified: py_compile main.py OK (dev-skill rule for the 4k-line file); imported the worktree CLI with HERMES_TUI_ENGINE=opentui → _resolve_tui_engine()='opentui', _make_opentui_argv() → [bun, …/ui-tui-opentui-v2/src/entry/main.tsx] (cwd ui-tui-opentui-v2, --watch in dev). v2 `bun run check` green (53 tests / 7 files). Smoke P8 + matrix updated. Remaining: header chrome detail (5b), agent-feature trail (5d), distribution (§10) — polish, not first-class blockers. --- hermes_cli/main.py | 49 +++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 68c310bb97e..ff47810c35d 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1611,26 +1611,39 @@ def _bun_bin() -> str: def _make_opentui_argv(tui_dev: bool) -> tuple[list[str], Path]: - """Argv for the native OpenTUI engine: ``bun src/entry.real.tsx``. + """Argv for the native OpenTUI engine (Bun runs the TypeScript entry directly). - No build step — Bun runs the TypeScript entry directly. Returns the argv and - the ``ui-tui-opentui/`` cwd. ``tui_dev`` adds ``--watch`` for hot reload. + Prefers the v4 Solid + Effect-at-boundary engine + (``ui-tui-opentui-v2/src/entry/main.tsx``); falls back to the superseded React + build (``ui-tui-opentui/src/entry.real.tsx``) if the v2 package isn't present. + Returns the argv and the package cwd. ``tui_dev`` adds ``--watch`` for hot reload. + + The spawned ``tui_gateway`` resolves its Python from this checkout + (``HERMES_PYTHON_SRC_ROOT`` env → ``/.venv`` …); since the package lives at + ``/ui-tui-opentui-v2`` the gateway's default source-root resolution lands on + ``PROJECT_ROOT`` without extra plumbing. """ - app_dir = PROJECT_ROOT / "ui-tui-opentui" - entry = app_dir / "src" / "entry.real.tsx" - if not entry.is_file(): - print( - f"OpenTUI engine entry not found at {entry}.\n" - f"Unset HERMES_TUI_ENGINE to use the default Ink engine.", - file=sys.stderr, - ) - sys.exit(1) - bun = _bun_bin() - args = [bun] - if tui_dev: - args.append("--watch") - args.append(str(entry)) - return args, app_dir + candidates = ( + (PROJECT_ROOT / "ui-tui-opentui-v2", Path("src") / "entry" / "main.tsx"), + (PROJECT_ROOT / "ui-tui-opentui", Path("src") / "entry.real.tsx"), + ) + for app_dir, rel in candidates: + entry = app_dir / rel + if entry.is_file(): + bun = _bun_bin() + args = [bun] + if tui_dev: + args.append("--watch") + args.append(str(entry)) + return args, app_dir + + tried = ", ".join(str(app_dir / rel) for app_dir, rel in candidates) + print( + f"OpenTUI engine entry not found (tried: {tried}).\n" + f"Unset HERMES_TUI_ENGINE to use the default Ink engine.", + file=sys.stderr, + ) + sys.exit(1) def _make_tui_argv(tui_dir: Path, tui_dev: bool) -> tuple[list[str], Path]: