Files
hermes-agent/apps
John Paul Soliva 0b9287c8cf fix(desktop): a finished agent terminal stops pinning its backlog for the life of the renderer
Every `terminal(background=true)` mints a new process id, and the agent-terminal
stream module never forgot one. `writers` was unregistered when a tab unmounted,
but `backlog`, `lastSnapshots`, `commandHeaders` and `seededCommands` are keyed
by process id and had no eviction at all, so every command an agent ever ran kept
its output until the window closed.

Replaying each process back through `registerAgentTerminalWriter` measures the
retention directly, without depending on GC: 256K chars held per finished process
(~512 KB, JS strings being UTF-16), growing linearly — 100 processes 25.6M chars,
200 51.2M, 400 102.4M (~195 MB). With this change it is flat at 1.79M chars
(~3.4 MB) for every one of those counts.

Bounded the way the other renderer caches already are (`lib/lru-cache`,
`chat/shiki-highlight-cache`): an entry ceiling and a total-character ceiling,
because one busy process can hold as much as twenty quiet ones. `backlog`
insertion order is the LRU clock, so a chunk write re-inserts to move its process
to the tail — a plain re-set keeps the original slot and would let the
oldest-first sweep evict a process that is still streaming.

A process whose terminal is MOUNTED is never evicted: that is on screen, not a
cache. Everything dropped is regenerable — the next `syncAgentTerminalSnapshot`
re-seeds the tab from the registry's rolling tail. The four maps are evicted
together because `lastSnapshots` is the delta fence for `backlog`; dropping one
without the other makes the next snapshot diff against a tail that is gone and
paint only the delta.

Each guarantee is pinned by a regression that fails when that guarantee alone is
reverted: no eviction, evicting a mounted process, losing the recency refresh,
and keeping a stale delta fence.
2026-09-29 11:41:14 -05:00
..