Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request refactors the auto-update mechanism to include a 24-hour cooldown after failed attempts and improves dependency cloning by propagating errors instead of returning booleans. Key changes include updating Cargo.lock with new dependencies, simplifying global state in the update helper, and enhancing user feedback during the update process. Feedback was provided regarding the loss of error context in the package cloning logic and the lack of error handling when saving the version cache.
1bcb3e1 to
080898e
Compare
Previously clone_package_once() returned bool and used .ok()? to
discard the error from clone_package(). The caller in install.rs
could only bail with a generic "{name} clone failed" message,
losing the underlying IO error (e.g. NTFS hardlink failure on
Windows).
Now clone_package_once() returns Result<()> and the full error
chain propagates to the user. The warn log also uses {:#} to
print the complete error chain.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
080898e to
65b5f59
Compare
Windows has been unstable lately; mirror the Linux bash e2e case for `utoo install --from pnpm` on eggjs/egg (next) so we catch Windows-specific regressions in pnpm migration + workspace install at the same cadence as Linux/macOS. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
0c54106 to
7ed8f27
Compare
OnceMap dedupes by *target path*, but install.rs and pipeline
workers construct the same logical target with different separators
on Windows:
install.rs: `cwd.join("node_modules/foo")` → forward slashes
(lockfile paths use `/`)
pipeline: `cwd.join(PathBuf::from("..."))` → mixed,
with `\` injected at `Path::join` boundaries
These produce distinct strings (`a/b/c` vs `a/b\c`) and OnceMap
sees them as two unrelated keys. Both clone tasks then race on the
same real directory file-by-file, surfacing as
`ERROR_SHARING_VIOLATION` (os error 32). The parent-wait via
`wait_clone_if_pending` is also defeated for the same reason.
Fix: switch the OnceMap key from `String` to `PathBuf`, and feed
it through `Path::components().collect()`. `components()` parses
both `/` and `\` as separators on Windows, and `collect::<PathBuf>()`
rebuilds with the OS-preferred separator — giving a stable key
without ad-hoc string replace and without an extra crate.
Linux/macOS unchanged (separator is already `/`). Includes a
Windows-only regression test asserting `cache_key("a/b") ==
cache_key("a\\b")`.
Surfaced by the eggjs/egg Windows e2e smoke test, which triggered
the race in `@langchain/core`'s nested node_modules.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
7ed8f27 to
51f4ce5
Compare
xusd320
approved these changes
Apr 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR started as a small "preserve clone error chain" fix and grew, in a good way: the new e2e coverage immediately surfaced a real Windows concurrency bug in
CLONE_CACHE, which is also fixed here.Three commits:
fix(pm): preserve clone error chain instead of swallowing itclone_package_once()now returnsResult<()>instead ofbool, so the full error chain reaches the caller via?instead of being collapsed into a generic"{name} clone failed"bail{:#}(alternate Display) to print the complete anyhow chain, not just the top-level messageinstall.rsand the pipeline pre-clone worker propagate / log the real errortest(pm): add eggjs/egg next branch smoke to Windows e2ee2e/utoo-pm.ps1so Windows CI also exercisesut install --from pnpmagainst a complex pnpm-workspace monorepo (@langchain/corewith deeply nestednode_modules)fix(pm): normalize path separators in CLONE_CACHE keys on WindowsERROR_SHARING_VIOLATION (os error 32)cloningcamelcaseanduuidinto@langchain/core/node_modules/OnceMapdedupes by target path string, butinstall.rsconstructs targets with forward slashes (lockfile-derived) while pipeline workers go throughPath::join, which injects\on Windows.node_modules/foo/barandnode_modules/foo\barare distinct strings → dedup fails → both clone tasks race on the same real directory file-by-file → second writer hits a sharing violation.wait_clone_if_pendingis also defeated for the same reason.StringtoPathBuf, run target paths throughPath::components().collect()on Windows.components()parses both/and\as separators andcollect::<PathBuf>()rebuilds with the OS-preferred separator — gives a stable key without any extra crate orreplace()hack. Unix paths skip the normalization and useto_path_buf()directly.cache_key("a/b") == cache_key("a\\b").Without commit 1, the diagnosis above wouldn't have been possible
The whole investigation was unblocked by the error chain fix: before commit 1 the failure would have shown up as
"camelcase clone failed"in the install bail, with noos error 32to grep for. Commit 1'stracing::warn!with{:#}plusbail!propagation made the exact NTFS error visible in CI logs the first time the new e2e job ran.Test plan
cargo build -p utoo-pmcleancargo clippy -p utoo-pm --all-targets -- -D warnings --no-depscleancargo test -p utoo-pm cloner::(16 pass)🤖 Generated with Claude Code