HERMES-GIELIE/api
ai-ag2026 a31cdb7765 fix(terminal): unsubscribe when the SSE header write fails after attaching
Adversarial review of the previous commit found a leak it introduced.

`attach_terminal()` subscribes and only then are the response headers written.
A client that dropped in that instant makes `end_headers()` raise
BrokenPipeError/ConnectionResetError, and because the `try/finally` started
*after* those writes, the exception escaped `_handle_terminal_output` with the
queue still in `_subscribers`. That pins `unwatched_since` at None — only
`unsubscribe()` on an empty subscriber list resets it — so the terminal became
permanently unreapable: the exact fd/thread leak (#4633) this reaper exists to
prevent, and strictly worse than the TOCTOU the previous commit fixed, since
that at least still allowed cleanup.

The try now starts immediately after the attach, so every exit path
unsubscribes. Regression test drives a handler whose `end_headers()` raises and
asserts the subscriber list is empty, `unwatched_since` is restored, and the
terminal is reapable again once the grace elapses. It fails against the
previous ordering.
2026-07-25 03:17:30 +02:00
..
__init__.py
agent_health.py fix: fail closed on wrapped gateway pid helpers 2026-07-14 16:36:23 +08:00
agent_runtime.py fix(runtime): ignore in-memory agent module swaps 2026-07-16 22:28:35 +08:00
agent_sessions.py Release exp-v0.52.40: ACP sessions in sidebar (#5939) + date-stamped Claude 3.0 reasoning fix (#5934) (#5951) 2026-07-11 15:20:41 -07:00
auth.py Release exp-v0.52.43: trusted-header auth / reverse-proxy SSO (#5568, #3351) (#5956) 2026-07-11 16:34:14 -07:00
auth_oidc.py Release: OIDC allowlist whitespace fix (#6244, @webtecnica) (#6259) 2026-07-18 10:36:17 -07:00
background.py
background_process.py fix(wakeup): recover terminal process completions after restart (#6287) 2026-07-18 20:07:54 -07:00
clarify.py
commands.py
compression_anchor.py
compression_recovery.py
config.py Merge remote-tracking branch 'origin/master' into stage/6040 2026-07-23 02:26:42 +00:00
crash_visibility.py
dashboard_probe.py
extension_sidecar_auth.py feat(extensions): token-v1 proxy→sidecar authentication boundary (#6331) 2026-07-20 17:49:23 +00:00
extensions.py feat(extensions): token-v1 proxy→sidecar authentication boundary (#6331) 2026-07-20 17:49:23 +00:00
gateway_chat.py fix(#6008): keep gateway cancel authority stable across startup teardown 2026-07-22 12:33:26 -04:00
gateway_restart.py fix: harden gateway restart recovery targeting 2026-07-14 16:01:56 +08:00
gateway_watcher.py
goals.py
helpers.py Release: raster-data-URI redaction fast-path (#6311, @inch772) (#6367) 2026-07-20 16:30:04 +00:00
kanban_bridge.py
metering.py feat(#6006): instrument send-to-first-token latency 2026-07-13 17:56:44 -04:00
models.py feat: render process wakeups as collapsed summary cards (#6350) 2026-07-23 20:52:51 +00:00
oauth.py perf(providers): invalidate cache on oauth credential changes 2026-07-13 19:58:41 +08:00
office_documents.py
onboarding.py Cover onboarding with atomic config writes 2026-07-18 13:47:04 +02:00
passkeys.py Release Batch D: terminal resource-leak fix + fsync atomic writers (#5835, #5843) (#5848) 2026-07-09 10:54:06 -07:00
paths.py fix(config): restore read-only-target protection for atomic writes 2026-07-18 20:32:56 +02:00
plugin_providers.py
plugins.py
process_event_utils.py feat: render process wakeups as collapsed summary cards (#6350) 2026-07-23 20:52:51 +00:00
profiles.py stage: merge #5797 2026-07-22 18:45:24 +00:00
providers.py perf(providers): invalidate cache on oauth credential changes 2026-07-13 19:58:41 +08:00
request_diagnostics.py perf(webui/session-load-latency) tier4: fix CI failures — lint B009/B905 + _emit_slow format args 2026-07-09 04:22:21 +00:00
rollback.py
route_approvals.py fix(#6008): serialize identity-less approval relays 2026-07-22 15:06:33 -04:00
route_session_list_cache.py fix(cache): keep streaming TTLs above poll cadence 2026-07-15 20:59:59 +00:00
routes.py fix(terminal): unsubscribe when the SSE header write fails after attaching 2026-07-25 03:17:30 +02:00
run_journal.py Release: run-journal summary cache (#6291, @sjungwon03) (#6355) 2026-07-20 09:12:32 +00:00
runner_client.py
runtime_adapter.py
session_discoverability.py Release Batch D: terminal resource-leak fix + fsync atomic writers (#5835, #5843) (#5848) 2026-07-09 10:54:06 -07:00
session_events.py
session_export_html.py
session_lifecycle.py
session_ops.py fix: preserve lazy alignment semantics 2026-07-17 15:36:55 -06:00
session_recovery.py
shares.py fix(share): harden _embed_share_media with path allow-list + mime validation (#6174) 2026-07-23 01:21:59 +00:00
skill_usage.py
sse_chunked.py
startup.py
state_sync.py
streaming.py feat: render process wakeups as collapsed summary cards (#6350) 2026-07-23 20:52:51 +00:00
system_health.py
terminal.py fix(terminal): close the reaper's selection→reconnect→close TOCTOU 2026-07-25 00:33:41 +02:00
todo_state.py
turn_journal.py
updates.py Release: pip-installable packaging metadata (#6337, @rodboev) (#6344) 2026-07-20 02:17:52 +00:00
upload.py Release: write Office upload sidecars (#5734, #540) (#5859) 2026-07-09 15:57:21 -07:00
usage.py
webui_session_db.py
workspace.py
workspace_git.py
worktrees.py fix(worktrees): unlock before remove so WebUI-created worktrees can be reaped 2026-07-13 17:47:58 +00:00