Why: token budget let the current tool batch run, compaction could split a tool pair or race an append, writes were not crash-atomic, and several MCP and session edges only existed as comments. Evidence: GOWORK=off go test -count=1 -race ./runtime/ ./runtime/llm/ ./runtime/session/ ./runtime/tools/ ./runtime/mcp/ ./adapters/native/ ./adapters/intentgate/ passed, including the TestR2* cases for budget, replacement, cancel, compaction, SSE, UTF-8, schema, MCP retry, session terminate, poison reload, and registry reload. Impact: over-budget tool calls are skipped and paired; Stop.Replacement is appended to the session; the intent gate can follow Registry.Reload. Refs: N5, N6, N7, N8, N9, N11, N12, N15, N16, N17, N18, N19, N21, I9 Co-authored-by: Cursor <cursoragent@cursor.com>
31 lines
577 B
Go
31 lines
577 B
Go
package tools
|
|
|
|
import "os"
|
|
|
|
func atomicWriteFile(path string, data []byte, mode os.FileMode) error {
|
|
tmp := path + ".tmp"
|
|
f, err := os.OpenFile(tmp, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := f.Write(data); err != nil {
|
|
_ = f.Close()
|
|
_ = os.Remove(tmp)
|
|
return err
|
|
}
|
|
if err := f.Sync(); err != nil {
|
|
_ = f.Close()
|
|
_ = os.Remove(tmp)
|
|
return err
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
_ = os.Remove(tmp)
|
|
return err
|
|
}
|
|
if err := os.Rename(tmp, path); err != nil {
|
|
_ = os.Remove(tmp)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|