fix(terminal): keep package-manager settings out of user shells

A desktop or dashboard started through `pnpm run` carries pnpm_config_*
(store, cache and state dirs) besides npm_config_*/npm_package_*, and the
user's own pnpm in the integrated terminal would pick them up. Both shell
builders, Electron's terminal IPC and the dashboard host terminal, now drop
all three prefixes, case-insensitively (Windows env names are).
This commit is contained in:
Maciej Lisiewski committed 2026-11-06 04:08:24 +01:00
1 parent 7062229090
commit ced0ea775d
3 files changed
+26 -4

No files matched your search

+7 -3
View File
@@ -171,10 +171,14 @@ export function registerTerminalIpc({
function terminalShellEnv() {
const env = { ...process.env }
// Electron is commonly launched through `npm run dev`; do not leak npm's
// managed prefix into a user's interactive shell (nvm/proto warn loudly).
// Electron is commonly launched through `pnpm run dev`; do not leak the
// package manager's settings into a user's interactive shell (nvm/proto warn
// loudly, and the user's own pnpm would inherit them). Windows env names are
// case-insensitive: NPM_CONFIG_* is the same setting.
for (const key of Object.keys(env)) {
if (key === 'npm_config_prefix' || key.startsWith('npm_config_') || key.startsWith('npm_package_')) {
const name = key.toLowerCase()
if (name.startsWith('npm_config_') || name.startsWith('npm_package_') || name.startsWith('pnpm_config_')) {
delete env[key]
}
}
+4 -1
View File
@@ -136,8 +136,11 @@ def resolve_argv(
finally:
reset_hermes_home_override(override_token)
# A dashboard started through `pnpm run` carries the package manager's
# settings; the user's own shell (and pnpm) must not inherit them. Windows
# env names are case-insensitive: NPM_CONFIG_* is the same setting.
for key in list(env):
if key == "npm_config_prefix" or key.startswith(("npm_config_", "npm_package_")):
if key.lower().startswith(("npm_config_", "npm_package_", "pnpm_config_")):
env.pop(key, None)
for key in ("NO_COLOR", "FORCE_COLOR", "COLORFGBG"):
env.pop(key, None)
@@ -116,6 +116,21 @@ def test_host_terminal_resolver_applies_selected_profile_home_and_config(
assert "OPENAI_API_KEY" not in env
def test_host_terminal_shell_inherits_no_package_manager_settings(tmp_path, monkeypatch):
from hermes_cli import web_host_terminal
from hermes_constants import get_hermes_home
leaked = {"pnpm_config_store_dir": str(tmp_path / "store"), "NPM_CONFIG_CACHE": str(tmp_path / "cache"),
"npm_config_prefix": str(tmp_path / "prefix"), "npm_package_name": "hermes-agent"}
for name, value in leaked.items():
monkeypatch.setenv(name, value)
_argv, _cwd, env, _shell_name = web_host_terminal.resolve_argv(home=get_hermes_home(), requested_cwd=str(tmp_path))
assert not set(leaked) & set(env)
assert env["TERM"] == "xterm-256color"
@pytest.mark.platforms("linux")
def test_host_terminal_resolver_uses_real_linux_shell(tmp_path, monkeypatch):
monkeypatch.setenv("SHELL", "/bin/sh")