mcp/pkg/mcp/agentic/write_atomic.go
Snider 8f3afaa42a refactor(mcp): migrate stdlib imports to core/go primitives + upgrade go-sdk v1.5.0
- 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>
2026-04-08 22:03:52 +01:00

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
}