Skip to content

feat(cli): add watch mode (--watch) to the CLI for check/format/lint commands#8731

Open
siketyan wants to merge 2 commits intobiomejs:nextfrom
siketyan:feat/watch-mode
Open

feat(cli): add watch mode (--watch) to the CLI for check/format/lint commands#8731
siketyan wants to merge 2 commits intobiomejs:nextfrom
siketyan:feat/watch-mode

Conversation

@siketyan
Copy link
Member

Summary

Resolves #135

Added the new option --watch to enable watch mode that watches file changes and re-run the traversal automatically.

Test Plan

Manually tested. I'm not sure if this can be tested in a test code.

Docs

I suppose it will be automatically added by the codegen

@siketyan siketyan self-assigned this Jan 11, 2026
@changeset-bot
Copy link

changeset-bot bot commented Jan 11, 2026

🦋 Changeset detected

Latest commit: 3119fa1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@biomejs/biome Minor
@biomejs/cli-win32-x64 Minor
@biomejs/cli-win32-arm64 Minor
@biomejs/cli-darwin-x64 Minor
@biomejs/cli-darwin-arm64 Minor
@biomejs/cli-linux-x64 Minor
@biomejs/cli-linux-arm64 Minor
@biomejs/cli-linux-x64-musl Minor
@biomejs/cli-linux-arm64-musl Minor
@biomejs/wasm-web Minor
@biomejs/wasm-bundler Minor
@biomejs/wasm-nodejs Minor
@biomejs/backend-jsonrpc Patch
@biomejs/js-api Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added A-CLI Area: CLI A-Project Area: project labels Jan 11, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 11, 2026

Merging this PR will not alter performance

✅ 58 untouched benchmarks
⏩ 95 skipped benchmarks1


Comparing siketyan:feat/watch-mode (3119fa1) with next (a215408)

Open in CodSpeed

Footnotes

  1. 95 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

Walkthrough

Adds a --watch flag to the check, format and lint CLI commands that reruns the command on workspace file changes. Introduces a Watcher trait, a DefaultWatcher implementation using the notify crate, a CrawlPath enum for path handling, and wires watch-mode through the command runner/traversal framework. The workspace adds the notify dependency.

Possibly related PRs

  • biomejs/biome PR 8485 — introduces the runner/command/crawler framework that this change extends with watch-mode and watcher wiring.
  • biomejs/biome PR 8071 — modifies the watcher subsystem and CLI runner wiring, touching the same watcher/runner surfaces.
  • biomejs/biome PR 7708 — alters CLI command payloads (BiomeCommand variants), overlapping the enum changes introduced here.

Suggested labels

A-Formatter, A-Linter, A-Tooling

Suggested reviewers

  • arendjr
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarises the main change: adding a watch mode feature to the CLI with the --watch flag for check/format/lint commands.
Description check ✅ Passed The description is directly related to the changeset, explaining the watch mode feature, its purpose, testing approach, and documentation expectations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @crates/biome_cli/src/commands/lint.rs:
- Around line 268-288: The watch-mode incompatibility check in
check_incompatible_arguments currently only checks self.fix and self.write; add
a similar branch for self.suppress so that if self.is_watch_mode() and
self.suppress is true you return
Err(CliDiagnostic::incompatible_arguments("--watch", "--suppress", "Modifying
files by adding suppression comments is not available in watch mode.")); place
this new check next to the existing checks for self.fix and self.write inside
the same if self.is_watch_mode() block and use the same
CliDiagnostic::incompatible_arguments helper.

In @crates/biome_cli/src/runner/impls/watchers/default.rs:
- Around line 35-57: The poll method uses self.rx.iter() which blocks
indefinitely and prevents graceful shutdown; replace the blocking iterator with
a non-blocking/timeout-driven receive (e.g., use
self.rx.recv_timeout(Duration::from_millis(...)) in a loop or try_recv() with a
sleep) so poll can return None or propagate a shutdown signal when the watcher
is dropped or on Ctrl+C; update the logic that filters events (the matches!
block) to operate on the received Event and construct the WatcherEvent paths the
same way, and ensure any recv timeout error is handled (returning None or
breaking) to allow clean shutdown.

In @crates/biome_cli/src/runner/watcher.rs:
- Around line 7-17: The trait method Watcher::poll currently takes &self but the
implementation calls iter() on a Receiver which requires &mut self; change the
trait signature to fn poll(&mut self) or alternatively wrap the internal
Receiver in interior mutability (e.g., Mutex/RefCell) so iter() can be called
from an immutable reference; update all impls of Watcher (and any callers) to
match the new fn poll(&mut self) signature if you choose the signature change,
or refactor the watcher struct to hold the Receiver inside a Mutex/RefCell and
adjust the impl of poll to lock/borrow and call iter() accordingly.
🧹 Nitpick comments (2)
crates/biome_cli/src/commands/format.rs (1)

232-252: Consider extracting shared validation logic.

This validation is now duplicated across check.rs, lint.rs, and format.rs. A shared helper function would reduce repetition.

♻️ Optional refactor suggestion
// In commands/mod.rs or a shared module
pub(crate) fn check_watch_incompatible_arguments(
    is_watch: bool,
    fix: bool,
    write: bool,
) -> Result<(), CliDiagnostic> {
    if is_watch {
        if fix {
            return Err(CliDiagnostic::incompatible_arguments(
                "--watch",
                "--fix",
                "Applying code fixes is not available in watch mode.",
            ));
        }
        if write {
            return Err(CliDiagnostic::incompatible_arguments(
                "--watch",
                "--write",
                "Applying code fixes is not available in watch mode.",
            ));
        }
    }
    Ok(())
}
crates/biome_cli/src/runner/mod.rs (1)

345-388: Two observations on the watch loop.

  1. Reusing scan_duration: The original scan duration is passed to every finalize call, but it doesn't reflect the actual time for re-runs. Consider measuring per-iteration or passing None.

  2. Discarded result: _ = Self::Finalizer::finalize(...) silently discards errors. If finalization fails (e.g., console issues), the loop continues without feedback.

♻️ Suggested improvement
             while let Some(event) = watcher.poll() {
+                let iteration_start = std::time::Instant::now();
                 let collector = self.collector(fs, execution.as_ref(), cli_options);
                 // ... crawl and before_finalize ...
 
-                _ = Self::Finalizer::finalize(FinalizePayload {
+                if let Err(e) = Self::Finalizer::finalize(FinalizePayload {
                     cli_options,
                     project_key,
                     execution: execution.as_ref(),
                     fs,
                     console,
                     workspace,
-                    scan_duration: duration,
+                    scan_duration: Some(iteration_start.elapsed()),
                     crawler_output: output,
                     paths: event
                         .paths
                         .into_iter()
                         .map(|path| path.into_string())
                         .collect(),
-                });
+                }) {
+                    console.error(markup! {
+                        {PrintDiagnostic::simple(&e)}
+                    });
+                }
             }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a215408 and 3a1be3a.

⛔ Files ignored due to path filters (4)
  • Cargo.lock is excluded by !**/*.lock and included by **
  • crates/biome_cli/tests/snapshots/main_commands_check/check_help.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_commands_format/format_help.snap is excluded by !**/*.snap and included by **
  • crates/biome_cli/tests/snapshots/main_commands_lint/lint_help.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (17)
  • .changeset/fresh-otters-peel.md
  • Cargo.toml
  • crates/biome_cli/Cargo.toml
  • crates/biome_cli/src/commands/check.rs
  • crates/biome_cli/src/commands/format.rs
  • crates/biome_cli/src/commands/lint.rs
  • crates/biome_cli/src/commands/mod.rs
  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/runner/crawler.rs
  • crates/biome_cli/src/runner/impls/commands/custom_execution.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs
  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_cli/src/runner/impls/watchers/default.rs
  • crates/biome_cli/src/runner/impls/watchers/mod.rs
  • crates/biome_cli/src/runner/mod.rs
  • crates/biome_cli/src/runner/watcher.rs
  • crates/biome_service/Cargo.toml
🧰 Additional context used
📓 Path-based instructions (2)
**/Cargo.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/Cargo.toml: Use workspace dependencies with workspace = true for internal crates in Cargo.toml
Use path dependencies for dev-dependencies in crates to avoid requiring published versions

Files:

  • crates/biome_cli/Cargo.toml
  • crates/biome_service/Cargo.toml
  • Cargo.toml
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_cli/src/runner/impls/watchers/mod.rs
  • crates/biome_cli/src/commands/format.rs
  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/commands/lint.rs
  • crates/biome_cli/src/runner/crawler.rs
  • crates/biome_cli/src/runner/impls/watchers/default.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs
  • crates/biome_cli/src/runner/watcher.rs
  • crates/biome_cli/src/commands/check.rs
  • crates/biome_cli/src/commands/mod.rs
  • crates/biome_cli/src/runner/impls/commands/custom_execution.rs
  • crates/biome_cli/src/runner/mod.rs
🧠 Learnings (34)
📓 Common learnings
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace_watcher.rs : Use WorkspaceWatcher to keep workspace state in sync with the filesystem, and only activate it in daemon mode
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/Cargo.toml : Include development dependencies in `Cargo.toml` for formatter tests: `biome_formatter_test`, `biome_<language>_factory`, `biome_<language>_parser`, `biome_parser`, `biome_service`, `countme`, `iai`, `quickcheck`, `quickcheck_macros`, and `tests_macros`

Applied to files:

  • crates/biome_cli/Cargo.toml
  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_service/Cargo.toml
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/Cargo.toml : Use workspace dependencies with `workspace = true` for internal crates in Cargo.toml

Applied to files:

  • crates/biome_cli/Cargo.toml
  • crates/biome_service/Cargo.toml
  • Cargo.toml
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Create two new crates `biome_{language}_syntax` and `biome_{language}_factory` using `cargo new --lib` for new language parsers

Applied to files:

  • crates/biome_cli/Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace*.rs : Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances

Applied to files:

  • crates/biome_cli/Cargo.toml
  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_service/Cargo.toml
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Build debug binaries using `cargo build --bin biome` for development and triaging

Applied to files:

  • crates/biome_cli/Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_cli/Cargo.toml
  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_cli/src/runner/impls/watchers/mod.rs
  • crates/biome_cli/src/commands/format.rs
  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/commands/lint.rs
  • crates/biome_cli/src/runner/impls/watchers/default.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs
  • crates/biome_cli/src/runner/watcher.rs
  • crates/biome_cli/src/commands/check.rs
  • crates/biome_cli/src/commands/mod.rs
  • crates/biome_service/Cargo.toml
  • crates/biome_cli/src/runner/impls/commands/custom_execution.rs
  • crates/biome_cli/src/runner/mod.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace_watcher.rs : Use WorkspaceWatcher to keep workspace state in sync with the filesystem, and only activate it in daemon mode

Applied to files:

  • crates/biome_cli/Cargo.toml
  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_cli/src/runner/impls/watchers/mod.rs
  • crates/biome_cli/src/commands/format.rs
  • crates/biome_cli/src/runner/impls/watchers/default.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs
  • crates/biome_cli/src/runner/watcher.rs
  • crates/biome_cli/src/commands/check.rs
  • crates/biome_cli/src/commands/mod.rs
  • crates/biome_cli/src/runner/impls/commands/custom_execution.rs
  • crates/biome_cli/src/runner/mod.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/js_module_info/collector.rs : Implement module-level (thin) inference to resolve `TypeReference::Qualifier` variants by looking up declarations in module scopes and handling import statements

Applied to files:

  • crates/biome_cli/src/runner/impls/mod.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • crates/biome_cli/src/runner/impls/mod.rs
  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/commands/check.rs
  • crates/biome_cli/src/runner/mod.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/local_inference.rs : Implement local inference in dedicated modules to derive type definitions from expressions without context of surrounding scopes

Applied to files:

  • crates/biome_cli/src/runner/impls/mod.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>

Applied to files:

  • .changeset/fresh-otters-peel.md
  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/runner/impls/commands/traversal.rs
  • crates/biome_cli/src/commands/mod.rs
  • crates/biome_cli/src/runner/mod.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/lib.rs : Expose a public `format_node` function that accepts formatting options and a root syntax node, returning a `FormatResult<Formatted<Context>>` with appropriate documentation

Applied to files:

  • crates/biome_cli/src/commands/format.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/context.rs : Define `<Language>FormatContext` struct in a `context.rs` file containing `comments` and `source_map` fields, implementing `FormatContext` and `CstFormatContext` traits

Applied to files:

  • crates/biome_cli/src/commands/format.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the `FormatNode` trait and implement it for your Node when creating formatters in biome_js_formatter

Applied to files:

  • crates/biome_cli/src/commands/format.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_cli/src/lib.rs
  • crates/biome_cli/src/commands/lint.rs
  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `diagnostic` function to provide error messages explaining what the error is, why it is triggered, and what the user should do

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2025-12-22T09:27:13.161Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:27:13.161Z
Learning: In crates/biome_analyze/**/*analyze/src/**/*.rs, the `fix_kind` field in `declare_lint_rule!` should only be specified when the rule implements the `action` function. Rules that only emit diagnostics without providing code fixes should not include `fix_kind` in their metadata.

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `Markup!` macro for diagnostic messages and code action descriptions to ensure proper formatting

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Mark rules with `issue_number` in the `declare_lint_rule!` macro if they are work-in-progress to indicate missing features

Applied to files:

  • crates/biome_cli/src/commands/lint.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ParseSeparatedList` and `ParseNodeList` for parsing lists with error recovery to avoid infinite loops

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Box<[Box<str>]>` instead of `Vec<String>` for collections of strings in rule options to save memory

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement custom `Queryable` and `Visitor` types for rules that require deep inspection of child nodes to avoid inefficient traversals

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Avoid string allocations by using `&str` or `TokenText` instead of `to_string()`

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Use `TypeReference` instead of `Arc` for types that reference other types to avoid stale cache issues when modules are replaced

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/language_kind.rs : Add a new variant to `LanguageKind` enum in `language_kind.rs` file and implement all methods for the new language variant

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `try operator (?)` to transform `Result` types into `Option` when the `run` function returns `Option`

Applied to files:

  • crates/biome_cli/src/runner/crawler.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/Cargo.toml : Use path dependencies for dev-dependencies in crates to avoid requiring published versions

Applied to files:

  • crates/biome_service/Cargo.toml
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/server.rs : Use WorkspaceServer implementation for maintaining workspace state in daemon mode and CLI daemonless mode

Applied to files:

  • crates/biome_cli/src/runner/mod.rs
🧬 Code graph analysis (8)
crates/biome_cli/src/commands/format.rs (8)
crates/biome_cli/src/commands/check.rs (2)
  • is_watch_mode (165-167)
  • check_incompatible_arguments (285-305)
crates/biome_cli/src/commands/lint.rs (2)
  • is_watch_mode (156-158)
  • check_incompatible_arguments (268-288)
crates/biome_cli/src/runner/impls/commands/traversal.rs (4)
  • is_watch_mode (101-103)
  • is_watch_mode (161-163)
  • check_incompatible_arguments (134-136)
  • check_incompatible_arguments (216-218)
crates/biome_cli/src/runner/mod.rs (2)
  • is_watch_mode (210-210)
  • check_incompatible_arguments (593-595)
crates/biome_cli/src/commands/ci.rs (1)
  • check_incompatible_arguments (249-266)
crates/biome_cli/src/commands/migrate.rs (1)
  • check_incompatible_arguments (111-119)
crates/biome_cli/src/commands/mod.rs (1)
  • incompatible_arguments (947-958)
crates/biome_cli/src/diagnostics.rs (1)
  • incompatible_arguments (297-307)
crates/biome_cli/src/lib.rs (2)
crates/biome_cli/src/runner/impls/watchers/default.rs (1)
  • watch (23-33)
crates/biome_cli/src/runner/watcher.rs (2)
  • watch (12-12)
  • watch (22-22)
crates/biome_cli/src/commands/lint.rs (8)
crates/biome_cli/src/commands/check.rs (2)
  • is_watch_mode (165-167)
  • check_incompatible_arguments (285-305)
crates/biome_cli/src/runner/impls/commands/custom_execution.rs (3)
  • is_watch_mode (100-102)
  • check_incompatible_arguments (57-57)
  • check_incompatible_arguments (144-146)
crates/biome_cli/src/runner/impls/commands/traversal.rs (4)
  • is_watch_mode (101-103)
  • is_watch_mode (161-163)
  • check_incompatible_arguments (134-136)
  • check_incompatible_arguments (216-218)
crates/biome_cli/src/runner/mod.rs (2)
  • is_watch_mode (210-210)
  • check_incompatible_arguments (593-595)
crates/biome_cli/src/commands/ci.rs (1)
  • check_incompatible_arguments (249-266)
crates/biome_cli/src/commands/migrate.rs (1)
  • check_incompatible_arguments (111-119)
crates/biome_cli/src/commands/mod.rs (1)
  • incompatible_arguments (947-958)
crates/biome_cli/src/diagnostics.rs (1)
  • incompatible_arguments (297-307)
crates/biome_cli/src/runner/impls/watchers/default.rs (1)
crates/biome_cli/src/runner/watcher.rs (6)
  • new (9-9)
  • new (20-20)
  • watch (12-12)
  • watch (22-22)
  • poll (16-16)
  • poll (24-26)
crates/biome_cli/src/runner/impls/commands/traversal.rs (5)
crates/biome_cli/src/commands/check.rs (1)
  • is_watch_mode (165-167)
crates/biome_cli/src/commands/format.rs (1)
  • is_watch_mode (123-125)
crates/biome_cli/src/commands/lint.rs (1)
  • is_watch_mode (156-158)
crates/biome_cli/src/runner/impls/commands/custom_execution.rs (1)
  • is_watch_mode (100-102)
crates/biome_cli/src/runner/mod.rs (1)
  • is_watch_mode (210-210)
crates/biome_cli/src/runner/watcher.rs (2)
crates/biome_cli/src/runner/impls/watchers/default.rs (3)
  • new (15-21)
  • watch (23-33)
  • poll (35-57)
crates/biome_cli/src/runner/mod.rs (1)
  • paths (230-233)
crates/biome_cli/src/runner/impls/commands/custom_execution.rs (5)
crates/biome_cli/src/commands/check.rs (1)
  • is_watch_mode (165-167)
crates/biome_cli/src/commands/format.rs (1)
  • is_watch_mode (123-125)
crates/biome_cli/src/commands/lint.rs (1)
  • is_watch_mode (156-158)
crates/biome_cli/src/runner/impls/commands/traversal.rs (2)
  • is_watch_mode (101-103)
  • is_watch_mode (161-163)
crates/biome_cli/src/runner/mod.rs (1)
  • is_watch_mode (210-210)
crates/biome_cli/src/runner/mod.rs (4)
crates/biome_cli/src/commands/check.rs (1)
  • is_watch_mode (165-167)
crates/biome_cli/src/commands/format.rs (1)
  • is_watch_mode (123-125)
crates/biome_cli/src/commands/lint.rs (1)
  • is_watch_mode (156-158)
crates/biome_cli/src/runner/watcher.rs (2)
  • new (9-9)
  • new (20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (26)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: End-to-end tests
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_html_analyze)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_tailwind_parser)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: autofix
🔇 Additional comments (30)
crates/biome_service/Cargo.toml (1)

71-71: LGTM!

Correctly migrated to workspace dependency whilst preserving the required feature.

crates/biome_cli/src/runner/crawler.rs (2)

20-23: LGTM!

The CrawlPath enum provides a clean abstraction for handling paths from different sources (CLI args vs. watch events).


84-87: LGTM!

Both variants are correctly converted to Utf8PathBuf for traversal.

crates/biome_cli/Cargo.toml (1)

58-58: LGTM!

Correctly declared as a workspace dependency for watch mode support.

crates/biome_cli/src/runner/impls/watchers/mod.rs (1)

1-1: LGTM! Consider adding tests for the watcher.

The module declaration is correct. Based on learnings, consider implementing watcher tests (similar to the workspace watcher tests) to verify the watch-mode behaviour, even if end-to-end tests are challenging.

Cargo.toml (1)

130-130: No action required—notify 8.2.0 is the latest version and has no known security advisories.

Version 8.2.0 (released August 2025) is current and secure.

crates/biome_cli/src/runner/impls/mod.rs (1)

8-8: LGTM!

Clean module addition that follows the existing pattern.

.changeset/fresh-otters-peel.md (1)

1-5: LGTM!

The changeset accurately documents the new watch mode feature with appropriate versioning.

crates/biome_cli/src/runner/impls/commands/custom_execution.rs (1)

87-87: LGTM!

Correctly signals that custom execution commands don't participate in watch mode by using the unit type for Watcher and returning false from is_watch_mode().

Also applies to: 100-102

crates/biome_cli/src/commands/mod.rs (1)

207-209: LGTM!

The watch flag is consistently added across Check, Lint, and Format commands with clear documentation. Appropriately excluded from CI command since it's read-only.

Also applies to: 325-327, 410-412

crates/biome_cli/src/commands/check.rs (2)

47-47: LGTM!

The watch field and is_watch_mode() accessor are correctly implemented, matching the pattern used in Format and Lint commands.

Also applies to: 165-167


285-305: Critical validation logic looks sound.

The incompatible arguments check correctly prevents combining --watch with --fix or --write, which would create an infinite loop (watch detects change → applies fix → file changes → watch detects change...).

However, as you noted in the PR description, test coverage for watch mode behaviour is missing. Consider adding tests to verify this validation and the watch mode lifecycle.

Based on learnings, implement watcher tests in watcher.tests.rs for workspace methods and end-to-end tests in LSP tests. Would you like me to help generate test cases for the incompatible arguments validation?

crates/biome_cli/src/commands/lint.rs (2)

52-52: LGTM!

The watch flag is correctly added to the payload.


156-158: LGTM!

Clean delegation to the watch field.

crates/biome_cli/src/commands/format.rs (2)

45-45: LGTM!

Watch field correctly added.


123-125: LGTM!

Clean implementation.

crates/biome_cli/src/lib.rs (3)

102-127: LGTM!

Watch flag correctly propagated to the Check command payload.


153-181: LGTM!

Watch flag correctly propagated to the Lint command payload.


240-264: LGTM!

Watch flag correctly propagated to the Format command payload.

crates/biome_cli/src/runner/impls/commands/traversal.rs (4)

8-8: LGTM!

DefaultWatcher import correctly added.


100-103: LGTM!

Sensible default - commands opt-in to watch mode rather than opt-out.


147-147: LGTM!

DefaultWatcher correctly wired as the concrete watcher type.


161-163: LGTM!

Clean delegation to the inner command's is_watch_mode().

crates/biome_cli/src/runner/watcher.rs (2)

3-5: LGTM!

Clean struct definition for watch events.


19-27: LGTM!

Useful no-op implementation for commands that don't support watch mode.

crates/biome_cli/src/runner/mod.rs (4)

133-133: LGTM!

Watcher module correctly added.


192-192: LGTM!

Watcher associated type correctly added to the trait.


209-210: LGTM!

Clear documentation and method signature.


266-272: LGTM!

Good UX decision - non-default reporters (JSON, GitHub Actions) wouldn't work well with continuous watch output.

crates/biome_cli/src/runner/impls/watchers/default.rs (1)

23-33: The code is correct — paths_mut() and commit() are standard notify crate APIs.

The notify crate (v8.2.0) provides exactly this API on the Watcher trait for batch operations. The PathsMut helper (returned by paths_mut()) allows adding or removing multiple paths efficiently before calling commit() to apply changes. This is the documented, standard approach and is properly implemented here.

Likely an incorrect or invalid review comment.

Comment on lines +14 to +21
impl Watcher for DefaultWatcher {
fn new() -> Self {
let (tx, rx) = channel();
Self {
rx,
watcher: Box::new(recommended_watcher(tx).expect("watcher created")),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Watcher creation can fail; avoid panicking.

recommended_watcher can fail on systems with limited inotify watches or other resource constraints. Consider propagating the error or providing a more graceful fallback.

🐛 Proposed fix
 impl Watcher for DefaultWatcher {
-    fn new() -> Self {
+    fn new() -> Self {
         let (tx, rx) = channel();
-        Self {
-            rx,
-            watcher: Box::new(recommended_watcher(tx).expect("watcher created")),
+        match recommended_watcher(tx) {
+            Ok(watcher) => Self {
+                rx,
+                watcher: Box::new(watcher),
+            },
+            Err(e) => {
+                // Consider logging or returning Result from new()
+                panic!("Failed to create filesystem watcher: {e}")
+            }
         }
     }

Ideally, change the trait signature to fn new() -> Result<Self, ...> to handle this gracefully.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
impl Watcher for DefaultWatcher {
fn new() -> Self {
let (tx, rx) = channel();
Self {
rx,
watcher: Box::new(recommended_watcher(tx).expect("watcher created")),
}
}
impl Watcher for DefaultWatcher {
fn new() -> Self {
let (tx, rx) = channel();
match recommended_watcher(tx) {
Ok(watcher) => Self {
rx,
watcher: Box::new(watcher),
},
Err(e) => {
// Consider logging or returning Result from new()
panic!("Failed to create filesystem watcher: {e}")
}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think recommended_watcher(tx) can unlikely fail, e.g. FsEventWatcher for macOS is infallible.

Comment on lines 35 to 57
fn poll(&self) -> Option<WatcherEvent> {
let event = self.rx.iter().filter_map(Result::ok).find(|event| {
// Modifying folder or metadata is ignored as it can unlikely affect the results.
// Any event types are necessary for some platforms to catch events.
matches!(
event.kind,
EventKind::Create(CreateKind::File | CreateKind::Any)
| EventKind::Modify(
ModifyKind::Name(_) | ModifyKind::Data(_) | ModifyKind::Any
)
| EventKind::Remove(RemoveKind::File | RemoveKind::Any)
| EventKind::Any
)
})?;

Some(WatcherEvent {
paths: event
.paths
.into_iter()
.filter_map(|path| Utf8PathBuf::from_path_buf(path).ok())
.collect(),
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Blocking iterator with no shutdown mechanism.

self.rx.iter() blocks indefinitely. If the watcher is dropped or an error occurs, this could hang. Consider using try_recv() with a timeout or recv_timeout() to allow graceful shutdown on Ctrl+C.

🤖 Prompt for AI Agents
In @crates/biome_cli/src/runner/impls/watchers/default.rs around lines 35 - 57,
The poll method uses self.rx.iter() which blocks indefinitely and prevents
graceful shutdown; replace the blocking iterator with a
non-blocking/timeout-driven receive (e.g., use
self.rx.recv_timeout(Duration::from_millis(...)) in a loop or try_recv() with a
sleep) so poll can return None or propagate a shutdown signal when the watcher
is dropped or on Ctrl+C; update the logic that filters events (the matches!
block) to operate on the received Event and construct the WatcherEvent paths the
same way, and ensure any recv timeout error is handled (returning None or
breaking) to allow clean shutdown.

Copy link
Member Author

@siketyan siketyan Jan 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the watching process is run synchronously, Ctrl+C still works (at least on my environment)

@siketyan siketyan requested review from a team January 11, 2026 11:02
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @crates/biome_cli/src/runner/impls/watchers/default.rs:
- Around line 27-32: The code currently swallows errors from
watched_paths.add(path.as_std_path(), RecursiveMode::Recursive).ok() and
watched_paths.commit().ok(), which can hide failures to watch paths; update the
calls to handle the Result instead of calling .ok(): for each
watched_paths.add(...) match the Result and log a warning or error including the
path display and the error (e.g., using the crate's logger/tracing) so users
know which paths failed to be added, and likewise check watched_paths.commit()
and log or propagate the error with context if commit fails.
- Around line 50-56: The current construction of WatcherEvent drops non-UTF-8
paths silently by calling Utf8PathBuf::from_path_buf(path).ok() inside the
filter_map; update this to detect conversion failures and log a warning when a
path is dropped. Replace the filter_map call in the WatcherEvent creation (the
block creating Some(WatcherEvent { paths: ... })) with code that attempts
Utf8PathBuf::from_path_buf for each path, collects successful conversions into
the paths vector, and emits a concise warning (e.g., tracing::warn! or
log::warn!) including the original PathBuf or its debug representation for any
conversion that fails so users are notified when non-UTF-8 paths are ignored.
🧹 Nitpick comments (3)
crates/biome_cli/src/runner/impls/watchers/default.rs (3)

15-21: Improve the panic message for better debugging.

The watcher creation can fail for several reasons (e.g., OS resource limits, permissions, unsupported platform features). Consider a more descriptive error message to help users diagnose failures.

📝 Suggested improvement
-            watcher: Box::new(recommended_watcher(tx).expect("watcher created")),
+            watcher: Box::new(recommended_watcher(tx).expect("failed to create file system watcher: check OS resources and permissions")),

35-48: Document the blocking behaviour and consider surfacing watcher errors.

Line 36: self.rx.iter() blocks the current thread indefinitely until a file system event arrives. This behaviour should be documented, as poll() typically implies non-blocking. Additionally, filter_map(Result::ok) silently discards watcher errors that could indicate issues (e.g., buffer overflow, dropped events).

Consider adding a rustdoc comment explaining the blocking nature:

/// Polls for the next file system event, blocking until one arrives.
/// Returns `None` if the event is filtered out as irrelevant.
fn poll(&mut self) -> Option<WatcherEvent> {

For errors, consider logging them:

-        let event = self.rx.iter().filter_map(Result::ok).find(|event| {
+        let event = self.rx.iter().find_map(|result| {
+            match result {
+                Ok(event) => Some(event),
+                Err(e) => {
+                    eprintln!("Watch error: {}", e);
+                    None
+                }
+            }
+        }).find(|event| {

9-12: Add rustdoc documentation for the struct and implementation.

As per coding guidelines, the struct and its methods should have rustdoc comments explaining their purpose and behaviour, particularly the blocking semantics of poll().

Based on coding guidelines.

📚 Example documentation
+/// Default file system watcher implementation using the notify crate.
+///
+/// Watches paths recursively and reports file creation, modification, and removal events.
 pub(crate) struct DefaultWatcher {
     rx: Receiver<Result<Event>>,
     watcher: Box<dyn notify::Watcher>,
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a1be3a and 3119fa1.

📒 Files selected for processing (3)
  • crates/biome_cli/src/commands/lint.rs
  • crates/biome_cli/src/runner/impls/watchers/default.rs
  • crates/biome_cli/src/runner/watcher.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/biome_cli/src/runner/watcher.rs
  • crates/biome_cli/src/commands/lint.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_cli/src/runner/impls/watchers/default.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace_watcher.rs : Use WorkspaceWatcher to keep workspace state in sync with the filesystem, and only activate it in daemon mode
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Debug the WorkspaceWatcher by starting the daemon with cargo run --bin=biome -- start and running commands such as cargo run --bin=biome -- lint --use-server <path>
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace*.rs : Implement the Workspace trait in the Biome Service to manage internal state of projects, including open documents, project layout instances, and module graph instances
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Implement watcher tests for workspace methods in watcher.tests.rs and end-to-end tests in LSP tests

Applied to files:

  • crates/biome_cli/src/runner/impls/watchers/default.rs
📚 Learning: 2025-11-24T18:06:12.048Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:12.048Z
Learning: Applies to crates/biome_service/src/workspace_watcher.rs : Use WorkspaceWatcher to keep workspace state in sync with the filesystem, and only activate it in daemon mode

Applied to files:

  • crates/biome_cli/src/runner/impls/watchers/default.rs
🧬 Code graph analysis (1)
crates/biome_cli/src/runner/impls/watchers/default.rs (1)
crates/biome_cli/src/runner/watcher.rs (6)
  • new (9-9)
  • new (20-20)
  • watch (12-12)
  • watch (22-22)
  • poll (16-16)
  • poll (24-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (26)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_tailwind_parser)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_html_analyze)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_analyze)

Comment on lines +27 to +32
watched_paths
.add(path.as_std_path(), RecursiveMode::Recursive)
.ok();
}

watched_paths.commit().ok();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Silent error handling could cause the watcher to appear functional whilst missing paths.

If add() or commit() fails for a path (e.g., due to permissions, non-existent directories, or OS limits), it's silently ignored with .ok(). Users won't know which paths are actually being watched, leading to confusion when changes aren't detected.

🔍 Suggested improvement with logging

Consider logging failures so users can diagnose issues:

         for path in paths {
-            watched_paths
+            if let Err(e) = watched_paths
                 .add(path.as_std_path(), RecursiveMode::Recursive)
-                .ok();
+            {
+                eprintln!("Warning: Failed to watch path {}: {}", path, e);
+            }
         }
 
-        watched_paths.commit().ok();
+        if let Err(e) = watched_paths.commit() {
+            eprintln!("Warning: Failed to commit watched paths: {}", e);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
watched_paths
.add(path.as_std_path(), RecursiveMode::Recursive)
.ok();
}
watched_paths.commit().ok();
for path in paths {
if let Err(e) = watched_paths
.add(path.as_std_path(), RecursiveMode::Recursive)
{
eprintln!("Warning: Failed to watch path {}: {}", path, e);
}
}
if let Err(e) = watched_paths.commit() {
eprintln!("Warning: Failed to commit watched paths: {}", e);
}
🤖 Prompt for AI Agents
In @crates/biome_cli/src/runner/impls/watchers/default.rs around lines 27 - 32,
The code currently swallows errors from watched_paths.add(path.as_std_path(),
RecursiveMode::Recursive).ok() and watched_paths.commit().ok(), which can hide
failures to watch paths; update the calls to handle the Result instead of
calling .ok(): for each watched_paths.add(...) match the Result and log a
warning or error including the path display and the error (e.g., using the
crate's logger/tracing) so users know which paths failed to be added, and
likewise check watched_paths.commit() and log or propagate the error with
context if commit fails.

Comment on lines +50 to +56
Some(WatcherEvent {
paths: event
.paths
.into_iter()
.filter_map(|path| Utf8PathBuf::from_path_buf(path).ok())
.collect(),
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Non-UTF-8 paths are silently ignored.

Line 54: Paths that cannot be converted to UTF-8 are silently dropped with .ok(). Whilst uncommon, this could cause file changes to be missed without any indication to the user.

Consider logging when paths are dropped:

             .paths
             .into_iter()
-            .filter_map(|path| Utf8PathBuf::from_path_buf(path).ok())
+            .filter_map(|path| {
+                Utf8PathBuf::from_path_buf(path.clone()).or_else(|_| {
+                    eprintln!("Warning: Ignoring non-UTF-8 path: {:?}", path);
+                    Err(path)
+                }).ok()
+            })
             .collect(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Some(WatcherEvent {
paths: event
.paths
.into_iter()
.filter_map(|path| Utf8PathBuf::from_path_buf(path).ok())
.collect(),
})
Some(WatcherEvent {
paths: event
.paths
.into_iter()
.filter_map(|path| {
Utf8PathBuf::from_path_buf(path.clone()).or_else(|_| {
eprintln!("Warning: Ignoring non-UTF-8 path: {:?}", path);
Err(path)
}).ok()
})
.collect(),
})
🤖 Prompt for AI Agents
In @crates/biome_cli/src/runner/impls/watchers/default.rs around lines 50 - 56,
The current construction of WatcherEvent drops non-UTF-8 paths silently by
calling Utf8PathBuf::from_path_buf(path).ok() inside the filter_map; update this
to detect conversion failures and log a warning when a path is dropped. Replace
the filter_map call in the WatcherEvent creation (the block creating
Some(WatcherEvent { paths: ... })) with code that attempts
Utf8PathBuf::from_path_buf for each path, collects successful conversions into
the paths vector, and emits a concise warning (e.g., tracing::warn! or
log::warn!) including the original PathBuf or its debug representation for any
conversion that fails so users are notified when non-UTF-8 paths are ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Project Area: project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant