diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 4a12a34bb..89b01b18c 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -267,6 +267,34 @@ def _profile_suffix() -> str: return hashlib.sha256(str(home).encode()).hexdigest()[:8] +def _profile_arg(hermes_home: str | None = None) -> str: + """Return ``--profile `` only when HERMES_HOME is a named profile. + + For ``~/.hermes/profiles/``, returns ``"--profile "``. + For the default profile or hash-based custom paths, returns the empty string. + + Args: + hermes_home: Optional explicit HERMES_HOME path. Defaults to the current + ``get_hermes_home()`` value. Should be passed when generating a + service definition for a different user (e.g. system service). + """ + import re + from pathlib import Path as _Path + home = Path(hermes_home or str(get_hermes_home())).resolve() + default = (_Path.home() / ".hermes").resolve() + if home == default: + return "" + profiles_root = (default / "profiles").resolve() + try: + rel = home.relative_to(profiles_root) + parts = rel.parts + if len(parts) == 1 and re.match(r"^[a-z0-9][a-z0-9_-]{0,63}$", parts[0]): + return f"--profile {parts[0]}" + except ValueError: + pass + return "" + + def get_service_name() -> str: """Derive a systemd service name scoped to this HERMES_HOME. @@ -626,6 +654,7 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None) if system: username, group_name, home_dir = _system_service_identity(run_as_user) hermes_home = _hermes_home_for_target_user(home_dir) + profile_arg = _profile_arg(hermes_home) path_entries.extend(_build_user_local_paths(Path(home_dir), path_entries)) path_entries.extend(common_bin_paths) sane_path = ":".join(path_entries) @@ -640,7 +669,7 @@ StartLimitBurst=5 Type=simple User={username} Group={group_name} -ExecStart={python_path} -m hermes_cli.main gateway run --replace +ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace WorkingDirectory={working_dir} Environment="HOME={home_dir}" Environment="USER={username}" @@ -661,6 +690,7 @@ WantedBy=multi-user.target """ hermes_home = str(get_hermes_home().resolve()) + profile_arg = _profile_arg(hermes_home) path_entries.extend(_build_user_local_paths(Path.home(), path_entries)) path_entries.extend(common_bin_paths) sane_path = ":".join(path_entries) @@ -672,7 +702,7 @@ StartLimitBurst=5 [Service] Type=simple -ExecStart={python_path} -m hermes_cli.main gateway run --replace +ExecStart={python_path} -m hermes_cli.main{f" {profile_arg}" if profile_arg else ""} gateway run --replace WorkingDirectory={working_dir} Environment="PATH={sane_path}" Environment="VIRTUAL_ENV={venv_dir}" @@ -965,6 +995,7 @@ def generate_launchd_plist() -> str: log_dir = get_hermes_home() / "logs" log_dir.mkdir(parents=True, exist_ok=True) label = get_launchd_label() + profile_arg = _profile_arg(hermes_home) # Build a sane PATH for the launchd plist. launchd provides only a # minimal default (/usr/bin:/bin:/usr/sbin:/sbin) which misses Homebrew, # nvm, cargo, etc. We prepend venv/bin and node_modules/.bin (matching @@ -986,21 +1017,32 @@ def generate_launchd_plist() -> str: dict.fromkeys(priority_dirs + [p for p in os.environ.get("PATH", "").split(":") if p]) ) + # Build ProgramArguments array, including --profile when using a named profile + prog_args = [ + f"{python_path}", + "-m", + "hermes_cli.main", + ] + if profile_arg: + for part in profile_arg.split(): + prog_args.append(f"{part}") + prog_args.extend([ + "gateway", + "run", + "--replace", + ]) + prog_args_xml = "\n ".join(prog_args) + return f""" Label {label} - + ProgramArguments - {python_path} - -m - hermes_cli.main - gateway - run - --replace + {prog_args_xml} WorkingDirectory