| 1 | package main |
| 2 | |
| 3 | // workspaceEntryConversation selects an existing conversation without changing |
| 4 | // its identity or allocating a new one. Runtime selection remains in the normal |
| 5 | // activation path; legacy sources keep their exact path/head selector. |
| 6 | func (a *App) workspaceEntryConversation(root string) (string, string, error) { |
| 7 | a.mu.RLock() |
| 8 | for _, id := range a.orderedTabIDsLocked() { |
| 9 | tab := a.tabs[id] |
| 10 | if tabInWorkspace(tab, root) && topicTabReusableLocked(tab) { |
| 11 | topicID, path := tab.TopicID, tab.SessionPath |
| 12 | if tab.SessionID != "" { |
| 13 | path = sessionRoute(tab.SessionID) |
| 14 | } |
| 15 | if topicID != "" || path != "" { |
| 16 | a.mu.RUnlock() |
| 17 | return topicID, path, nil |
| 18 | } |
| 19 | } |
| 20 | } |
| 21 | a.mu.RUnlock() |
| 22 | page, err := a.ListProjectTopics(ProjectTopicPageRequest{Scope: "project", WorkspaceRoot: root, Limit: 1, SortMode: "updated", GroupFilter: "all"}) |
| 23 | if err != nil { |
| 24 | return "", "", err |
| 25 | } |
| 26 | defer a.ReleaseReadSnapshot(page.SnapshotID) |
| 27 | if len(page.Items) == 0 { |
| 28 | return "", "", nil |
| 29 | } |
| 30 | node := page.Items[0] |
| 31 | path := node.SessionPath |
| 32 | if node.Session != nil { |
| 33 | path = sessionRoute(node.Session.SessionID) |
| 34 | } else if node.Source != nil { |
| 35 | path = nativeSessionSourceRoute(node.Source) |
| 36 | } |
| 37 | return node.TopicID, path, nil |
| 38 | } |
| 39 |