feat(watch): impl poll mode#353
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces configurable file-watching backends, allowing users to choose between platform-native notifications, polling, or an automatic fallback mode. This is particularly useful for environments like network filesystems where native notifications may fail. The changes include updates to the configuration schema, documentation, and a refactor of the internal watcher logic to support multiple backends simultaneously. However, a critical bug was identified in the supervisor's main watch loop: the tokio::select! block will enter a 100% CPU busy loop if any watcher backend is uninitialized, as the branches return immediately instead of pending.
Greptile SummaryThis PR implements per-daemon Confidence Score: 5/5Safe to merge — no correctness or security issues found; all findings are style suggestions. Only P2 findings: submodule init ordering in mise.toml, runtime vs compile-time enforcement of the Auto-mode restriction in WatchFiles::new, and duplicated match arms. The core watcher loop logic is sound, the auto-fallback state machine handles creation failure and per-dir failure correctly, and watched_native_dirs/watched_poll_dirs are only assigned after target sets are adjusted to reflect what was actually registered. src/watch_files.rs — WatchMode::Auto runtime error and duplicated match arms; mise.toml — submodule init placement Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Loop iteration: get_all_watch_configs] --> B[Partition dirs by WatchMode]
B --> C{required_auto_dirs?}
C -- yes --> D{dir in auto_fallback_dirs?}
D -- yes --> E[→ target_poll_dirs]
D -- no --> F[→ target_native_dirs]
C -- no --> G[Skip]
F --> H[unwatch_removed_dirs native]
H --> I{native_wf exists?}
I -- no --> J[Create native WatchFiles]
J -- ok --> K[native_wf = Some]
J -- err --> L[Move all target_native → target_poll, clear target_native]
K --> M[watch_new_dirs native, returns new_fallback_dirs]
I -- yes --> M
M --> N{fallback dirs?}
N -- yes --> O[Remove from target_native, Add to target_poll, Record in auto_fallback_dirs]
O --> P[unwatch_removed_dirs poll]
L --> P
E --> P
P --> Q{poll_wf exists?}
Q -- no --> R[Create poll WatchFiles]
R -- ok --> S[poll_wf = Some]
R -- err --> T[clear target_poll]
S --> U[watch_new_dirs poll]
Q -- yes --> U
U --> V[watched_native = target_native, watched_poll = target_poll]
T --> V
V --> W[Prune stale auto_fallback_dirs]
W --> X{tokio::select!}
X -- native change --> Y[restart_for_changed_paths]
X -- poll change --> Z[restart_for_changed_paths]
X -- watch_interval timeout --> A
Reviews (11): Last reviewed commit: "feat(watch): impl poll mode" | Re-trigger Greptile |
27accf5 to
0e10e11
Compare
0f7fe59 to
1420edc
Compare
1420edc to
f990577
Compare
f990577 to
b8136c5
Compare
919f248 to
ce91300
Compare
ce91300 to
b41a2b0
Compare
## 🤖 New release * `pitchfork-cli`: 2.6.0 -> 2.7.0 <details><summary><i><b>Changelog</b></i></summary><p> <blockquote> ## [2.7.0](v2.6.0...v2.7.0) - 2026-04-26 ### Added - *(supervisor)* run daemons as a configured user ([#384](#384)) - *(watch)* impl poll mode ([#353](#353)) - *(cli)* stop / restart --all-global / --all-local ([#385](#385)) - version check in IPC ([#354](#354)) ### Fixed - pass error when failed to parse toml ([#386](#386)) ### Other - *(deps)* update rust crate xx to v2.5.4 ([#378](#378)) - *(deps)* lock file maintenance ([#371](#371)) - *(deps)* update rust crate xx to v2.5.4 ([#363](#363)) - *(deps)* update rust crate hyper-rustls to v0.27.9 ([#359](#359)) - *(deps)* update rust crate rmcp to v1.5.0 ([#364](#364)) - *(deps)* update rust crate libc to v0.2.185 ([#360](#360)) - *(deps)* update rust crate tokio to v1.52.1 ([#365](#365)) - *(deps)* update rust crate uuid to v1.23.1 ([#362](#362)) - *(deps)* update rust crate rustls to v0.23.38 ([#361](#361)) - *(deps)* update rust crate clap to v4.6.1 ([#358](#358)) - *(deps)* update rust crate axum to v0.8.9 ([#357](#357)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk release bookkeeping: only bumps the `pitchfork-cli` version and regenerates changelog/docs metadata, with no runtime code changes. > > **Overview** > Updates project metadata for the `v2.7.0` release. > > Bumps `pitchfork-cli` from `2.6.0` to `2.7.0` across `Cargo.toml`, `Cargo.lock`, and the generated CLI docs (`docs/cli/*` and `pitchfork.usage.kdl`), and adds the `2.7.0` entry to `CHANGELOG.md`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e93c44b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
addresses #351.