writeFileAtomic: exclusive-create random-suffix temp + rename carrying the caller-stated mode; settings-local persistSection now consumes it. The credentials-local store shares it next.
dsh-atomic-write
English | 中文
Zero-dependency atomic file replacement shared by file-backed stores that must never leave partial, symlink-hijacked, or wider-than-intended content on disk — the user-settings document (dsh-settings-local) and the credentials store (dsh-credentials-local).
Surface
import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
await writeFileAtomic('/home/u/.dsh/settings.yaml', text, { mode: 0o600 })
One export. The contract, in the order failures would exploit it:
- Exclusive-create temp (
wx, random suffix): the open refuses to follow a symlink planted at a guessable temp path. - The fresh inode carries
modethrough the rename: replacing a wider-permission file narrows it without a chmod race.modeis required so the permission decision stays visible at every call site (subject to the process umask, like every fresh inode). renamereplaces a symlinked target itself, never writing through to its referent.- Same-directory sibling keeps the rename on one filesystem, so the swap stays atomic.
- Parent directories are created; on any failure the temp is removed and the failure rethrown; readers observe either the old or the new complete content.
Model Experience
None, as this is a pure filesystem primitive; nothing here reaches a model request.
Known Limitations and Deferred Work
- Atomic, not durable — no
fsyncof the file or its directory, so after a crash the rename may be observed unwound. The file-backed stores here re-read and republish on boot, keeping durability the caller's policy. - String content only — no
Bufferor stream form until a consumer needs one.