{"repo":"NousResearch/hermes-agent","public_id":"19514","display_label":"Packaged installs failing to locate bundled TUI assets","summary":"Most members concern the TUI (--tui / Chat tab) on packaged installs such as pip, pipx, and Homebrew, where a ui-tui workspace check or missing runtime assets in the package is reported alongside proposed changes to try the bundled TUI first, adjust manifests, or give clearer messages. One bug report (a bare FileNotFoundError) has too little detail to confirm it belongs to this theme.","subsystem":"dashboard","counts":{"members":16,"open_issues":0,"open_issues_distinct":0,"open_prs":1,"closed_issues":5,"merged_prs":1,"attempt_prs":10},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":67116,"merged_at":"2026-07-18T21:17:25+00:00"},"resolution":{"state":"partially_resolved","by":"pr-67116"},"freshness":{"state":"verified","last_verified_at":"2026-07-18T21:17:25+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.10666666666666665},"fix_edges":[{"issue_number":56665,"pr_number":67116,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-07-18T21:17:25+00:00"}],"members":[{"kind":"issue","number":19514,"title":"[Bug]: MANIFEST.in missing ui-tui/ and scripts/ — hermes --tui crashes after pip install","url":null,"state":"closed"},{"kind":"issue","number":24544,"title":"[Bug]: Homebrew / packaged installs advertise --tui but crash because ui-tui is not included in the installed package","url":null,"state":"closed"},{"kind":"issue","number":30957,"title":"[Bug]: FileNotFoundError:  No such file or directory:","url":null,"state":"closed"},{"kind":"issue","number":56665,"title":"Chat tab fails with \"Chat unavailable: 1\" on pip/pipx install — ui-tui workspace check runs before bundled-wheel fallback","url":null,"state":"closed"},{"kind":"issue","number":57031,"title":"[Bug]: Installs from homebrew / linuxbrew cannot run TUI","url":null,"state":"closed"},{"kind":"pr","number":19525,"title":"fix(package): include TUI runtime assets in manifest","url":null,"state":"open","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false},{"kind":"pr","number":19995,"title":"fix(packaging): include TUI runtime assets","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"3215ef160938c71ff61bab279b30545c0cc14a14","number":0},{"kind":"commit","value":"b2bf658442f413a9a1d24b011589e5e38544947e","number":0},{"kind":"pr","value":"#19514","number":19514},{"kind":"pr","value":"#19525","number":19525}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":24646,"title":"fix(cli): exit with clear message when ui-tui/ is missing in packaged installs","url":null,"state":"closed","close_reason":{"category":"uncategorized","implication":"needs_llm"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":56669,"title":"fix(cli): check bundled TUI before workspace validation for pip/pipx installs","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#56672","number":56672}],"category":"superseded_by_pr","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":56672,"title":"fix(cli): try bundled TUI before requiring ui-tui workspace","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#67116","number":67116},{"kind":"pr","value":"#56665","number":56665}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":56855,"title":"fix(dashboard): prefer bundled TUI for wheel chat","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#56672","number":56672}],"category":"superseded_by_pr","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":57047,"title":"fix(cli): skip TUI workspace check for managed installs (Homebrew/NixOS)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#57031","number":57031}],"category":"wontfix_bydesign","implication":"wontfix"},"merged":false},{"kind":"pr","number":57064,"title":"fix(tui): prefer bundled TUI on packaged installs; give install-method-specific recovery (#57031)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#57031","number":57031}],"category":"wontfix_bydesign","implication":"wontfix"},"merged":false},{"kind":"pr","number":57087,"title":"fix(tui): prefer bundled dist before workspace check","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#57031","number":57031}],"category":"wontfix_bydesign","implication":"wontfix"},"merged":false},{"kind":"pr","number":57136,"title":"fix(cli): skip TUI workspace check when bundled TUI exists (#57031)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#57031","number":57031}],"category":"wontfix_bydesign","implication":"wontfix"},"merged":false},{"kind":"pr","number":67116,"title":"fix(cli): try bundled TUI before requiring ui-tui workspace","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["contributors/emails/[redacted:email]","hermes_cli/main.py","tests/hermes_cli/test_tui_npm_install.py"],"fix_hunks":[{"file":"contributors/emails/[redacted:email]","hunks":["@@ -0,0 +1,2 @@\n+lucaskvasirr\n+# PR #56672 salvage (fix(cli): try bundled TUI before requiring ui-tui workspace; #56665)"]},{"file":"hermes_cli/main.py","hunks":["@@ -1766,10 +1766,14 @@ def _node_bin(bin: str) -> str:\n         )\n         sys.exit(1)\n \n-    if not ext_dir:\n-        _ensure_tui_workspace(tui_dir)\n-\n     # 1. Prebuilt bundle (nix / packaged release): just run it.\n+    #\n+    # This must run BEFORE _ensure_tui_workspace() below. A pip/pipx install\n+    # ships hermes_cli/tui_dist/entry.js in the wheel but never ships ui-tui/\n+    # at all (that directory only exists in a git checkout) — so requiring\n+    # the workspace to exist first made every pip/pipx dashboard Chat tab\n+    # connection hard-exit before it ever got a chance to try the bundled\n+    # entry.js it already has. See #56665.\n     if not tui_dev:\n         if ext_dir:\n             p = Path(ext_dir)","@@ -1783,6 +1787,11 @@ def _node_bin(bin: str) -> str:\n             node = _node_bin(\"node\")\n             return [node, \"--expose-gc\", str(bundled)], bundled.parent\n \n+    # No prebuilt bundle available (or --dev, which never uses one) — we're\n+    # about to npm install/build from source, so the workspace must exist.\n+    if not ext_dir:\n+        _ensure_tui_workspace(tui_dir)\n+\n     # 2. Normal flow: npm install if needed, always esbuild, then node dist/entry.js.\n     #    --dev flow: npm install if needed, then tsx src/entry.tsx.\n     #    Existing desktop behaviour runs npm from the workspace root.  Termux"]},{"file":"tests/hermes_cli/test_tui_npm_install.py","hunks":["@@ -361,6 +361,79 @@ def fake_run(*args, **kwargs):\n     _assert_utf8_replace_capture(calls[0][1])\n \n \n+def test_make_tui_argv_uses_bundled_tui_when_workspace_missing(\n+    tmp_path: Path, main_mod, monkeypatch\n+) -> None:\n+    \"\"\"pip/pipx install regression (#56665): the wheel ships\n+    hermes_cli/tui_dist/entry.js but never ships ui-tui/ (that directory only\n+    exists in a git checkout). Before this fix, _make_tui_argv called\n+    _ensure_tui_workspace() unconditionally before checking for the bundled\n+    entry.js, so every pip/pipx dashboard Chat tab connection hard-exited\n+    with `sys.exit(1)` — surfaced to the user as the unhelpful \"Chat\n+    unavailable: 1\" — despite having a perfectly runnable bundled TUI on\n+    disk. The bundled-wheel shortcut must be tried first and succeed without\n+    ever touching the (missing) ui-tui workspace or git.\n+    \"\"\"\n+    monkeypatch.delenv(\"HERMES_TUI_DIR\", raising=False)\n+    monkeypatch.setattr(main_mod, \"_ensure_tui_node\", lambda: None)\n+\n+    bundled_entry = tmp_path / \"bundled\" / \"entry.js\"\n+    bundled_entry.parent.mkdir(parents=True)\n+    bundled_entry.write_text(\"// bundled TUI\")\n+    monkeypatch.setattr(main_mod, \"_find_bundled_tui\", lambda: bundled_entry)\n+\n+    def which(name: str) -> str | None:\n+        if name == \"node\":\n+            return \"/usr/bin/node\"\n+        raise AssertionError(f\"unexpected shutil.which({name!r}) call — bundled path must not need npm/git\")\n+\n+    monkeypatch.setattr(main_mod.shutil, \"which\", which)\n+\n+    def fail_run(*_args, **_kwargs):\n+        raise AssertionError(\"bundled TUI path must not spawn any subprocess (no npm install/build, no git restore)\")\n+\n+    monkeypatch.setattr(main_mod.subprocess, \"run\", fail_run)\n+\n+    # ui-tui/ deliberately does not exist under tmp_path, and there is no\n+    # .git either — this mirrors a pip/pipx install exactly.\n+    tui_dir = tmp_path / \"ui-tui\"\n+    assert not tui_dir.exists()\n+\n+    argv, cwd = main_mod._make_tui_argv(tui_dir, tui_dev=False)\n+\n+    assert argv == [\"/usr/bin/node\", \"--expose-gc\", str(bundled_entry)]\n+    assert cwd == bundled_entry.parent\n+\n+\n+def test_make_tui_argv_dev_mode_still_requires_workspace_even_with_bundle(\n+    tmp_path: Path, main_mod, monkeypatch, capsys\n+) -> None:\n+    \"\"\"--dev never uses the prebuilt bundle (there's no source to hot-reload\n+    from a bundled entry.js), so it must still hit the workspace guard when\n+    ui-tui/ is missing — the bundled-first reordering must not weaken --dev.\n+    \"\"\"\n+    monkeypatch.delenv(\"HERMES_TUI_DIR\", raising=False)\n+    monkeypatch.setattr(main_mod, \"_ensure_tui_node\", lambda: None)\n+\n+    bundled_entry = tmp_path / \"bundled\" / \"entry.js\"\n+    bundled_entry.parent.mkdir(parents=True)\n+    bundled_entry.write_text(\"// bundled TUI\")\n+    monkeypatch.setattr(main_mod, \"_find_bundled_tui\", lambda: bundled_entry)\n+\n+    def which(name: str) -> str | None:\n+        if name == \"git\":\n+            return \"/usr/bin/git\"\n+        raise AssertionError(\"node/npm lookup must not run when ui-tui is missing\")\n+\n+    monkeypatch.setattr(main_mod.shutil, \"which\", which)\n+\n+    with pytest.raises(SystemExit) as exc:\n+        main_mod._make_tui_argv(tmp_path / \"ui-tui\", tui_dev=True)\n+\n+    assert exc.value.code == 1\n+    assert \"TUI workspace is missing\" in capsys.readouterr().err\n+\n+\n def test_make_tui_argv_exits_with_recovery_hint_when_workspace_unrecoverable(\n     tmp_path: Path, main_mod, monkeypatch, capsys\n ) -> None:\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}