fix(desktop): use the canonical gateway matcher for the preflight exemption

_is_pausable_gateway() hand-rolled a second gateway parser and regressed
a valid form: in `--profile gateway gateway run` the profile VALUE
shadowed the subcommand token, so the scan reported that gateway as a
fatal preflight holder. Delegate to
gateway.status.looks_like_gateway_command_line() - profile-selector
aware, shlex-tokenizing, run-only - so the preflight exemption, the
pause discovery, and the updater's guard fallback share one parser.
Non-run gateway subcommands, serve backends, and REPLs still block; the
bare-`gateway` form now classifies as a running gateway, mirroring the
canonical matcher's contract.
This commit is contained in:
iso2kx 2026-07-31 11:46:47 +08:00 committed by Teknium
parent a31fe8db6e
commit f3edd0e538
2 changed files with 18 additions and 9 deletions

View File

@ -109,16 +109,21 @@ def _is_pausable_gateway(cmdline: str) -> bool:
venv (an operator's REPL, a stray script, a ``serve`` backend that
survived the desktop's own teardown) has no pause machinery downstream
and must keep blocking the handoff.
Delegates to ``gateway.status.looks_like_gateway_command_line`` the
canonical ``gateway run`` matcher (profile-selector aware, shlex
tokenization, ``run``-only) so this exemption, the pause discovery,
and the updater's guard fallback all share one parser. A hand-rolled
token scan here regressed ``--profile gateway gateway run``: the profile
*value* shadowed the subcommand token. An import failure counts as
not-pausable the scan then reports the process as a blocker, which is
exactly the pre-exemption behavior.
"""
lowered = cmdline.lower()
if "hermes_cli.main" not in lowered:
return False
try:
tokens = [t for t in lowered.split() if t]
idx = tokens.index("gateway")
except ValueError:
from gateway.status import looks_like_gateway_command_line # noqa: PLC0415
except Exception:
return False
return len(tokens) > idx + 1 and tokens[idx + 1] == "run"
return looks_like_gateway_command_line(cmdline)
def main() -> None:

View File

@ -118,6 +118,12 @@ def test_redact_short_flags_not_redacted() -> None:
" -m hermes_cli.main gateway run --replace",
# profile-scoped gateway
"python.exe -m hermes_cli.main --profile work gateway run",
# a profile literally NAMED "gateway" — the profile value must not
# shadow the subcommand token (the hand-rolled matcher regressed this)
"python.exe -m hermes_cli.main --profile gateway gateway run",
"python.exe -m hermes_cli.main -p gateway gateway run",
# bare `gateway` defaults to `run` (mirrors the canonical matcher)
"python.exe -m hermes_cli.main gateway",
# case variations survive
"PYTHON.EXE -m hermes_cli.main GATEWAY RUN",
],
@ -138,8 +144,6 @@ def test_is_pausable_gateway_accepts_gateway_run_chains(cmdline: str) -> None:
# operator REPL / stray script
"python.exe",
"python.exe myscript.py gateway run", # not a hermes_cli.main invocation
# 'gateway' as a trailing word with nothing after it
"python.exe -m hermes_cli.main gateway",
"",
],
)