The README still described the binary as a highlights extractor, which has not
been the primary mode since snapshot was added.
Records the two constraints that only real hardware surfaced, because both cost
real time and neither is discoverable from a host build: the Elipsa's 4.9 kernel
predates statx, so Zig's File.stat and getEndPos fail as a bare
error.Unexpected after the snapshot is already written; and usize is 32-bit on
armv7, so a u64 stat size will not coerce. Also pins Zig to 0.15.2 rather than
"or later", since the 0.16 in pacman breaks the build, and notes that the host
build fails on CachyOS for reasons unrelated to this code.
Points at c0smere_devops/kobo-sync for deployment and operations rather than
duplicating them here — this repo is just the binary; the ingest service,
schema, trigger, monitoring and recovery runbook live with the rest of the
infrastructure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The watchdog was spawned inside snapshot.run, so legacy highlights mode ran
without it. That is the mode NickelMenu invokes, against the endpoint that
stopped responding and hung a run for 16 days — so the exact failure being
fixed was still reachable from the device's menu.
Moves the spawn into main, ahead of mode dispatch, so both paths are covered.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds `kb_exfiltrator snapshot <db> [endpoint] [timeout-secs]`, which uploads a
consistent copy of the whole database instead of just extracted highlights. The
server can then parse whatever it wants, so adding a new statistic never means
touching the device again.
Uses VACUUM INTO rather than copying the file. Nickel keeps the database in WAL
mode and recent commits live in KoboReader.sqlite-wal until a checkpoint, so
copying the bare .sqlite silently loses reading progress — measured at 19 hours
of drift on the live device. Copying all three files instead is non-atomic: a
checkpoint landing mid-copy yields a pre-checkpoint main file plus a post-reset
WAL, losing data with no error. VACUUM INTO runs in a read transaction, so it
sees WAL-resident commits and emits one compacted journal_mode=delete file.
Also fixes the failure mode that left a process hung for 16 days: the server
stopped responding and std.http.Client has no timeout, so the process blocked
forever while holding the SQLite handle open. Snapshot mode closes the database
before any network I/O, and a watchdog thread hard-exits after a deadline
covering the whole run (snapshotting can stall on a locked database too).
Two portability constraints, both specific to the Kobo Elipsa:
- Linux 4.9.77 predates statx (4.11). Zig's File.stat() and getEndPos() both
issue it, returning ENOSYS as a bare error.Unexpected — after the snapshot
is already written, so it presents as a post-write failure. readToEndAlloc
with no size hint uses plain read() calls instead.
- usize is 32-bit on armv7, so a u64 stat size will not coerce. Only the ARM
build catches this.
Legacy invocations are unchanged, so the existing NickelMenu item keeps working.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Add text cleaning to remove page reference numbers (e.g., "10After" -> "After")
- Implement cleanHighlightText() function with boundary detection
- Add NickelMenu configuration for UI integration
- Create sync wrapper scripts (with and without FBInk notifications)
- Add installation guides for Kobo deployment
- Include pointer/slice explanation examples for learning
Features:
- Extracts highlights from Kobo SQLite database
- Cleans page references from academic texts
- Computes SHA-256 hashes for deduplication
- POSTs JSON to Flask API endpoint
- Supports ARM static linking for Kobo hardware
- Optional FBInk notifications for user feedback
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add Highlight struct to represent bookmarks with owned memory
- Implement SHA-256 hashing for text and book identification
- Update SQL query to extract clean book filenames (removes path and fragment)
- Remove unused Annotation column from query
- Add CLAUDE.md for repository documentation
- Update .gitignore to exclude SQLite WAL files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>