Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func runInteractiveStreaming(cfg cmd.Config, from, until *time.Time) {
combined := cfg.MultiAgent()

cache := source.LoadPIDCache()
metaCache := source.LoadMetaCache()

var wg sync.WaitGroup
wg.Add(1)
Expand Down Expand Up @@ -110,7 +111,7 @@ func runInteractiveStreaming(cfg cmd.Config, from, until *time.Time) {
loadWg.Add(1)
go func() {
defer loadWg.Done()
err := source.LoadClaudeStream(cfg.PathFilter, strictMatch, cfg.Verbose, emitSession)
err := source.LoadClaudeStreamWithCache(cfg.PathFilter, strictMatch, cfg.Verbose, emitSession, metaCache)
if err != nil {
emitError("Claude", err)
}
Expand Down Expand Up @@ -168,7 +169,7 @@ func runInteractiveStreaming(cfg cmd.Config, from, until *time.Time) {
}
}()

session, err := picker.RunStreaming(stream, combined, cache)
session, err := picker.RunStreaming(stream, combined, cache, metaCache)
wg.Wait()
if err != nil {
fmt.Fprintf(os.Stderr, "picker error: %v\n", err)
Expand Down
20 changes: 13 additions & 7 deletions picker/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ type Model struct {
tickCount int // total tick count, drives spinner frames
activeConfs map[string]activeConf // sessions with a running process: guessed or confirmed

pidCache *source.PIDCache // persistent pid→sessionID mapping
pidCache *source.PIDCache // persistent pid→sessionID mapping
metaCache *source.MetaCache // updated by applyRefresh so cold-start reads fresh metadata
procs []source.ProcInfo // running procs snapshot from startup (cwd→proc index)

// matchIdx maps session ID to per-field matched rune offsets populated by applyFilter.
Expand All @@ -171,7 +172,7 @@ type Model struct {
sgrBuf string // accumulates partial SGR mouse fragment split by ESC-disambiguation timer
}

func newModel(sessions []source.Session, combined bool, w *watcher.Watcher, cache *source.PIDCache) Model {
func newModel(sessions []source.Session, combined bool, w *watcher.Watcher, cache *source.PIDCache, metaCache *source.MetaCache) Model {
ti := textinput.New()
ti.Prompt = ""
ti.Placeholder = " search query"
Expand Down Expand Up @@ -210,6 +211,7 @@ func newModel(sessions []source.Session, combined bool, w *watcher.Watcher, cach
w: w,
activeConfs: activeConfs,
pidCache: cache,
metaCache: metaCache,
procs: procs,
}
}
Expand Down Expand Up @@ -1236,13 +1238,13 @@ func (m Model) View() string {
// The picker starts immediately with an empty session list (loading=true)
// and consumes batches from stream until a Done batch is received.
// combined=true shows the SRC column.
func RunStreaming(stream <-chan SessionBatch, combined bool, cache *source.PIDCache) (*source.Session, error) {
func RunStreaming(stream <-chan SessionBatch, combined bool, cache *source.PIDCache, metaCache *source.MetaCache) (*source.Session, error) {
home, _ := os.UserHomeDir()
baseDir := filepath.Join(home, ".claude", "projects")

w, _ := watcher.New(baseDir)

m := newModel(nil, combined, w, cache)
m := newModel(nil, combined, w, cache, metaCache)
m.loading = true
m.streamCh = stream
firstViewLogged.Store(false)
Expand Down Expand Up @@ -1277,13 +1279,13 @@ func RunStreaming(stream <-chan SessionBatch, combined bool, cache *source.PIDCa
// Run starts the interactive session picker and returns the chosen session,
// or nil if the user cancelled. combined=true shows the SRC column.
// statusText/statusIsErr set the initial bottom status bar content.
func Run(sessions []source.Session, combined bool, cache *source.PIDCache, statusText string, statusIsErr bool) (*source.Session, error) {
func Run(sessions []source.Session, combined bool, cache *source.PIDCache, metaCache *source.MetaCache, statusText string, statusIsErr bool) (*source.Session, error) {
home, _ := os.UserHomeDir()
baseDir := filepath.Join(home, ".claude", "projects")

w, _ := watcher.New(baseDir) // failure degrades to poll-only; w is never nil

m := newModel(sessions, combined, w, cache)
m := newModel(sessions, combined, w, cache, metaCache)
m.statusText = statusText
m.statusIsErr = statusIsErr
firstViewLogged.Store(false)
Expand Down Expand Up @@ -1328,7 +1330,7 @@ func (m *Model) applyRefresh(paths []string) {
anchorClient, anchorID := m.cursorAnchor()

for _, path := range paths {
updated, err := source.ReloadSession(path, false)
updated, err := source.ReloadSession(path, false, m.metaCache)
if err != nil {
continue
}
Expand Down Expand Up @@ -1376,6 +1378,10 @@ func (m *Model) applyRefresh(paths []string) {
m.updateMaxColOffset()

m.restoreCursor(anchorClient, anchorID)

if m.metaCache != nil {
_ = m.metaCache.Save()
}
}

// applySessionBatch upserts the sessions in batch into m.sessions by (Client, ID),
Expand Down
Loading