- CLI holds a lock file from load to save, so concurrent commands can't
lose an update; stale locks from crashed runs are taken over
- load() renumbers duplicate ids from the old add() bug instead of
refusing the file
- save() keeps owner, group and setgid on the temp file, and falls back to
an in-place write for hard-linked files, files whose owner/group can't
be kept, and directories that aren't writable
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- add() refuses to create an id that load() would reject; the CLI reports it
- save() creates the temp file with the real file's mode (and O_EXCL), so a
private list is never briefly world-readable; one stat call; symlink
resolution inlined; comment states the rename trade-offs
- CLI rejects ids with leading zeros and id 0
- Tests for trimming, the bare 'todo' default, and the id limit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- load() rejects duplicate ids (left by the old add bug) and ids that aren't safe positive integers
- save() refuses files the user can't write, and follows dangling symlinks to their target
- CLI rejects ids beyond Number.MAX_SAFE_INTEGER
- Skip permission-based tests when running as root
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- save() follows symlinks, keeps permissions, uses a unique temp file and cleans it up on failure
- load() rejects entries that aren't {id, text, done}
- add() finds the max id with reduce (no spread limit)
- CLI accepts only plain digits as ids and reports save errors readably
- Ignore *.tmp
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- add() uses max id + 1 so ids are never reused after rm
- done/rm reject missing, non-numeric and unknown ids; add rejects empty text
- load() gives a readable error on bad JSON or non-list data
- save() writes a temp file and renames it
- CLI checks the command before loading and no longer relies on process.exit for ls
- Add regression tests for all of the above
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>