Files
hermes-agent/hermes_state_ids.py
teknium1 c1e58f4cb2 fix(process-identity): desktop reap, Windows updater and profile liveness use the canonical matchers
Two kill/relaunch predicates decided identity by argv substring, the bug class root AGENTS.md
forbids: hermes_cli/dashboard_procs.py::_is_desktop_local_serve_cmdline (`"serve" not in cmd`,
on the orphan-reap KILL path) and hermes_cli/update_cmd_windows.py::_is_backend_argv
(`" serve" in argv_low`, in the very file that defines _hermes_holder_subcommand). Both now ask
the canonical token classifier; host/port are read as flag values, not substrings.

hermes_cli/profiles.py::_check_gateway_running open-coded rungs 1/3 of
gateway.status.resolve_gateway_liveness and skipped the multiplexer rung; it is now that ladder
scoped to the profile dir (pid probe keeps cleanup_stale=False so a probe for another profile
never unlinks its PID file). The gateway/status.py ladder itself is untouched.

Behavior change: `hermes kanban --preserve-cache --host 127.0.0.1 --port 0` and
`-m dashboard serve`-style argv are no longer classified as serve backends (never killed /
relaunched as one); a named profile served by the live default multiplexer now reads as
running from _check_gateway_running (previously only via the separate
_served_by_running_multiplexer OR at some call sites).
2026-09-13 05:21:02 -07:00

29 lines
1.2 KiB
Python

"""Session-id minting: the ONE place that knows the ``YYYYMMDD_HHMMSS_<hex>`` shape.
stdlib-only on purpose: ``agent/``, ``cli.py``, ``gateway/`` and ``tui_gateway/`` all mint ids and
must not pull the SessionDB import graph in to do it. ``hermes_cli/session_lost_and_found.py``
classifies schema-less salvage rows by ``SESSION_ID_PATTERN``, so a shape change here is a
recovery-classification change — keep the prefix stable.
"""
from __future__ import annotations
import re
import uuid
from datetime import datetime
from typing import Optional
SESSION_ID_PATTERN = re.compile(r"^\d{8}_\d{6}_")
# Interactive surfaces (CLI, TUI, agent, branches, imports) share 6 hex chars — the Desktop's
# session-id candidate regex is pinned to that width. Gateway keys are 8, portability imports 12
# (many rows minted in the same second).
DEFAULT_HEX_LEN = 6
def new_session_id(now: Optional[datetime] = None, *, hex_len: int = DEFAULT_HEX_LEN) -> str:
"""``<timestamp>_<random hex>`` for a fresh session; ``now`` pins the timestamp to a clock the
caller already captured (``agent.session_start``) so the id and the row agree to the second."""
stamp = (now or datetime.now()).strftime("%Y%m%d_%H%M%S")
return f"{stamp}_{uuid.uuid4().hex[:hex_len]}"