返回 DeepSeek-Reasonix
native_tab_session.go
根目录 / desktop / native_tab_session.go
1 package main
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "reasonix/internal/agent"
8 "reasonix/internal/control"
9 "reasonix/internal/session"
10 "strings"
11 )
12
13 // nativeSessionSelection belongs to the durable source, including detached views.
14 type nativeSessionSelection struct {
15 SessionHeadID string `json:"sessionHeadId,omitempty"`
16 }
17
18 // A historical directory (or its retained JSONL alias) is represented by a
19 // bound runtime whose SessionPath is empty. Compare both store and identity;
20 // comparing only the path would rebuild that runtime on every admission.
21 func (a *App) controllerMatchesSessionPath(ctrl control.SessionAPI, path string) bool {
22 if path == "" || sessionRuntimeKey(ctrl.SessionPath()) == sessionRuntimeKey(path) {
23 return true
24 }
25 service, runtime, bound := exclusiveSessionBinding(ctrl)
26 if !bound {
27 return false
28 }
29 root, id := desktopSessionRoot(filepath.Dir(path)), agent.BranchID(path)
30 if nativeStoredDirectory(path) {
31 root, id = filepath.Dir(path), filepath.Base(path)
32 }
33 expected, err := a.historicalSessionService(root)
34 return err == nil && service == expected && runtime.Ref().SessionID == id
35 }
36
37 func nativeStoredDirectory(path string) bool {
38 info, err := os.Stat(path)
39 return err == nil && info.IsDir() && hasHistoricalSessionArtifacts(path)
40 }
41
42 func (a *App) sessionServiceForSource(sessionDir, sessionID, path, storedDir string) (*session.Service, error) {
43 if storedDir != "" {
44 return a.historicalSessionService(filepath.Dir(storedDir))
45 }
46 if sessionID == "" && path != "" {
47 return a.historicalSessionService(desktopSessionRoot(filepath.Dir(path)))
48 }
49 return a.desktopSessionService(sessionDir), nil
50 }
51
52 func (a *App) bindNativeDirectoryForTab(buildCtx context.Context, tab *WorkspaceTab, ctrl control.SessionAPI, storedLegacyDir, rootKey string, buildGeneration uint64) bool {
53 identity := ctrl.(control.IdentityLifecycle)
54 ref := session.SessionRef{HostID: localDesktopHostID, SessionID: filepath.Base(storedLegacyDir)}
55 if _, bindErr := identity.OpenSession(buildCtx, ref); bindErr != nil {
56 a.recordTabStartupFailure(tab, buildGeneration, a.ctx, friendlySessionLoadError(bindErr))
57 ctrl.Close()
58 a.releaseSharedHost(rootKey)
59 return false
60 }
61 a.mu.Lock()
62 if a.tabBuildSupersededLocked(tab, buildGeneration) {
63 a.mu.Unlock()
64 a.abandonSupersededBuild(tab, ctrl, rootKey, "")
65 return false
66 }
67 tab.SessionID, tab.SessionPath = "", storedLegacyDir
68 a.mu.Unlock()
69 tab.replaceTelemetry(loadTelemetry(storedLegacyDir+".telemetry.json"), sessionRuntimeKey(storedLegacyDir))
70 return true
71 }
72
73 func (a *App) validateNativeHeadLocked(path, headID string) error {
74 if owner := a.liveRuntimeTabMatchingLocked(nil, path); owner != nil && owner.SessionHeadID != headID {
75 return newSessionOperationError("busy", "Close the open head before opening another head of this historical session.")
76 }
77 return nil
78 }
79
80 func (a *App) nativeStartupSource(tab *WorkspaceTab, root, tabScope, tabWorkspaceRoot, tabTopicID, tabSessionPath string) (string, string, string) {
81 sessionDir := desktopSessionDir(root)
82 if tabScope == "global" {
83 sessionDir = desktopSessionDir(globalWorkspaceRoot())
84 }
85 topicID := strings.TrimSpace(tabTopicID)
86 pinnedPath, hasPinnedPath := pinnedTabSessionPathForBuild(tabScope, tabWorkspaceRoot, sessionDir, tabSessionPath)
87 if hasPinnedPath && agent.IsCleanupPending(pinnedPath) {
88 // Boot reconciliation may finish the pending deletion before the later
89 // resume step. Clear the local candidate now so the disappeared path is
90 // not mistaken for a deliberate empty placeholder afterward.
91 hasPinnedPath = false
92 pinnedPath = ""
93 }
94 catalogTopicPath := ""
95 if hasPinnedPath {
96 // A restored tab's exact path is already known state, not history
97 // discovery. Keep legacy-directory and empty placeholder paths usable
98 // while the catalog is still opening or rebuilding.
99 sessionDir = filepath.Dir(pinnedPath)
100 } else {
101 catalogTopicPath = a.catalogSessionPathForTopic(tabScope, tabWorkspaceRoot, topicID)
102 }
103 if !hasPinnedPath && catalogTopicPath != "" {
104 sessionDir = filepath.Dir(catalogTopicPath)
105 }
106 startupSessionPath := ""
107 if hasPinnedPath {
108 if !agent.IsCleanupPending(pinnedPath) {
109 startupSessionPath = pinnedPath
110 }
111 } else if catalogTopicPath != "" {
112 startupSessionPath = catalogTopicPath
113 }
114 if nativeStoredDirectory(tabSessionPath) {
115 startupSessionPath = tabSessionPath
116 sessionDir = filepath.Dir(tabSessionPath)
117 }
118 prepareStartupPinnedContext(tab, startupSessionPath, tabSessionPath)
119 storedLegacyDir := ""
120 if nativeStoredDirectory(startupSessionPath) {
121 storedLegacyDir = startupSessionPath
122 }
123 return sessionDir, startupSessionPath, storedLegacyDir
124 }
125
125 lines GO