refactor(windows): tidy managed-node resolver helpers

Behavior-preserving cleanups on the managed-node resolver:
- Hoist _candidate_node_command_names() out of the inner dir loop in
  find_hermes_node_executable (computed once, not per directory).
- Drop redundant os.environ.copy() at the two with_hermes_node_path(
  os.environ.copy()) sites \u2014 the helper already copies os.environ when
  called with no argument (verified env-equivalent).
- Add reciprocal keep-in-sync comments between iter_hermes_node_dirs()
  (hermes_constants.py) and hermesManagedNodePathEntries() (electron
  main.cjs), which mirror the same platform-ordering rule across the
  Python/Node boundary.
This commit is contained in:
kshitijk4poor 2026-06-20 02:12:16 +05:30
parent fcc169057d
commit d4e7dd609d
4 changed files with 12 additions and 3 deletions

View file

@ -270,6 +270,9 @@ function resolveHermesHome() {
const HERMES_HOME = resolveHermesHome()
function hermesManagedNodePathEntries() {
// NOTE: keep this ordering in sync with iter_hermes_node_dirs() in
// hermes_constants.py — this Node main process cannot import the Python
// module, so the platform-ordering rule is mirrored here.
const root = path.join(HERMES_HOME, 'node')
const bin = path.join(root, 'bin')
const entries = IS_WINDOWS ? [root, bin] : [bin, root]

View file

@ -492,7 +492,8 @@ class WhatsAppAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter):
# Build bridge subprocess environment.
# Pass WHATSAPP_REPLY_PREFIX from config.yaml so the Node bridge
# can use it without the user needing to set a separate env var.
bridge_env = with_hermes_node_path(os.environ.copy())
# with_hermes_node_path() copies os.environ when called with no arg.
bridge_env = with_hermes_node_path()
if self._reply_prefix is not None:
bridge_env["WHATSAPP_REPLY_PREFIX"] = self._reply_prefix
# Pass the profile-aware cache directories so the bridge writes

View file

@ -5407,7 +5407,8 @@ def cmd_gui(args: argparse.Namespace):
from hermes_constants import find_node_executable, with_hermes_node_path
env = with_hermes_node_path(os.environ.copy())
# with_hermes_node_path() copies os.environ when called with no arg.
env = with_hermes_node_path()
if getattr(args, "fake_boot", False):
env["HERMES_DESKTOP_BOOT_FAKE"] = "1"
if getattr(args, "ignore_existing", False):

View file

@ -254,6 +254,9 @@ def iter_hermes_node_dirs(home: Path | None = None) -> list[Path]:
root = home or get_hermes_home()
dirs = [root / "node"]
bin_dir = root / "node" / "bin"
# NOTE: keep this ordering in sync with hermesManagedNodePathEntries() in
# apps/desktop/electron/main.cjs — the Electron main process is Node and
# cannot import this module, so the platform-ordering rule is mirrored there.
if sys.platform == "win32":
return dirs + [bin_dir]
return [bin_dir] + dirs
@ -276,8 +279,9 @@ def _candidate_node_command_names(command: str) -> list[str]:
def find_hermes_node_executable(command: str) -> str | None:
"""Return a Hermes-managed Node/npm executable path, if installed."""
names = _candidate_node_command_names(command)
for directory in iter_hermes_node_dirs():
for name in _candidate_node_command_names(command):
for name in names:
candidate = directory / name
if candidate.is_file() and (
sys.platform == "win32" or os.access(candidate, os.X_OK)