jsonutil

package
v0.10.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package jsonutil provides JSON utilities with consistent formatting.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateTempIn added in v0.10.4

func CreateTempIn(root *os.Root, name string) (*os.File, string, error)

CreateTempIn creates a uniquely named, exclusively created temp file next to name inside root, and returns it with its root-relative name. It is the os.Root counterpart to os.CreateTemp, which has no Root form.

O_EXCL rather than a fixed "<name>.tmp": concurrent hook processes write the same session and checkpoint files, and a shared temp path corrupts whichever write lands second.

func IsTempName added in v0.10.4

func IsTempName(name string) bool

IsTempName reports whether name was produced by CreateTempIn.

It exists because an atomic write leaves its temp file in the SAME directory as its target, and one of those directories — .entire/metadata/<session> — is walked wholesale into every checkpoint tree. A hook killed between CreateTempIn and Rename (an agent's hook timeout, Codex's session-end process tree kill, a crash) leaves the temp behind, and without this the walk redacts it, commits it, and pushes it on every checkpoint from then on.

The match is the whole shape CreateTempIn produces — "<base>.<16 hex>.tmp" — not a bare ".tmp" suffix, so a file a user or an agent legitimately named something.tmp is still captured.

func MarshalIndentWithNewline

func MarshalIndentWithNewline(v any, prefix, indent string) ([]byte, error)

MarshalIndentWithNewline is like json.MarshalIndent but adds a trailing newline. This ensures JSON files have proper POSIX line endings.

func MarshalWithNoHTMLEscape added in v0.5.6

func MarshalWithNoHTMLEscape(v any) ([]byte, error)

MarshalWithNoHTMLEscape is like json.Marshal but disables HTML escaping.

func WriteFileAtomic added in v0.6.2

func WriteFileAtomic(filePath string, data []byte, perm fs.FileMode) error

WriteFileAtomic writes data to filePath atomically by writing to a temp file in the same directory and renaming it into place. A crash or signal mid-write leaves the original file intact rather than a truncated partial — important for config files like .entire/settings.json that callers expect to remain parseable across interrupted writes.

The rename is what provides that, and it is deliberately NOT paired with an fsync. The property every caller here needs is "a reader never sees a torn file", which the rename gives on its own. fsync buys something different — that the bytes survive a power loss — and nothing written through this function is worth that price: settings, session state, caches and manifests are all reconstructible, and losing the last write to one costs a repeated command, not data. The price is not small, measured at 14x on a 4KiB payload (1.02ms against 71µs), and session state is written on every agent hook.

What is given up, precisely: on a filesystem that reorders the rename ahead of the data write, a hard power loss can leave a zero-length file where the old contents used to be. Every reader here treats an unparseable or empty file as absent and rebuilds it.

perm is applied to the temp file via Chmod before rename so the final file lands with the requested permission regardless of the temp file's default.

func WriteFileAtomicIn added in v0.10.4

func WriteFileAtomicIn(root *os.Root, name string, data []byte, perm fs.FileMode) error

WriteFileAtomicIn is WriteFileAtomic confined to root: name is resolved relative to root by the kernel, so neither the temp file nor the rename target can escape it. It is the form every .entire writer uses, because the names under .entire are built from agent-supplied session and tool-use IDs.

The sequence is identical to WriteFileAtomic — write, close, chmod, rename, and no fsync — and the same reasoning applies to each step. Two differences: os.Root has no CreateTemp, so the unique temp name is drawn here and created with O_EXCL (a collision retries rather than clobbering a concurrent writer's temp file); and the parent directory is opened once, up front, with every component checked for symlinks, so the temp file, the chmod and the rename all act on the same pinned directory rather than re-resolving name each time.

name must be a valid slash-separated path beneath root (see fs.ValidPath): "./x", "x//y" and "x/./y" are rejected rather than cleaned.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL