fix(conversations): clear closed agent status#2662
Conversation
Greptile SummaryThis PR fixes stale agent activity indicators by making
Confidence Score: 5/5Safe to merge — the change is tightly scoped and correctly addresses the stale-indicator bug without regressing tmux sessions. The boolean return from detachSession cleanly encodes whether the agent was actually terminated, and dehydrateConversation gates the event emit on that signal. The tmux guard (return false) prevents any status reset for live tmux agents. The AgentHookService listener is idempotent, both implementation classes and the interface are consistently updated, and the new unit tests cover the critical conditional paths. No files require special attention.
|
| Filename | Overview |
|---|---|
| apps/emdash-desktop/src/main/core/conversations/dehydrateConversation.ts | Conditional emit of agentSessionExitedChannel based on detachSession return value; correctly avoids resetting live tmux agents. |
| apps/emdash-desktop/src/main/core/conversations/impl/local-conversation.ts | detachSession now returns false for tmux paths, true for plain-PTY paths; logic is unchanged, only the return type and value differ. |
| apps/emdash-desktop/src/main/core/conversations/impl/ssh-conversation.ts | Mirrors local-conversation.ts changes: detachSession returns boolean indicating whether the SSH agent was terminated. |
| apps/emdash-desktop/src/main/core/agent-hooks/agent-hook-service.ts | Extracts shouldResetAgentStatusOnSessionExit helper and broadens the reset guard to cover awaiting-input in addition to working. |
| apps/emdash-desktop/src/main/core/conversations/types.ts | Interface updated to reflect Promise return type for detachSession; correctly propagated. |
| apps/emdash-desktop/src/main/core/conversations/dehydrateConversation.test.ts | New test file covering both the emit and no-emit paths for dehydrateConversation; thorough coverage of the conditional logic. |
| apps/emdash-desktop/src/main/core/agent-hooks/agent-hook-service.test.ts | Tests for shouldResetAgentStatusOnSessionExit correctly assert that working/awaiting-input reset and idle/completed/error/null do not. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as Renderer (tab close)
participant DC as dehydrateConversation
participant LP as LocalConversationProvider
participant EV as events (agentSessionExitedChannel)
participant AHS as AgentHookService
UI->>DC: dehydrateConversation(projectId, taskId, convId)
DC->>LP: detachSession(convId)
alt tmux session
LP-->>DC: false (agent still running in tmux)
DC-->>UI: (no emit)
else plain PTY
LP->>LP: detachPty() to pty.kill()
LP->>LP: knownSessionIds.delete() + supervisor.forget()
LP-->>DC: true (agent terminated)
DC->>EV: emit agentSessionExitedChannel
EV->>AHS: listener fires
AHS->>AHS: shouldResetAgentStatusOnSessionExit(status)?
alt status is working or awaiting-input
AHS->>AHS: UPDATE agentStatus to idle
AHS->>EV: emit conversationAgentStatusChangedChannel idle
else status is idle/completed/error/null
AHS-->>AHS: no-op
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as Renderer (tab close)
participant DC as dehydrateConversation
participant LP as LocalConversationProvider
participant EV as events (agentSessionExitedChannel)
participant AHS as AgentHookService
UI->>DC: dehydrateConversation(projectId, taskId, convId)
DC->>LP: detachSession(convId)
alt tmux session
LP-->>DC: false (agent still running in tmux)
DC-->>UI: (no emit)
else plain PTY
LP->>LP: detachPty() to pty.kill()
LP->>LP: knownSessionIds.delete() + supervisor.forget()
LP-->>DC: true (agent terminated)
DC->>EV: emit agentSessionExitedChannel
EV->>AHS: listener fires
AHS->>AHS: shouldResetAgentStatusOnSessionExit(status)?
alt status is working or awaiting-input
AHS->>AHS: UPDATE agentStatus to idle
AHS->>EV: emit conversationAgentStatusChangedChannel idle
else status is idle/completed/error/null
AHS-->>AHS: no-op
end
end
Reviews (2): Last reviewed commit: "fix(conversations): preserve tmux agent ..." | Re-trigger Greptile
Description
workingandawaiting-inputstatuses toidleon session exitScreenshot/Recording (if applicable)
https://streamable.com/oett2n
Checklist
messages and, when possible, the PR title