Skip to content

Commit e15a581

Browse files
authored
Fix sessions disappearing from UI shortly after hooks fire (farouqaldori#53)
* Fix sessions disappearing from UI shortly after hooks fire (farouqaldori#43) Sessions were incorrectly transitioning to idle phase and being filtered out of the display. This fix addresses two root causes: 1. HookEvent.determinePhase() now correctly maps idle_prompt notifications to waitingForInput instead of idle, and handles notification status explicitly as processing state. 2. UI filters in NotchView and NotchHeaderView no longer exclude idle sessions, allowing running Claude processes to remain visible with a dimmed indicator. * Align sessionPhase with determinePhase() for notification handling Ensures notification events trigger processing-related behavior like starting the InterruptWatcherManager. Previously, sessionPhase fell through to .idle for notification events while determinePhase() correctly returned .processing.
1 parent 12e7401 commit e15a581

4 files changed

Lines changed: 30 additions & 6 deletions

File tree

ClaudeIsland/Models/SessionEvent.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,14 @@ extension HookEvent {
161161
))
162162
}
163163

164-
if event == "Notification" && notificationType == "idle_prompt" {
165-
return .idle
164+
// Handle Notification events explicitly
165+
if event == "Notification" {
166+
if notificationType == "idle_prompt" {
167+
// idle_prompt means Claude finished and is waiting for user input
168+
return .waitingForInput
169+
}
170+
// Other notifications - session is still processing
171+
return .processing
166172
}
167173

168174
switch status {
@@ -172,11 +178,15 @@ extension HookEvent {
172178
"processing",
173179
"starting":
174180
return .processing
181+
case "notification":
182+
// Explicit notification status - session is still active
183+
return .processing
175184
case "compacting":
176185
return .compacting
177186
case "ended":
178187
return .ended
179188
default:
189+
// Unknown status - default to idle
180190
return .idle
181191
}
182192
}

ClaudeIsland/Services/Hooks/HookSocketServer.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ struct HookEvent: Sendable {
100100
return .compacting
101101
}
102102

103+
// Handle Notification events explicitly (aligned with determinePhase())
104+
if event == "Notification" {
105+
if notificationType == "idle_prompt" {
106+
return .waitingForInput
107+
}
108+
// Other notifications - session is still processing
109+
return .processing
110+
}
111+
103112
switch status {
104113
case "waiting_for_approval":
105114
// Note: Full PermissionContext is constructed by SessionStore, not here
@@ -116,6 +125,9 @@ struct HookEvent: Sendable {
116125
"processing",
117126
"starting":
118127
return .processing
128+
case "notification":
129+
// Explicit notification status - session is still active
130+
return .processing
119131
case "compacting":
120132
return .compacting
121133
default:

ClaudeIsland/UI/Views/NotchHeaderView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,10 +311,11 @@ struct SessionStateDots: View {
311311

312312
// MARK: Private
313313

314-
/// Filter to only active/attention-needed sessions and sort by priority
314+
/// Filter to exclude ended sessions and sort by priority
315+
/// Idle sessions are included as they represent running Claude processes
315316
private var sortedActiveSessions: [SessionState] {
316317
self.sessions
317-
.filter { $0.phase != .ended && $0.phase != .idle }
318+
.filter { $0.phase != .ended }
318319
.sorted { self.priority(for: $0.phase) < self.priority(for: $1.phase) }
319320
}
320321

ClaudeIsland/UI/Views/NotchView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,10 @@ struct NotchView: View {
183183
}
184184
}
185185

186-
/// Sessions that are active (not idle/ended) - used for dots display
186+
/// Sessions that are active (not ended) - includes idle sessions as they
187+
/// still represent running Claude processes
187188
private var activeSessions: [SessionState] {
188-
self.sessionMonitor.instances.filter { $0.phase != .ended && $0.phase != .idle }
189+
self.sessionMonitor.instances.filter { $0.phase != .ended }
189190
}
190191

191192
/// Whether we have multiple active sessions to show dots for

0 commit comments

Comments
 (0)