Merge origin/main into bb/gui

Adopt main's web/ dashboard layout (apps/dashboard removed; web/ restored),
keep bb/gui's desktop CLI/update workspace handling, and preserve main's
mTLS/URL validation MCP changes. Dashboard backend is aligned to main with
only the intended STT provider quarantine/ElevenLabs override reapplied.
This commit is contained in:
Brooklyn Nicholson
2026-05-29 20:40:08 -05:00
1205 changed files with 39074 additions and 9768 deletions
+37 -24
View File
@@ -133,11 +133,10 @@ class TestCmdUpdateBranchFallback:
captured = capsys.readouterr()
assert "Already up to date!" in captured.out
@patch("hermes_cli.main._web_ui_build_needed", return_value=True)
@patch("shutil.which")
@patch("subprocess.run")
def test_update_refreshes_repo_and_tui_node_dependencies(
self, mock_run, mock_which, _mock_web_ui_build_needed, mock_args
self, mock_run, mock_which, mock_args
):
from hermes_cli import main as hm
@@ -145,7 +144,13 @@ class TestCmdUpdateBranchFallback:
mock_run.side_effect = _make_run_side_effect(
branch="main", verify_ok=True, commit_count="1"
)
with patch.object(hm, "_is_termux_env", return_value=False):
# The web UI build runs through _run_with_idle_timeout now (issue
# #33788) so it no longer appears in subprocess.run's call list.
# Mock it so the test doesn't actually shell out to ``tsc``.
import subprocess as _subprocess
build_ok = _subprocess.CompletedProcess([], 0, stdout="", stderr="")
with patch.object(hm, "_is_termux_env", return_value=False), \
patch.object(hm, "_run_with_idle_timeout", return_value=build_ok) as mock_idle:
cmd_update(mock_args)
npm_calls = [
@@ -154,35 +159,43 @@ class TestCmdUpdateBranchFallback:
if call.args and call.args[0][0] == "/usr/bin/npm"
]
# cmd_update runs npm commands in three locations:
# 1. repo root — slash-command / TUI bridge deps
# 2. ui-tui/ — Ink TUI deps
# 3. apps/dashboard/ — install + "npm run build" for the web frontend
full_flags = [
# cmd_update runs npm commands in four locations:
# 1. repo root — slash-command / TUI bridge deps (subprocess.run)
# 2. ui-tui/ — Ink TUI deps (subprocess.run)
# 3. web/ — npm install (subprocess.run)
# 4. web/ — npm run build (_run_with_idle_timeout)
#
# Repo-root and ui-tui installs intentionally omit `--silent` and run
# without `capture_output` so optional postinstall scripts (e.g.
# `@askjo/camofox-browser`'s browser-binary fetch) print progress —
# otherwise long downloads look like a hang (#18840). The web/ install
# keeps `--silent` because its build step is short and noisy.
update_flags = [
"/usr/bin/npm",
"ci",
"--silent",
"--no-fund",
"--no-audit",
"--progress=false",
"--workspaces=false",
]
app_flags = [
"/usr/bin/npm",
"ci",
"--silent",
"--no-fund",
"--no-audit",
"--progress=false",
]
# Repo root additionally passes --workspaces=false so npm does not
# recursively install every apps/* workspace (desktop, shared).
repo_flags = [*update_flags, "--workspaces=false"]
assert npm_calls[:2] == [
(full_flags, PROJECT_ROOT),
(app_flags, PROJECT_ROOT / "ui-tui"),
]
assert npm_calls[2:] == [
(["/usr/bin/npm", "ci", "--silent"], PROJECT_ROOT / "apps" / "dashboard"),
(["/usr/bin/npm", "run", "build"], PROJECT_ROOT / "apps" / "dashboard"),
(repo_flags, PROJECT_ROOT),
(update_flags, PROJECT_ROOT / "ui-tui"),
]
if len(npm_calls) > 2:
# Only the web/ install is left in subprocess.run; the build moved
# to _run_with_idle_timeout to make Vite progress visible (#33788).
assert npm_calls[2:] == [
(["/usr/bin/npm", "ci", "--silent"], PROJECT_ROOT / "web"),
]
# The web UI build itself went through the streaming helper.
mock_idle.assert_called_once()
idle_args, idle_kwargs = mock_idle.call_args
assert idle_args[0] == ["/usr/bin/npm", "run", "build"]
assert idle_kwargs["cwd"] == PROJECT_ROOT / "web"
# Regression for #18840: repo root + ui-tui installs must stream
# output (capture_output=False) so postinstall progress is visible