返回 DeepSeek-Reasonix
session_trash_reconcile.go
根目录 / desktop / session_trash_reconcile.go
1 package main
2
3 import (
4 "encoding/json"
5 "fmt"
6 "os"
7 "path/filepath"
8 "time"
9
10 "reasonix/internal/agent"
11 )
12
13 func reconcileDesktopTrashSessionArtifacts(dir, sessionPath, key string) error {
14 // Hold the removal guard across the whole move so no runtime can acquire
15 // the session (or save into it) while its artifacts are relocated; the
16 // lock sidecars are deleted atomically with the guard release.
17 guard, err := acquireSessionRemovalGuard(sessionPath)
18 if err != nil {
19 return err
20 }
21 return trashSessionArtifactsWithGuard(dir, sessionPath, key, guard)
22 }
23
24 func trashSessionArtifactsWithGuard(dir, sessionPath, key string, guard *agent.SessionRemovalGuard) error {
25 if guard == nil {
26 return errSessionBusyElsewhere
27 }
28 defer guard.Release()
29 itemDir := filepath.Join(sessionTrashPath(dir), key)
30 if info, err := os.Stat(itemDir); err == nil {
31 if !info.IsDir() {
32 return fmt.Errorf("session trash target is not a directory: %s", key)
33 }
34 trashPath := filepath.Join(itemDir, key)
35 if trashInfo, err := os.Stat(trashPath); err == nil && !trashInfo.IsDir() {
36 _, liveErr := os.Stat(sessionPath)
37 if liveErr != nil && !os.IsNotExist(liveErr) {
38 return liveErr
39 }
40 if liveErr == nil {
41 discardable, err := liveSessionContentDiscardable(sessionPath)
42 if err != nil {
43 return err
44 }
45 if discardable {
46 return removeDesktopSessionArtifactsWithGuard(sessionPath, guard)
47 }
48 matches, err := trashSessionMatchesLive(sessionPath, trashPath)
49 if err != nil {
50 return err
51 }
52 if matches {
53 return removeDesktopSessionArtifactsWithGuard(sessionPath, guard)
54 }
55 itemDir, err = reserveUniqueSessionTrashItemDir(dir, key)
56 if err != nil {
57 return err
58 }
59 }
60 } else if err != nil && !os.IsNotExist(err) {
61 return err
62 }
63 } else if os.IsNotExist(err) {
64 if err := os.MkdirAll(itemDir, 0o755); err != nil {
65 return err
66 }
67 } else {
68 return err
69 }
70 defer invalidateTopicSessionIndexForPath(sessionPath)
71 if err := invalidateTopicDirMarkers(dir); err != nil {
72 return err
73 }
74 for _, artifact := range sessionTrashArtifacts(sessionPath, key) {
75 if err := movePathIfExists(artifact.src, filepath.Join(itemDir, artifact.name)); err != nil {
76 return err
77 }
78 }
79 if err := trashSubagentArtifacts(dir, sessionPath, itemDir); err != nil {
80 return err
81 }
82 if err := guard.RemoveSidecarsAndRelease(); err != nil {
83 return err
84 }
85 meta := trashedSessionMeta{Key: key, DeletedAt: time.Now().UnixMilli()}
86 b, err := json.MarshalIndent(meta, "", " ")
87 if err != nil {
88 return err
89 }
90 if err := os.WriteFile(filepath.Join(itemDir, sessionTrashMetaFile), b, 0o644); err != nil {
91 return err
92 }
93 return agent.ClearCleanupPending(sessionPath)
94 }
95
95 lines GO