返回 DeepSeek-Reasonix
recovery_groups.go
根目录 / internal / sessioncatalog / recovery_groups.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "path/filepath"
6 )
7
8 // RecoveryGroup is a catalog projection of one proved recovery lineage. It is
9 // diagnostic input only; destructive callers must revalidate file contents and
10 // locks through agent helpers before moving anything.
11 type RecoveryGroup struct {
12 ID string `json:"id"`
13 Directory string `json:"directory"`
14 RootPath string `json:"rootPath,omitempty"`
15 CanonicalPath string `json:"canonicalPath,omitempty"`
16 State string `json:"state"`
17 Members []SessionRecord `json:"members"`
18 }
19
20 // ListRecoveryGroups returns every indexed recovery lineage in directory. All
21 // slices are initialized for stable CLI/desktop JSON contracts.
22 func (c *Catalog) ListRecoveryGroups(ctx context.Context, directory string) ([]RecoveryGroup, error) {
23 out := []RecoveryGroup{}
24 if c == nil || c.db == nil {
25 return out, nil
26 }
27 directory = cleanCatalogAccessPath(directory)
28 rows, err := c.db.QueryContext(ctx, `SELECT `+sessionSelectColumns+` FROM catalog_sessions
29 WHERE directory_key=? AND recovered=1 AND recovery_group_id<>'' AND missing_since=0
30 ORDER BY recovery_group_id,path`, c.pathKey(directory))
31 if err != nil {
32 return out, err
33 }
34 defer rows.Close()
35 byID := map[string]int{}
36 for rows.Next() {
37 record, err := scanSession(rows)
38 if err != nil {
39 return []RecoveryGroup{}, err
40 }
41 index, ok := byID[record.RecoveryGroupID]
42 if !ok {
43 index = len(out)
44 byID[record.RecoveryGroupID] = index
45 out = append(out, RecoveryGroup{ID: record.RecoveryGroupID, Directory: directory,
46 RootPath: filepath.Join(directory, record.RecoveryGroupID+".jsonl"), Members: []SessionRecord{}})
47 }
48 group := &out[index]
49 group.Members = append(group.Members, record)
50 if record.RecoveryCanonical && record.RecoveryRole == RecoveryRolePreferred {
51 group.CanonicalPath = record.Path
52 group.State = "preferred"
53 } else if record.RecoveryCanonical && record.RecoveryRole == RecoveryRoleAdopted {
54 group.CanonicalPath = record.Path
55 group.State = "adopted"
56 } else if group.State == "" && record.RecoveryRole == RecoveryRoleDiverged {
57 group.State = "diverged"
58 }
59 }
60 if err := rows.Err(); err != nil {
61 return []RecoveryGroup{}, err
62 }
63 for index := range out {
64 if out[index].State == "" {
65 out[index].State = "repairing"
66 }
67 }
68 return out, nil
69 }
70
70 lines GO