返回 DeepSeek-Reasonix
persist.go
根目录 / internal / recovery / persist.go
1 package recovery
2
3 import (
4 "encoding/json"
5 "os"
6
7 "reasonix/internal/fileutil"
8 fileencoding "reasonix/internal/fileutil/encoding"
9 "reasonix/internal/store"
10 )
11
12 // PathFor returns the recovery state sidecar for a main session path.
13 // Example: session.jsonl → session.recovery.json
14 func PathFor(sessionPath string) string {
15 return store.SessionRecoveryState(sessionPath)
16 }
17
18 // SaveSnapshot writes the recovery gate state beside the session file.
19 func SaveSnapshot(sessionPath string, snap Snapshot) error {
20 path := PathFor(sessionPath)
21 if path == "" {
22 return nil
23 }
24 data, err := json.MarshalIndent(snap, "", " ")
25 if err != nil {
26 return err
27 }
28 // Failure excerpts and command arguments may contain project-sensitive
29 // details. Publish atomically with owner-only permissions so concurrent
30 // root/sub-agent snapshots never expose a truncated JSON document.
31 return fileutil.AtomicWriteFile(path, data, 0o600)
32 }
33
34 // LoadSnapshot reads a previously saved recovery gate state.
35 // Missing files return an empty snapshot and nil error.
36 func LoadSnapshot(sessionPath string) (Snapshot, error) {
37 path := PathFor(sessionPath)
38 if path == "" {
39 return Snapshot{}, nil
40 }
41 data, err := fileencoding.ReadFileUTF8(path)
42 if err != nil {
43 if os.IsNotExist(err) {
44 return Snapshot{}, nil
45 }
46 return Snapshot{}, err
47 }
48 var snap Snapshot
49 if err := json.Unmarshal(data, &snap); err != nil {
50 return Snapshot{}, err
51 }
52 if snap.Tasks == nil {
53 snap.Tasks = map[string]*TaskState{}
54 }
55 return snap, nil
56 }
57
57 lines GO