- Replace fmt/errors/strings/path/filepath with core.Sprintf, core.E, core.Contains, core.Path etc. across 16 files - Remove 'errors' import from bridge.go (core.Is/core.As) - Remove 'fmt' from transport_tcp.go, ide.go (core.Print, inline interface) - Remove 'strings' from notify.go, transport_http.go, tools_webview.go, process_notifications.go (core.Trim, core.HasPrefix, core.Lower etc.) - Upgrade go-sdk from v1.4.1 to v1.5.0 - Keep encoding/json for json.NewDecoder/MarshalIndent (no core equivalent) - Keep os/exec in agentic subsystem (needs go-process Action wiring) Co-Authored-By: Virgil <virgil@lethean.io>
51 lines
1 KiB
Go
51 lines
1 KiB
Go
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package agentic
|
|
|
|
import (
|
|
"os"
|
|
|
|
core "dappco.re/go/core"
|
|
coreio "dappco.re/go/core/io"
|
|
)
|
|
|
|
// writeAtomic writes content to path by staging it in a temporary file and
|
|
// renaming it into place.
|
|
//
|
|
// This avoids exposing partially written workspace files to agents that may
|
|
// read status, prompt, or plan documents while they are being updated.
|
|
func writeAtomic(path, content string) error {
|
|
dir := core.PathDir(path)
|
|
if err := coreio.Local.EnsureDir(dir); err != nil {
|
|
return err
|
|
}
|
|
|
|
tmp, err := os.CreateTemp(dir, "."+core.PathBase(path)+".*.tmp")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tmpPath := tmp.Name()
|
|
|
|
cleanup := func() {
|
|
_ = tmp.Close()
|
|
_ = os.Remove(tmpPath)
|
|
}
|
|
|
|
if _, err := tmp.WriteString(content); err != nil {
|
|
cleanup()
|
|
return err
|
|
}
|
|
if err := tmp.Sync(); err != nil {
|
|
cleanup()
|
|
return err
|
|
}
|
|
if err := tmp.Close(); err != nil {
|
|
_ = os.Remove(tmpPath)
|
|
return err
|
|
}
|
|
if err := os.Rename(tmpPath, path); err != nil {
|
|
_ = os.Remove(tmpPath)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|