Skip to content

Commit e5dad78

Browse files
phiatclaude
andcommitted
Graceful startup when no Claude Code sessions exist
Start TUI with empty tree instead of crashing when ~/.claude doesn't exist or no sessions are found. Auto-discovers sessions as they appear. - Don't error in New() when session not found or dir missing - Watch ancestor directory when claudeDir doesn't exist yet - Switch to full recursive watch when claudeDir is created - Show "Waiting for Claude Code sessions..." in empty tree - Show "Waiting..." in header when 0 sessions - Bump version to 0.3.1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d27d0e4 commit e5dad78

File tree

4 files changed

+39
-12
lines changed

4 files changed

+39
-12
lines changed

internal/tui/model.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,9 @@ func (m *Model) renderHeader() string {
380380
if !m.watcher.IsAutoDiscoveryEnabled() {
381381
autoDisc = " [paused]"
382382
}
383-
if len(sessions) == 1 {
383+
if len(sessions) == 0 {
384+
sessionInfo = "Waiting..."
385+
} else if len(sessions) == 1 {
384386
for _, s := range sessions {
385387
sessionInfo = fmt.Sprintf("Session: %s%s", truncate(s.ID, 12), autoDisc)
386388
}

internal/tui/tree.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ func (t *TreeView) SetSize(width, height int) {
418418
// View renders the tree
419419
func (t *TreeView) View() string {
420420
if len(t.nodes) == 0 {
421-
return mutedStyle.Render("No sessions")
421+
return mutedStyle.Render("Waiting for Claude Code sessions...")
422422
}
423423

424424
var b strings.Builder

internal/watcher/watcher.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,15 @@ func New(sessionID string, pollInterval time.Duration) (*Watcher, error) {
223223
w.watchActive.Store(sessionID == "") // watch all active if no specific session
224224

225225
if sessionID != "" {
226-
// Watch a specific session
226+
// Watch a specific session (graceful — don't crash if not found yet)
227227
session, err := w.findSession(sessionID)
228-
if err != nil {
229-
return nil, err
228+
if err == nil {
229+
w.sessions[session.ID] = session
230230
}
231-
w.sessions[session.ID] = session
231+
// If not found, watch loops will discover it
232232
} else {
233-
// Find all active sessions
234-
if err := w.discoverActiveSessions(); err != nil {
235-
return nil, err
236-
}
233+
// Find all active sessions (ignore errors — dir may not exist yet)
234+
_ = w.discoverActiveSessions()
237235
}
238236

239237
return w, nil
@@ -753,7 +751,11 @@ func (w *Watcher) watchLoopFsnotify() {
753751
defer cleanupTicker.Stop()
754752

755753
// Set up directory watches for discovery
756-
w.addDirectoryWatches(w.claudeDir)
754+
if _, err := os.Stat(w.claudeDir); err == nil {
755+
w.addDirectoryWatches(w.claudeDir)
756+
} else {
757+
w.watchAncestorDirectory(w.claudeDir)
758+
}
757759

758760
// Register file watches for all known sessions
759761
sessions := w.getSessionsSnapshot()
@@ -788,6 +790,22 @@ func (w *Watcher) watchLoopFsnotify() {
788790
}
789791
}
790792

793+
// watchAncestorDirectory watches the closest existing ancestor of a path
794+
func (w *Watcher) watchAncestorDirectory(target string) {
795+
dir := target
796+
for {
797+
parent := filepath.Dir(dir)
798+
if parent == dir {
799+
break
800+
}
801+
if _, err := os.Stat(parent); err == nil {
802+
w.fsWatcher.Add(parent)
803+
return
804+
}
805+
dir = parent
806+
}
807+
}
808+
791809
// addDirectoryWatches recursively adds fsnotify watches on directories
792810
func (w *Watcher) addDirectoryWatches(root string) {
793811
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
@@ -846,6 +864,13 @@ func (w *Watcher) handleFsCreate(path string) {
846864
// New directory — add a watch so we catch files created inside it
847865
if info.IsDir() {
848866
w.fsWatcher.Add(path)
867+
// If claude_dir was just created, switch to full recursive watch
868+
if strings.HasPrefix(w.claudeDir, path) || path == w.claudeDir {
869+
if _, err := os.Stat(w.claudeDir); err == nil {
870+
w.addDirectoryWatches(w.claudeDir)
871+
_ = w.discoverActiveSessions()
872+
}
873+
}
849874
return
850875
}
851876

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
)
2525

2626
var (
27-
version = "0.3.0"
27+
version = "0.3.1"
2828
)
2929

3030
func main() {

0 commit comments

Comments
 (0)