fix(tui): rebuild when Ink bundle is missing

This commit is contained in:
Brooklyn Nicholson
2026-04-25 12:41:57 -05:00
parent 648b89911f
commit d603bce4cb
2 changed files with 43 additions and 3 deletions

View File

@@ -826,14 +826,26 @@ def _tui_need_npm_install(root: Path) -> bool:
return lock.stat().st_mtime > marker.stat().st_mtime return lock.stat().st_mtime > marker.stat().st_mtime
def _tui_ink_bundle_exists(root: Path) -> bool:
return (root / "node_modules" / "@hermes" / "ink" / "dist" / "ink-bundle.js").is_file()
def _tui_runtime_ready(root: Path) -> bool:
return (
(root / "dist" / "entry.js").exists()
and not _tui_need_npm_install(root)
and _tui_ink_bundle_exists(root)
)
def _find_bundled_tui(tui_dir: Path) -> Optional[Path]: def _find_bundled_tui(tui_dir: Path) -> Optional[Path]:
"""Directory whose dist/entry.js we should run: HERMES_TUI_DIR first, else repo ui-tui.""" """Directory whose dist/entry.js we should run: HERMES_TUI_DIR first, else repo ui-tui."""
env = os.environ.get("HERMES_TUI_DIR") env = os.environ.get("HERMES_TUI_DIR")
if env: if env:
p = Path(env) p = Path(env)
if (p / "dist" / "entry.js").exists() and not _tui_need_npm_install(p): if _tui_runtime_ready(p):
return p return p
if (tui_dir / "dist" / "entry.js").exists() and not _tui_need_npm_install(tui_dir): if _tui_runtime_ready(tui_dir):
return tui_dir return tui_dir
return None return None
@@ -842,6 +854,8 @@ def _tui_build_needed(tui_dir: Path) -> bool:
entry = tui_dir / "dist" / "entry.js" entry = tui_dir / "dist" / "entry.js"
if not entry.exists(): if not entry.exists():
return True return True
if _hermes_ink_bundle_stale(tui_dir):
return True
dist_m = entry.stat().st_mtime dist_m = entry.stat().st_mtime
skip = frozenset({"node_modules", "dist"}) skip = frozenset({"node_modules", "dist"})
for dirpath, dirnames, filenames in os.walk(tui_dir, topdown=True): for dirpath, dirnames, filenames in os.walk(tui_dir, topdown=True):
@@ -958,7 +972,7 @@ def _make_tui_argv(tui_dir: Path, tui_dev: bool) -> tuple[list[str], Path]:
ext_dir = os.environ.get("HERMES_TUI_DIR") ext_dir = os.environ.get("HERMES_TUI_DIR")
if ext_dir: if ext_dir:
p = Path(ext_dir) p = Path(ext_dir)
if (p / "dist" / "entry.js").exists() and not _tui_need_npm_install(p): if _tui_runtime_ready(p):
node = _node_bin("node") node = _node_bin("node")
return [node, str(p / "dist" / "entry.js")], p return [node, str(p / "dist" / "entry.js")], p

View File

@@ -19,6 +19,18 @@ def _touch_ink(root: Path) -> None:
ink.write_text("{}") ink.write_text("{}")
def _touch_entry(root: Path) -> None:
entry = root / "dist" / "entry.js"
entry.parent.mkdir(parents=True, exist_ok=True)
entry.write_text("")
def _touch_bundle(root: Path) -> None:
bundle = root / "node_modules" / "@hermes" / "ink" / "dist" / "ink-bundle.js"
bundle.parent.mkdir(parents=True, exist_ok=True)
bundle.write_text("")
def test_need_install_when_ink_missing(tmp_path: Path, main_mod) -> None: def test_need_install_when_ink_missing(tmp_path: Path, main_mod) -> None:
(tmp_path / "package-lock.json").write_text("{}") (tmp_path / "package-lock.json").write_text("{}")
assert main_mod._tui_need_npm_install(tmp_path) is True assert main_mod._tui_need_npm_install(tmp_path) is True
@@ -51,3 +63,17 @@ def test_need_install_when_marker_missing(tmp_path: Path, main_mod) -> None:
def test_no_install_without_lockfile_when_ink_present(tmp_path: Path, main_mod) -> None: def test_no_install_without_lockfile_when_ink_present(tmp_path: Path, main_mod) -> None:
_touch_ink(tmp_path) _touch_ink(tmp_path)
assert main_mod._tui_need_npm_install(tmp_path) is False assert main_mod._tui_need_npm_install(tmp_path) is False
def test_build_needed_when_ink_bundle_missing(tmp_path: Path, main_mod) -> None:
_touch_entry(tmp_path)
assert main_mod._tui_build_needed(tmp_path) is True
def test_find_bundled_tui_requires_ink_bundle(tmp_path: Path, main_mod) -> None:
_touch_entry(tmp_path)
_touch_ink(tmp_path)
assert main_mod._find_bundled_tui(tmp_path) is None
_touch_bundle(tmp_path)
assert main_mod._find_bundled_tui(tmp_path) == tmp_path