From af42cb40e670a218512a7d8a5faef18ddc4e4b17 Mon Sep 17 00:00:00 2001 From: jenkins Date: Sun, 9 Aug 2026 16:12:00 -0300 Subject: [PATCH] fix(hermes): recover browser terminal sessions --- services/hermes/agent-deployment.yaml | 2 +- services/hermes/scripts/patch_ttyd_index.py | 96 ++++++++++++++++++++- testing/tests/test_hermes_herdr.py | 19 ++++ 3 files changed, 112 insertions(+), 5 deletions(-) diff --git a/services/hermes/agent-deployment.yaml b/services/hermes/agent-deployment.yaml index 633e1e5c7..13a4869bb 100644 --- a/services/hermes/agent-deployment.yaml +++ b/services/hermes/agent-deployment.yaml @@ -24,7 +24,7 @@ spec: ai.bstein.dev/execution: Herdr-supervised Codex and Claude Code ai.bstein.dev/model-policy: Jetson-assisted AUTO routing, low through xhigh, cross-provider fallback ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available - ai.bstein.dev/config-rev: "20260809-terminal-clipboard" + ai.bstein.dev/config-rev: "20260809-terminal-recovery" vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: hermes-agent vault.hashicorp.com/agent-inject-secret-anthropic-token: kv/data/atlas/hermes/agent-tokens diff --git a/services/hermes/scripts/patch_ttyd_index.py b/services/hermes/scripts/patch_ttyd_index.py index cb4a293c8..32a1d5eb6 100644 --- a/services/hermes/scripts/patch_ttyd_index.py +++ b/services/hermes/scripts/patch_ttyd_index.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Add reliable browser clipboard handling to ttyd's pinned client page.""" +"""Add reliable clipboard and reconnect handling to ttyd's pinned client.""" from __future__ import annotations @@ -27,9 +27,25 @@ CLIPBOARD_ADAPTER = r""" top: 12px; z-index: 10000; } + #atlas-terminal-recovery { + background: #181825; + border: 1px solid #89b4fa; + border-radius: 8px; + color: #cdd6f4; + font: 16px/1.4 monospace; + left: 50%; + padding: 12px 18px; + position: fixed; + top: 50%; + transform: translate(-50%, -50%); + z-index: 10001; + } ' + ) + content = ttyd_patch.patch_html(source) + + assert "class AtlasRecoveringWebSocket" in content + assert "new URL('token', window.location.href)" in content + assert "credentials: 'same-origin'" in content + assert "response.type === 'opaqueredirect'" in content + assert "typeof payload.token === 'string'" in content + assert "window.location.reload()" in content + assert "Reconnecting terminal automatically..." in content + assert "if (!recoveryStarted || event.key !== 'Enter') return" in content + assert content.index('id="atlas-ttyd-clipboard"') < content.index( + '' + ) + + def test_ttyd_clipboard_patch_fails_closed_on_upstream_drift(): with pytest.raises(RuntimeError, match="context changed"): ttyd_patch.patch_html("changed")