返回 DeepSeek-Reasonix
historical_archive_removed_topic.go
根目录 / desktop / historical_archive_removed_topic.go
1 package main
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7
8 "reasonix/desktop/internal/workspacestate"
9 "reasonix/internal/agent"
10 "reasonix/internal/store"
11 )
12
13 // retireRemovedSourceTopic makes clearing a source whose session is already
14 // deleted durable: its legacy topic joins deletedTopics, which every sidebar
15 // projection honours. A topic that anything else still carries stays listed.
16 func retireRemovedSourceTopic(state workspacestate.State, source historicalSource) error {
17 if source.format == "canonical" {
18 return nil
19 }
20 meta, ok, err := agent.LoadBranchMeta(source.path)
21 if err != nil || !ok {
22 return err
23 }
24 topicID := strings.TrimSpace(meta.TopicID)
25 if topicID == "" || topicHasSurvivingOwner(state, topicID) {
26 return nil
27 }
28 shared, err := legacyTopicSharedBeyond(state, source.path, topicID)
29 if err != nil || shared {
30 return err
31 }
32 return removeTopicFromProjectsFile(topicID)
33 }
34
35 func topicHasSurvivingOwner(state workspacestate.State, topicID string) bool {
36 for id, presentation := range state.Presentation {
37 if presentation.TopicID == topicID && state.SessionStates[id].Lifecycle != workspacestate.Deleted {
38 return true
39 }
40 }
41 for _, pending := range state.PendingCreates {
42 if pending.Presentation != nil && pending.Presentation.TopicID == topicID {
43 return true
44 }
45 }
46 return false
47 }
48
49 // legacyTopicSharedBeyond reports whether another transcript beside path
50 // carries topicID without being adopted by a deleted session. Unreadable
51 // metadata cannot prove the topic is unshared.
52 func legacyTopicSharedBeyond(state workspacestate.State, path, topicID string) (bool, error) {
53 entries, err := os.ReadDir(filepath.Dir(path))
54 if err != nil {
55 return false, err
56 }
57 for _, entry := range entries {
58 sibling := filepath.Join(filepath.Dir(path), entry.Name())
59 if entry.IsDir() || !store.IsSessionTranscriptName(entry.Name()) || sameDesktopPath(sibling, path) {
60 continue
61 }
62 meta, ok, err := agent.LoadBranchMeta(sibling)
63 if err != nil || !ok {
64 return true, nil
65 }
66 if strings.TrimSpace(meta.TopicID) == topicID && !sourceAdoptedByDeletedSession(state, sibling) {
67 return true, nil
68 }
69 }
70 return false, nil
71 }
72
73 func sourceAdoptedByDeletedSession(state workspacestate.State, path string) bool {
74 for _, mapping := range state.SourceMappings {
75 if sameDesktopPath(mapping.Path, path) && state.SessionStates[mapping.SessionID].Lifecycle == workspacestate.Deleted {
76 return true
77 }
78 }
79 return false
80 }
81
81 lines GO