fix(cli): floor watch-mode stat timestamps to integer ms

CLIWatchAdapter._toNodeFile passed chokidar's raw stats.ctimeMs/mtimeMs
straight through. On Linux those carry sub-millisecond precision (e.g.
1778511180024.462), so watch-mode file changes wrote non-integer
timestamps into the database.

The earlier floor fix (3f7bb047) covered the scan/stat adapters but missed
this watch path, which is the one the daemon actually uses at runtime.
Mobile clients then crash on such a document because Capacitor's
Filesystem.setTimes casts the value to a Java Long (ClassCastException:
Double cannot be cast to Long).

Floor ctimeMs/mtimeMs here, with a null guard so a partial stat still
falls back to Date.now(). Adds a regression test that a fractional stat is
floored.

Claude-Session: https://claude.ai/code/session_0123E9jVQrsgu3zb82Csuwhi
This commit is contained in:
Andrew Leech
2026-07-22 14:08:21 +10:00
parent f54d162ef9
commit 4393a49cba
2 changed files with 25 additions and 2 deletions
@@ -116,8 +116,10 @@ class CLIWatchAdapter implements IStorageEventWatchAdapter {
return {
path: path.relative(this.basePath, filePath).replace(/\\/g, "/") as FilePath,
stat: {
ctime: stats?.ctimeMs ?? Date.now(),
mtime: stats?.mtimeMs ?? Date.now(),
// Floor to integer milliseconds; Linux fs.Stats.*Ms carry sub-millisecond
// precision, and timestamps are stored as integer ms everywhere else.
ctime: Math.floor(stats?.ctimeMs ?? Date.now()),
mtime: Math.floor(stats?.mtimeMs ?? Date.now()),
size: stats?.size ?? 0,
type: "file",
},