Skip to content

Commit a21a427

Browse files
authored
Merge pull request #204 from shelltime/fix/cc-statusline-git-info-cache
fix(daemon): cache git info to avoid cc statusline timeout
2 parents 40aba69 + 0a4c29b commit a21a427

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

daemon/cc_info_timer.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type CCInfoCache struct {
2121
FetchedAt time.Time
2222
}
2323

24+
2425
// CCInfoTimerService manages lazy-fetching of CC info data
2526
type CCInfoTimerService struct {
2627
config *model.ShellTimeConfig
@@ -35,6 +36,10 @@ type CCInfoTimerService struct {
3536
ticker *time.Ticker
3637
stopChan chan struct{}
3738
wg sync.WaitGroup
39+
40+
// Git info (single active working directory, fetched by timer)
41+
activeWorkingDir string
42+
gitInfo GitInfo
3843
}
3944

4045
// NewCCInfoTimerService creates a new CC info timer service
@@ -117,9 +122,11 @@ func (s *CCInfoTimerService) stopTimer() {
117122
s.ticker.Stop()
118123
s.timerRunning = false
119124

120-
// Clear active ranges when stopping
125+
// Clear active ranges and git info when stopping
121126
s.mu.Lock()
122127
s.activeRanges = make(map[CCInfoTimeRange]bool)
128+
s.activeWorkingDir = ""
129+
s.gitInfo = GitInfo{}
123130
s.mu.Unlock()
124131

125132
slog.Info("CC info timer stopped due to inactivity")
@@ -131,6 +138,7 @@ func (s *CCInfoTimerService) timerLoop() {
131138

132139
// Fetch immediately on start
133140
s.fetchActiveRanges(context.Background())
141+
s.fetchGitInfo()
134142

135143
for {
136144
select {
@@ -143,6 +151,7 @@ func (s *CCInfoTimerService) timerLoop() {
143151
return
144152
}
145153
s.fetchActiveRanges(context.Background())
154+
s.fetchGitInfo()
146155

147156
case <-s.stopChan:
148157
return
@@ -262,3 +271,40 @@ func (s *CCInfoTimerService) fetchCCInfo(ctx context.Context, timeRange CCInfoTi
262271
TotalSessionSeconds: analytics.TotalSessionSeconds,
263272
}, nil
264273
}
274+
275+
// GetCachedGitInfo marks the working directory as active and returns cached git info.
276+
// Git info is fetched by the background timer, so first call may return empty.
277+
func (s *CCInfoTimerService) GetCachedGitInfo(workingDir string) GitInfo {
278+
if workingDir == "" {
279+
return GitInfo{}
280+
}
281+
282+
s.mu.Lock()
283+
s.activeWorkingDir = workingDir
284+
info := s.gitInfo
285+
s.mu.Unlock()
286+
287+
return info
288+
}
289+
290+
// fetchGitInfo fetches git info for the active working directory
291+
func (s *CCInfoTimerService) fetchGitInfo() {
292+
s.mu.RLock()
293+
workingDir := s.activeWorkingDir
294+
s.mu.RUnlock()
295+
296+
if workingDir == "" {
297+
return
298+
}
299+
300+
info := GetGitInfo(workingDir)
301+
302+
s.mu.Lock()
303+
s.gitInfo = info
304+
s.mu.Unlock()
305+
306+
slog.Debug("Git info updated",
307+
slog.String("workingDir", workingDir),
308+
slog.String("branch", info.Branch),
309+
slog.Bool("dirty", info.Dirty))
310+
}

daemon/socket.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,8 @@ func (p *SocketHandler) handleCCInfo(conn net.Conn, msg SocketMessage) {
216216
cache := p.ccInfoTimer.GetCachedCost(timeRange)
217217
p.ccInfoTimer.NotifyActivity()
218218

219-
// Get git info (fast, no caching needed since it changes frequently)
220-
gitInfo := GetGitInfo(workingDir)
219+
// Get git info (cached to avoid slow worktree.Status() on large repos)
220+
gitInfo := p.ccInfoTimer.GetCachedGitInfo(workingDir)
221221

222222
response := CCInfoResponse{
223223
TotalCostUSD: cache.TotalCostUSD,

0 commit comments

Comments
 (0)