Skip to content

fix: watch cwds of dependencies#10054

Open
43081j wants to merge 9 commits into
jdx:mainfrom
43081j:watch-cwds
Open

fix: watch cwds of dependencies#10054
43081j wants to merge 9 commits into
jdx:mainfrom
43081j:watch-cwds

Conversation

@43081j
Copy link
Copy Markdown

@43081j 43081j commented May 23, 2026

When I changed watch mode to also watch dependencies' sources, I didn't
take into account the fact that the sources will be used as-is (i.e.
not resolved to anything).

This meant the following would happen:

  • build:a has ["src/*.ts"]
  • build:b has ["lib/*.js"] and depends on build:a
  • We pass ["src/*.ts", "lib/*.js"] to watchexec in the directory of
    build:b

This made lib/*.js basically no-op, or worse, watch the wrong files.

This change resolves the paths to their owning directory so we end up
with ["wherever-builda-lives/src/*.ts", "wherever-buildb-lives/lib/*.js"].

Notable Changes:

  • Instead of passing relative globs to watchexec, we now pass resolved
    ones (relative to the root)
  • We now pass --project-origin to watchexec which comes with some perf
    gains but also means globs are now relative to it
  • We pass --watch {cwd} for the cwd of each dependency
  • This new resolve_source function is basically turning a source glob
    into a relative-to-the-root glob while retaining negations
  • The new common_ancestor function tries to find the common ancestor of two directories

cc @jdx i don't usually delve into rust so i'd love some help here if you can.

especially if there's a better way to find the common ancestor, or if you think we should deal with that differently.

basically, watchexec doesn't seem to support absolute paths, so we have to set the project-origin to something above all globs. which is why this new function tries to find a common root (if not the configured one)

43081j added 4 commits May 22, 2026 09:41
When I changed watch mode to also watch dependencies' sources, I didn't
take into account the fact that the `sources` will be used _as-is_ (i.e.
not resolved to anything).

This meant the following would happen:

- `build:a` has `["src/*.ts"]`
- `build:b` has `["lib/*.js"]` and depends on `build:a`
- We pass `["src/*.ts", "lib/*.js"]` to watchexec _in the directory of
  `build:b`_

This made `lib/*.js` basically no-op, or worse, watch the wrong files.

This change resolves the paths to their owning directory so we end up
with `["wherever-builda-lives/src/*.ts",
"wherever-buildb-lives/lib/*.js"]`.

**Notable Changes:**

- Instead of passing relative globs to watchexec, we now pass resolved
  ones (relative to the root)
- We now pass `--project-origin` to watchexec which comes with some perf
  gains but also means globs are now relative to it
- We pass `--watch {cwd}` for the cwd of each dependency
- This new `resolve_source` function is basically turning a source glob
  into a relative-to-the-root glob while retaining negations
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces logic to calculate a "filter anchor" for watchexec by determining the common ancestor of task working directories, ensuring glob filters are correctly interpreted relative to a project origin. It adds utility functions for finding common path ancestors and resolving source patterns, including support for negations and escaped characters. Review feedback focused on optimizing the common_ancestor function by using AsRef to avoid unnecessary cloning and reducing memory allocations during path component comparisons.

Comment thread src/cli/watch.rs Outdated
Comment thread src/cli/watch.rs Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR fixes watch mode incorrectly applying dependency source globs relative to the wrong task's working directory. Sources are now resolved to absolute paths, re-expressed relative to a computed anchor (--project-origin), and each task cwd is added via --watch so watchexec monitors the right directories.

  • New helpers parse_source, normalize_path, relativize_source, and common_ancestor handle the path resolution pipeline; the anchor is widened to cover sources that escape above their task's cwd via ...
  • The if parsed.iter().all(|v| v.is_empty()) guard correctly opts out of source-based watching when no task declares any sources, preserving prior watchexec default behaviour for that case.
  • Two edge cases: normalize_path treats glob wildcard components as literal directory names so a .. following a wildcard pops it rather than the real parent, and the anchor defaults to the full configured project root even when sources fall within a narrower subdirectory.

Confidence Score: 4/5

Safe to merge; the core bug fix is correct and the three concerns raised in prior review threads are addressed. Two non-blocking edge cases remain in the new path-resolution helpers.

The path manipulation pipeline works correctly for the common cases and is well-covered by the new unit tests. The normalize_path function silently alters patterns that contain .. after glob wildcards, and the anchor is set to the full configured project root even when the actual common ancestor of all sources is narrower, expanding watchexec gitignore scanning scope. Neither issue causes incorrect file watching in typical configurations.

src/cli/watch.rs — specifically the normalize_path function and the (Some(mut cfg), Some(common)) anchor-selection branch.

Important Files Changed

Filename Overview
src/cli/watch.rs Core fix: source globs from dependency tasks are now resolved to absolute paths and re-expressed relative to a computed anchor before being passed to watchexec, along with explicit --watch flags for each task cwd. New helpers are logically correct for typical patterns; two edge cases flagged.

Reviews (5): Last reviewed commit: "fix: handle windows escapes" | Re-trigger Greptile

Comment thread src/cli/watch.rs
Comment thread src/cli/watch.rs Outdated
Comment thread src/cli/watch.rs
Copy link
Copy Markdown
Owner

jdx commented May 29, 2026

This mostly looks good, but I think there is one missed case before merge.

When a source escapes the task cwd, the filter anchor is widened correctly, but the watched paths are still only the task cwds. For example:

[tasks.build]
dir = "packages/foo"
sources = ["../../shared/src/*.ts"]

This becomes roughly:

--project-origin /repo
--watch /repo/packages/foo
-f shared/src/*.ts

The filter now points at /repo/shared/src/*.ts, but watchexec is not watching /repo/shared, so changes there may not trigger.

Could we either watch the computed anchor/common ancestor, or add watch dirs for source paths that fall outside their task cwd? A regression test for dir plus ../.. sources would be great too.

This comment was generated by an AI coding assistant.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants