返回 DeepSeek-Reasonix
session_history_listing.go
根目录 / desktop / session_history_listing.go
1 package main
2
3 import (
4 "reasonix/internal/config"
5 "reasonix/internal/sessioncatalog"
6 "sort"
7 )
8
9 // ListSessions returns the saved sessions newest-first for the history panel,
10 // marking the one the current conversation is writing to and attaching any
11 // user-chosen titles.
12 func (a *App) ListSessions() []SessionMeta {
13 dir := a.activeSessionDir()
14 active := a.activeSessionPath(dir)
15 if tab := a.activeTab(); tab != nil {
16 active = tab.currentSessionIdentity()
17 }
18 return a.listSessionsFromDir(dir, active)
19 }
20
21 // ListSessionsForTab returns sessions from the directory owned by tabID. Task
22 // Monitor uses this stable target after asynchronous control lookups so a tab
23 // switch cannot redirect the eventual session lookup to another workspace.
24 func (a *App) ListSessionsForTab(tabID string) []SessionMeta {
25 target, err := a.taskMonitorTargetForTab(tabID)
26 if err != nil {
27 return []SessionMeta{}
28 }
29 active := target.sessionPath
30 if tab := a.tabByID(tabID); tab != nil {
31 active = tab.currentSessionIdentity()
32 }
33 return a.listSessionsFromDir(target.sessionDir, active)
34 }
35
36 func (a *App) listSessionsFromDir(dir, active string) []SessionMeta {
37 v3 := a.listCanonicalSessionsFromDir(dir, active)
38 state, stateErr := a.workspaceRegistry().Load(a.bootContext())
39 if stateErr != nil {
40 return v3
41 }
42 scope, root := "", ""
43 if sameDesktopPath(dir, config.SessionDir()) || sameDesktopPath(dir, desktopSessionDir(globalWorkspaceRoot())) {
44 scope = "global"
45 } else {
46 for _, target := range a.sessionCatalogTargets() {
47 if sameDesktopPath(dir, target.Path) {
48 scope, root = target.Scope, target.WorkspaceRoot
49 break
50 }
51 }
52 }
53 historical := a.historicalCanonicalTopics(scope, root, state)
54 saved, _ := readHistoricalSidecar()
55 applyHistoricalPresentations(historical, saved)
56 for _, node := range historical {
57 v3 = append(v3, SessionMeta{Source: node.Source, Historical: true, PreparationStatus: node.PreparationStatus,
58 Path: node.SessionPath, Title: node.Label, TopicID: node.TopicID, Scope: scope, WorkspaceRoot: root,
59 Preview: node.Preview, Turns: node.Turns, TurnsState: node.TurnsState,
60 CreatedAt: node.CreatedAt, LastActivityAt: node.LastActivityAt, ModTime: node.LastActivityAt})
61 }
62 adopted := adoptedSourceRows(state)
63 catalog := a.sessionCatalog.Load()
64 if catalog == nil {
65 return v3
66 }
67 target := sessioncatalog.DirectoryTarget{Path: dir, Scope: "global"}
68 for _, candidate := range a.sessionCatalogTargets() {
69 if sameProjectRoot(candidate.Path, dir) {
70 target = candidate
71 break
72 }
73 }
74 records, err := listCatalogSessionsForDirectory(a.bootContext(), catalog, target, dir)
75 if err != nil {
76 return v3
77 }
78 open := a.openSessionPaths(dir)
79 channelRoutes := channelSessionRoutesForDir(dir)
80 out := make([]SessionMeta, 0, len(records)+len(v3))
81 out = append(out, v3...)
82 for _, record := range records {
83 if adopted[sessionRuntimeKey(record.Path)] {
84 continue
85 }
86 _, isOpen := open[record.Path]
87 meta := sessionMetaFromCatalog(record, record.Path == active, isOpen)
88 if route, ok := channelRoutes[sessionRuntimeKey(record.Path)]; ok {
89 applyChannelSessionRoute(&meta, route)
90 }
91 for _, row := range expandSessionSourceRows(ProjectNode{SessionPath: record.Path}) {
92 if row.Source == nil {
93 out = append(out, meta)
94 continue
95 }
96 if adopted[projectNodeSessionKey(row)] {
97 continue
98 }
99 headMeta := meta
100 headMeta.Source = row.Source
101 headMeta.Historical, headMeta.HistoricalBranch = true, row.HistoricalBranch
102 headMeta.PreparationStatus = a.historicalPreparationStatus(row.Source.SourceKey)
103 if presentation := saved.Presentations[row.Source.SourceKey]; presentation.Title != "" {
104 headMeta.Title = presentation.Title
105 }
106 headMeta.Turns, headMeta.Preview = row.Turns, row.Preview
107 if row.LastActivityAt > 0 {
108 headMeta.LastActivityAt, headMeta.ModTime = row.LastActivityAt, row.LastActivityAt
109 }
110 if row.CreatedAt > 0 {
111 headMeta.CreatedAt = row.CreatedAt
112 }
113 headMeta.Current = sessionRuntimeKey(headMeta.Path) == sessionRuntimeKey(active)
114 out = append(out, headMeta)
115 }
116 }
117 sort.SliceStable(out, func(i, j int) bool { return out[i].LastActivityAt > out[j].LastActivityAt })
118 return out
119 }
120
120 lines GO