Skip to content

fix(web): build web UI with NODE_ENV=development so devDependencies install#17906

Open
OnTheDotMediaLtd wants to merge 1 commit into
NousResearch:mainfrom
OnTheDotMediaLtd:fix/web-build-node-env
Open

fix(web): build web UI with NODE_ENV=development so devDependencies install#17906
OnTheDotMediaLtd wants to merge 1 commit into
NousResearch:mainfrom
OnTheDotMediaLtd:fix/web-build-node-env

Conversation

@OnTheDotMediaLtd

Copy link
Copy Markdown

Summary

hermes update (and any path that calls _build_web_ui) silently fails to
build the web UI when NODE_ENV=production is in the environment. The build
prints ⚠ Web UI build failed (hermes web will not be available) while the
rest of the update reports success, so users only notice when hermes web
serves a stale or missing bundle. This PR forces NODE_ENV=development for
the npm install + build child processes inside _build_web_ui and threads an
explicit env= kwarg through _run_npm_install_deterministic so npm ci
and the npm install fallback both honor it.

Root cause

  • hermes_cli/main.py:1150 (_launch_tui) sets NODE_ENV=production on the
    node TUI subprocess.
  • Every shell, slash-command and hermes update spawned under the TUI
    inherits it, verified by walking /proc/<pid>/environ up the parent chain.
  • NODE_ENV is not in ~/.bashrc, ~/.zshrc, ~/.profile,
    /etc/environment, or any /etc/profile.d script — the TUI is the sole
    source on a fresh install. With NODE_ENV=production set, npm install
    on npm ≥ 9 skips devDependencies, so typescript is missing and
    tsc -b && vite build fails with sh: 1: tsc: not found.

Diff

diff --git a/hermes_cli/main.py b/hermes_cli/main.py
@@ def _run_npm_install_deterministic(
     *,
     extra_args: tuple[str, ...] = (),
     capture_output: bool = True,
+    env: dict | None = None,
 ) -> subprocess.CompletedProcess:
     ...
         ci_result = subprocess.run(
             ci_cmd, cwd=cwd, capture_output=capture_output,
-            text=True, check=False,
+            text=True, check=False, env=env,
         )
     ...
     return subprocess.run(
         install_cmd, cwd=cwd, capture_output=capture_output,
-        text=True, check=False,
+        text=True, check=False, env=env,
     )

@@ def _build_web_ui(web_dir: Path, *, fatal: bool = False) -> bool:
     print("→ Building web UI...")
-    r1 = _run_npm_install_deterministic(npm, web_dir, extra_args=("--silent",))
+    # Force devDependencies to install regardless of inherited NODE_ENV.
+    # The bundled TUI launcher sets NODE_ENV=production on its node
+    # subprocess (see _launch_tui), and many CI/deploy shells set
+    # NODE_ENV=production system-wide. npm >= 9 honors that and skips
+    # devDependencies, which causes `tsc -b && vite build` to fail with
+    # "tsc: not found". Override at the build site so the install is
+    # robust to caller env.
+    build_env = {**os.environ, "NODE_ENV": "development"}
+    r1 = _run_npm_install_deterministic(
+        npm, web_dir, extra_args=("--silent",), env=build_env
+    )
     ...
-    r2 = subprocess.run([npm, "run", "build"], cwd=web_dir, capture_output=True)
+    r2 = subprocess.run([npm, "run", "build"], cwd=web_dir, capture_output=True, env=build_env)

Impact

Affects any user running the bundled web-UI build path with
NODE_ENV=production set — in practice, anyone running hermes update from
inside the Hermes TUI (the default workflow), CI/CD pipelines, and Docker
images that adopt the NODE_ENV=production convention. The failure is
silent in the non-fatal branch, so installs that look successful can ship
with a stale hermes_cli/web_dist/.

Verification

With NODE_ENV=production exported and a wiped node_modules /
web_dist/: before this patch, npm install --silent && npm run build
fails with sh: 1: tsc: not found. After: ✓ built in 5.35s.

Test plan

The existing assertion in tests/hermes_cli/test_tui_resume_flow.py
(env["NODE_ENV"] == "production") is unchanged, since this PR does not
touch the TUI launcher. A targeted regression test calling _build_web_ui
with NODE_ENV=production set in os.environ and asserting the
subprocess env= carries NODE_ENV=development would slot under
tests/hermes_cli/. I can add it in this PR or a follow-up — pick whichever
fits the maintainers' usual cadence.

Alternative framings

  1. Per-call override at the build site (this PR).
  2. Strip NODE_ENV from the TUI subprocess env in _launch_tui.
  3. Both — (1) is required regardless because of CI/deploy shells; (2) is
    complementary cleanup.

…nstall

The bundled TUI launcher (_launch_tui in hermes_cli/main.py) sets
NODE_ENV=production on its node subprocess, and that env is inherited by
every shell, slash-command, and `hermes update` invocation spawned
from inside the TUI. Many CI/deploy shells also set NODE_ENV=production
system-wide.

When _build_web_ui then calls `npm install` (or `npm ci`) inside
web/, npm >= 9 honors NODE_ENV=production and skips devDependencies.
typescript lives in devDependencies, so tsc is not installed, and the
subsequent `tsc -b && vite build` fails with 'tsc: not found'. The
non-fatal branch swallows the failure as a warning and `hermes update`
otherwise reports success, leaving the user with a stale or missing
web_dist/ bundle.

Fix at the build site:

- _build_web_ui now constructs a child env with NODE_ENV=development
  for the npm install + build subprocesses.
- _run_npm_install_deterministic accepts and forwards an explicit
  env= kwarg so both `npm ci` and the `npm install` fallback honor
  the override.

Verified locally on a WSL install where NODE_ENV=production is in the
environment: before the fix, `npm install --silent && npm run build`
fails with 'sh: 1: tsc: not found'; after the fix the same shell
produces a clean web_dist/ build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants