17 Commits
Author SHA1 Message Date
ai-ag2026andClaude Fable 5 a248aa52de fix(ctl): close all three 12.07 re-gate findings on the systemd guard
1. inherit_errexit: the listener-diagnostic assignments in
   _port_listener_diag abort status/stop when errexit is inherited into
   command substitutions (shopt inherit_errexit or a BASHOPTS env from the
   invoking shell). Guard both assignments with || true; regression test
   runs status/stop under BASHOPTS=inherit_errexit.

2. PID/port AND: _pid_listens_on_port called lsof -p PID -iTCP:PORT
   without -a, which OR-combines the selectors — any socket of the PID or
   any listener on the port matched, so an active unit could be blamed for
   a port its MainPID does not listen on. Add -a; the new fake lsof
   mimics real OR/AND semantics so a missing -a fails the test.

3. Binding-aware collision: an active/activating unit whose ownership
   could not be attributed via MainPID was assumed to own port 8787
   unconditionally. Resolve the unit's configured binding first
   (HERMES_WEBUI_PORT from Environment=, then --port from ExecStart=) and
   refuse only on actual overlap; the default-port guard remains solely
   for undeterminable bindings (#3291 semantics). Tests cover the reverse
   alternate-port case (unit on 9999, start on 8787 proceeds) and the
   overlap case (unit on the requested port refuses).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 20:47:03 +02:00
ai-ag2026 7ab9f6ee5c fix: bypass proxies in ctl startup health probe 2026-07-18 13:53:21 +02:00
ai-ag2026 ee7af85884 fix(ctl): keep listener diagnostics best-effort 2026-07-18 13:53:21 +02:00
ai-ag2026andClaude Fable 5 1272ccb4eb fix(ctl): harden the foreign-instance guards per review
Four fixes from the Greptile review on #5944:

- Bracket IPv6 literals in the probe target ('::1' -> '[::1]') so the
  URL-based responder checks don't silently miss a running instance.
- Force direct connections in the local ownership probes: --noproxy '*'
  (curl) / --no-proxy (wget) in _port_answers_http, and neutralized
  proxy env around the startup-grace health probe — a configured
  http(s)_proxy would report the proxy instead of the port.
- Clamp HERMES_WEBUI_START_GRACE=0 to the default: a zero window would
  skip startup monitoring entirely and restore the stale-PID behavior
  the window exists to prevent.
- stop: warn about an unmanaged instance BEFORE deleting the state
  file — it carries the saved host/port binding the probe needs when
  the instance was started off-default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:53:21 +02:00
ai-ag2026andClaude Fable 5 6f10e4d48b fix(ctl): detect foreign/supervised WebUI instances instead of double-starting
ctl.sh start only guarded against launchd (macOS). On Linux, with a
systemd-supervised WebUI serving the port and a stale PID file, stop
reported 'stopped', start spawned a bootstrap that died ~2s later on
server.py's 'already responding' check — after the 0.15s aliveness gate
had already printed 'Started' and recorded the doomed PID. Killing the
foreign server by hand then put its supervisor's auto-restart into a
race with ctl.sh's start, ending in a permanent RestartSec crash loop.

- start: refuse when anything answers HTTP(S) on the target port (any
  response bytes, matching server.py's abort semantics — a 404 squatter
  still dooms our server), and when the hermes-webui systemd unit is
  active on our port or mid-auto-restart (activating). Port scoping
  mirrors the launchd #3291 over-block fix; overrides:
  HERMES_WEBUI_CTL_ALLOW_SYSTEMD_CONFLICT / _ALLOW_PORT_CONFLICT,
  unit name via HERMES_WEBUI_SYSTEMD_UNIT.
- start: watch the child through a startup grace window
  (HERMES_WEBUI_START_GRACE, default 3s) — report failure and clean the
  PID file when it dies during startup; break early once /health answers.
- status/stop: when ctl.sh owns no PID but the port answers, say
  'running (not managed by ctl.sh)' with listener diagnostics instead of
  'stopped', and never touch the foreign process.
- _pid_listens_on_port: ss fallback for Linux hosts without lsof.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:53:21 +02:00
nesquena-hermes b1a02bdb72 #5309: ctl.sh load ~/.hermes/.env 2026-07-01 23:24:38 +00:00
nesquena-hermesandtomas-forgac a308fdd5e8 release: v0.51.494 — TLS-aware launcher health probes (#4412)
Absorbs #4412 (tomas-forgac) rebased onto fresh master, plus two
Codex-regression-gate fixes: (1) use the scheme that actually answered the
probe for the ready/already-up URL + browser-open, (2) honor an explicit
HERMES_WEBUI_HEALTH_URL override in the WSL autostart probe.

Co-authored-by: tomas-forgac <tomas-forgac@users.noreply.github.com>

Closes #4412
2026-06-18 18:13:46 +00:00
2c7b530071 Release v0.51.269 — Release IK (stage-b2 — sidebar perf + search scope + Windows ctl) (#3672)
* perf(ui): single-pass sidebar session row partitioning (#3658)

Co-authored-by: Pamnard <pamnard@users.noreply.github.com>

* fix(search): scope session search to active profile (#3646)

Co-authored-by: hinotoi-agent <paperlantern.agent@gmail.com>

* fix(ctl): tree-kill ctl.sh stop on Windows (#3670)

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* docs(changelog): v0.51.269 — Release IK (stage-b2)

---------

Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: Pamnard <pamnard@users.noreply.github.com>
Co-authored-by: hinotoi-agent <paperlantern.agent@gmail.com>
Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-05 10:53:45 -07:00
AJV20 18eea5b2ab test(ctl): allow dotenv-free launches 2026-06-01 04:42:05 +00:00
nesquena-hermes e86488072a fix(#3291): make launchd duplicate-start guard port-aware (Codex gate MUST-FIX)
Codex regression gate found the launchd guard blocked ANY ctl.sh start while a
launchd job was live — including a legitimate second instance on a different
port (HERMES_WEBUI_PORT=8788). Now _launchd_webui_pid only treats the launchd
job as a conflict when its PID is actually listening on the requested CTL_PORT
(via a new best-effort _pid_listens_on_port helper using lsof); a different-port
start is allowed. When port ownership can't be determined (no lsof), falls back
to guarding only the default 8787 port so non-default ports are never wrongly
blocked. Adds a different-port-allowed regression test + makes the existing
block test deterministic. Co-authored-by preserved.
2026-05-31 23:08:52 +00:00
Andy Kang 91717b7e47 fix: block duplicate webui start when launchd owns 8787 2026-05-31 23:02:23 +00:00
Charanis f0b0854773 fix: preserve webui launcher environment
(cherry picked from commit 2297ab4db854b52b20cdd34731cd82e8cc5bdb72)
2026-05-24 21:49:21 +02:00
Frank Song d5dda03ec2 Fix ctl Python wrapper ownership 2026-05-13 13:09:42 +08:00
Ayush Sahay Chaudhary 74926090e3 fix: guard empty array iteration for bash 3.2 compatibility
The _load_repo_dotenv_preserving_env() function iterates over
${preserved[@]} with set -euo pipefail. On bash 3.2 (macOS default),
an empty array triggers 'unbound variable' under set -u, crashing
ctl.sh start. Bash 4+ handles this fine, but macOS ships 3.2.

Wraps the for loop in a length check: [[ ${#preserved[@]} -gt 0 ]]
2026-05-12 10:34:02 +05:30
Alan 025f137f28 fix: guard empty CTL_BOOTSTRAP_ARGS expansion for bash 3.2
With set -u, bash 3.2 treats empty array expansion
"\${CTL_BOOTSTRAP_ARGS[@]}" as an unbound variable.

Use ${CTL_BOOTSTRAP_ARGS[@]+"..."} pattern to skip
expansion when the array is empty.
2026-05-10 14:34:39 +08:00
Alan 630981a068 fix: use bash 3.2 compatible variable check in ctl.sh
Replace [[ -v ${key} ]] (requires bash 4.2+) with
[[ -n "${!key+x}" ]] which works on bash 3.2+ and all
POSIX-compatible shells.

macOS ships with bash 3.2, causing:
  ./ctl.sh: line 42: conditional binary operator expected
2026-05-10 14:29:07 +08:00
Michael Lam 46bdb3c1af feat: add ctl daemon lifecycle script 2026-05-05 01:12:08 +00:00