返回 DeepSeek-Reasonix
write_recovery.go
根目录 / internal / tool / builtin / write_recovery.go
1 package builtin
2
3 import (
4 "context"
5 "crypto/sha256"
6 "fmt"
7 "os"
8 "path/filepath"
9
10 "reasonix/internal/tool"
11 )
12
13 func contentDigest(content string) string { return fmt.Sprintf("%x", sha256.Sum256([]byte(content))) }
14 func resolvedWritePath(path string) (string, error) {
15 if resolved, err := filepath.EvalSymlinks(path); err == nil {
16 return resolved, nil
17 }
18 if filepath.Dir(path) == path {
19 return "", fmt.Errorf("cannot resolve write root")
20 }
21 parent, err := resolvedWritePath(filepath.Dir(path))
22 if err != nil {
23 return "", err
24 }
25 return filepath.Join(parent, filepath.Base(path)), nil
26 }
27 func (s editSource) recordWrite(ctx context.Context, path, content, route string, overlay FileOverlay) error {
28 if !tool.HasWriteIntentHook(ctx) {
29 return nil
30 }
31 host, err := os.Hostname()
32 if err != nil {
33 return err
34 }
35 resolved, err := resolvedWritePath(path)
36 if err != nil {
37 return err
38 }
39 transport := ""
40 if id, ok := overlay.(interface{ RecoveryIdentity() string }); ok {
41 transport = id.RecoveryIdentity()
42 }
43 return tool.RecordWriteIntent(ctx, tool.FileWriteIntent{TransportID: transport, Version: 1, Path: path, Host: host, Route: route, ResolvedPath: resolved, Before: contentDigest(s.content), After: contentDigest(content), Encoding: fmt.Sprint(s.enc), Existed: s.id.existed})
44 }
45 func verifyFileWrite(ctx context.Context, overlay FileOverlay, intent tool.FileWriteIntent) tool.WriteVerification {
46 host, err := os.Hostname()
47 if err != nil || intent.Version != 1 || host != intent.Host || !filepath.IsAbs(intent.Path) {
48 return tool.WriteUnknown
49 }
50 resolved, err := resolvedWritePath(intent.Path)
51 if err != nil || resolved != intent.ResolvedPath {
52 return tool.WriteUnknown
53 }
54 var content, encoding string
55 switch intent.Route {
56 case "overlay":
57 // Without a stable transport identity, an overlay cannot prove that it
58 // still addresses the same editor/remote host after restart.
59 identity, ok := overlay.(interface{ RecoveryIdentity() string })
60 if !ok || intent.TransportID == "" || identity.RecoveryIdentity() != intent.TransportID {
61 return tool.WriteUnknown
62 }
63 value, ok := overlay.ReadTextFile(ctx, intent.Path)
64 if !ok {
65 return tool.WriteUnknown
66 }
67 content, encoding = value, intent.Encoding
68 case "disk":
69 value, enc, readErr := readFileEncoded(intent.Path)
70 if readErr != nil {
71 return tool.WriteUnknown
72 }
73 content, encoding = value, fmt.Sprint(enc)
74 default:
75 return tool.WriteUnknown
76 }
77 if encoding != intent.Encoding {
78 return tool.WriteConflict
79 }
80 digest := contentDigest(content)
81 if digest == intent.After {
82 return tool.WriteSatisfied
83 }
84 if digest == intent.Before {
85 return tool.WriteUnchanged
86 }
87 return tool.WriteConflict
88 }
89
90 func (w writeFile) VerifyWrite(ctx context.Context, intent tool.FileWriteIntent) tool.WriteVerification {
91 if err := confineWrite(ctx, effectiveWriteRoots(ctx, w.rootSet, w.roots), w.guard, w.managed, intent.Path); err != nil {
92 return tool.WriteUnknown
93 }
94 return verifyFileWrite(ctx, w.overlay, intent)
95 }
96
97 func (e editFile) VerifyWrite(ctx context.Context, intent tool.FileWriteIntent) tool.WriteVerification {
98 if err := confineWrite(ctx, effectiveWriteRoots(ctx, e.rootSet, e.roots), e.guard, e.managed, intent.Path); err != nil {
99 return tool.WriteUnknown
100 }
101 return verifyFileWrite(ctx, e.overlay, intent)
102 }
103
104 func (m multiEdit) VerifyWrite(ctx context.Context, intent tool.FileWriteIntent) tool.WriteVerification {
105 if err := confineWrite(ctx, effectiveWriteRoots(ctx, m.rootSet, m.roots), m.guard, m.managed, intent.Path); err != nil {
106 return tool.WriteUnknown
107 }
108 return verifyFileWrite(ctx, m.overlay, intent)
109 }
110
111 func (n notebookEdit) VerifyWrite(ctx context.Context, intent tool.FileWriteIntent) tool.WriteVerification {
112 if err := confineWrite(ctx, effectiveWriteRoots(ctx, n.rootSet, n.roots), n.guard, n.managed, intent.Path); err != nil {
113 return tool.WriteUnknown
114 }
115 return verifyFileWrite(ctx, n.overlay, intent)
116 }
117
118 func (d deleteRange) VerifyWrite(ctx context.Context, intent tool.FileWriteIntent) tool.WriteVerification {
119 if err := confineWrite(ctx, effectiveWriteRoots(ctx, d.rootSet, d.roots), d.guard, d.managed, intent.Path); err != nil {
120 return tool.WriteUnknown
121 }
122 return verifyFileWrite(ctx, d.overlay, intent)
123 }
124
125 func (d deleteSymbol) VerifyWrite(ctx context.Context, intent tool.FileWriteIntent) tool.WriteVerification {
126 if err := confineWrite(ctx, effectiveWriteRoots(ctx, d.rootSet, d.roots), d.guard, d.managed, intent.Path); err != nil {
127 return tool.WriteUnknown
128 }
129 return verifyFileWrite(ctx, d.overlay, intent)
130 }
131
131 lines GO