Count Hermes run as a module from an activated venv as Hermes too

With the venv active, a gateway started by hand is `python -m hermes_cli.main gateway run`: the interpreter is bare, the executable resolves outside the runtime, and no runtime path is on the command line, so the removal took it for a stranger and refused over the files it holds rather than closing it. Hermes's own package named with -m is the program.

Co-Authored-By: Codex XHigh <noreply@openai.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
committed 2026-09-24 21:41:08 -05:00
1 parent 14eb9430c3
commit 5630c6f561
2 files changed
+26 -3

No files matched your search

+7 -3
View File
@@ -21,7 +21,8 @@ unit_stopped() {
# the desktop app and its helpers, a gateway run by hand -- every process
# whose program, by its executable or by what it was started as, lives in the
# runtime about to be deleted or in the package; for an interpreter that is
# the script it runs, so a gateway started by hand as `python .../hermes` is
# the script it runs, or Hermes's own package named with -m, so a gateway
# started by hand as `python .../hermes` or `python -m hermes_cli.main` is
# found too. Judged by the program alone, never by a later argument: an
# editor opened on a file in the runtime is the user's. `check` refuses first if anything else has Hermes's files open, by
# its executable, its working directory or a descriptor, that editor or a
@@ -76,9 +77,12 @@ def processes():
except PermissionError:
pass
started_as = argv[:1]
if started_as and re.fullmatch(r'(python[0-9.]*|node|bash|sh)', os.path.basename(started_as[0])):
interpreter = bool(started_as) and re.fullmatch(r'(python[0-9.]*|node|bash|sh)', os.path.basename(started_as[0]))
if interpreter:
started_as = argv[:2]
ours = any(under(target, runtime) for target in started_as + program)
# Hermes's own package, run as a module from an activated venv.
ours = any(under(target, runtime) for target in started_as + program) or \
(bool(interpreter) and argv[1:3] and argv[1] == '-m' and argv[2].startswith('hermes_cli'))
if ours or any(under(target, roots) for target in touched):
try:
name = (process / 'comm').read_text().strip()
+19
View File
@@ -430,6 +430,25 @@ finally:
gateway.wait(timeout=5)
print('ok - an interpreter running a runtime script is Hermes and is stopped')
# Run as a module from an activated venv, the interpreter is bare and the
# script is nowhere on the command line; Hermes's own package name is.
home, runtime, env = setup('module')
(runtime / 'hermes_cli').mkdir(parents=True)
(runtime / 'hermes_cli/__init__.py').write_text('')
(runtime / 'hermes_cli/main.py').write_text('import time\ntime.sleep(30)\n')
module = subprocess.Popen([sys.executable, '-m', 'hermes_cli.main', 'gateway', 'run'], cwd=scratch,
env={**os.environ, 'PYTHONPATH': str(runtime)})
try:
result = remove(env)
assert result.returncode == 0, result
assert 'Stopping Hermes (PIDs: ' + str(module.pid) in result.stdout, result.stdout
assert module.wait(timeout=5) != 0, 'hermes_cli run as a module is stopped'
finally:
if module.poll() is None:
module.terminate()
module.wait(timeout=5)
print('ok - hermes_cli run as a module from a bare interpreter is Hermes and is stopped')
# A program whose executable lives in the runtime is Hermes whatever it was
# started as: the Electron helpers name themselves by path, but a copy of the
# binary started by a bare name is found through /proc/<pid>/exe.