Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion hermes_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5549,6 +5549,8 @@ def _run_npm_install_deterministic(
cwd=cwd,
capture_output=capture_output,
text=True,
encoding="utf-8",
errors="replace",
check=False,
)
if ci_result.returncode == 0:
Expand All @@ -5561,6 +5563,8 @@ def _run_npm_install_deterministic(
cwd=cwd,
capture_output=capture_output,
text=True,
encoding="utf-8",
errors="replace",
check=False,
)

Expand Down Expand Up @@ -5597,7 +5601,14 @@ def _build_web_ui(web_dir: Path, *, fatal: bool = False) -> bool:
if fatal:
print(" Run manually: cd web && npm install && npm run build")
return False
r2 = subprocess.run([npm, "run", "build"], cwd=web_dir, capture_output=True)
r2 = subprocess.run(
[npm, "run", "build"],
cwd=web_dir,
capture_output=True,
text=True,
encoding="utf-8",
errors="replace",
)
if r2.returncode != 0:
print(
f" {'✗' if fatal else '⚠'} Web UI build failed"
Expand Down
1 change: 1 addition & 0 deletions scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@
"58116817+TurgutKural@users.noreply.github.com": "TurgutKural", # salvage of #23356 (HERMES_HOME inject)
"openclaw@agent.local": "29206394", # PR #22194 salvage (sudo -S brute-force guard, #9590)
"freedemon@gmail.com": "fr33d3m0n", # PR #21128 salvage (sudo stdin/askpass DANGEROUS, #17873 cat 4)
"zhaowh3613@outlook.com": "VinceZcrikl", # PR #23647 salvage (npm UTF-8 decode on GBK Windows)
}


Expand Down
30 changes: 29 additions & 1 deletion tests/hermes_cli/test_web_ui_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import pytest

from hermes_cli.main import _web_ui_build_needed, _build_web_ui
from hermes_cli.main import _web_ui_build_needed, _build_web_ui, _run_npm_install_deterministic


def _touch(path: Path, offset: float = 0.0) -> None:
Expand Down Expand Up @@ -119,3 +119,31 @@ def test_runs_npm_when_dist_missing(self, tmp_path):

assert result is True
assert mock_run.call_count == 2 # npm install + npm run build

def test_npm_install_uses_utf8_replace_output_decoding(self, tmp_path):
web_dir, _ = _make_web_dir(tmp_path)
(web_dir / "package-lock.json").write_text("{}", encoding="utf-8")

mock_cp = __import__("subprocess").CompletedProcess([], 0, stdout="", stderr="")
with patch("hermes_cli.main.subprocess.run", return_value=mock_cp) as mock_run:
result = _run_npm_install_deterministic("/usr/bin/npm", web_dir)

assert result.returncode == 0
_, kwargs = mock_run.call_args
assert kwargs["text"] is True
assert kwargs["encoding"] == "utf-8"
assert kwargs["errors"] == "replace"

def test_web_build_uses_utf8_replace_output_decoding(self, tmp_path):
web_dir, _ = _make_web_dir(tmp_path)

mock_cp = __import__("subprocess").CompletedProcess([], 0, stdout="", stderr="")
with patch("hermes_cli.main.shutil.which", return_value="/usr/bin/npm"), \
patch("hermes_cli.main.subprocess.run", side_effect=[mock_cp, mock_cp]) as mock_run:
result = _build_web_ui(web_dir)

assert result is True
_, build_kwargs = mock_run.call_args_list[1]
assert build_kwargs["text"] is True
assert build_kwargs["encoding"] == "utf-8"
assert build_kwargs["errors"] == "replace"
Loading