feat(install): resolve install-dir collisions#88
Conversation
The node_modules collision was computed at detection time and every command flushed it, so run/list/doctor nagged about an install-time hazard they cannot act on, and `[install].pms` never silenced it. It is now an install verdict computed against the effective PM set. - ctx.install_dirs records writers per dir as a fact; cmd::install::plan_install picks a winner and shadows the rest - [install].on_collision = resolve (default) | error, plus RUNNER_INSTALL_ON_COLLISION - writers of one dir install serially, distinct dirs still overlap; install reaps a running child on wait error instead of orphaning it - doctor reports the plan (install set, shadowed dir); the collision warning is confined to install and doctor - detection warnings print once per project root across nested runners Also: - fix(detect): deno writes node_modules whenever a package.json is present (documented default is manual mode), not only on explicit nodeModulesDir - fix(detect): two node lockfiles resolve by which one git tracks before the bun > pnpm > yarn > npm preference order - fix(node): prerelease PM builds satisfy devEngines version ranges - schema: schema-facing descriptions via schemars(description) instead of post-hoc JSON stripping - style: remove em-dashes repo-wide - build: rust-toolchain nightly channel
Cleanup of 3176dda's install-collision code and the blind em-dash sweep it carried, per review of what that commit did crappily. - give the install-plan collision its own `CollisionDir` type; the old `DetectionWarning::InstallDirCollision` variant is deleted, so detection can no longer emit a verdict the type system now forbids - merge `InstallPlan.collisions` and `.serialized` into one field the warning text and serial run-order both derive from - make `shadowed` a named `Shadowed` struct instead of a bare 3-tuple - document `dir_winner`'s node-only resolution instead of hiding it behind a generic-looking install-dir shape - fix ~260 comma splices the em-dash->comma sweep left across source, tests, docs, scripts, packaging, and the site; regenerate the schema descriptions to match `[install].on_collision` stays; it was requested.
Further review after abf22a1 surfaced 30 comma-spliced clauses it missed, across doc and code comments, CHANGELOG, README, site copy, and the generated schema descriptions. Each now takes the mark its context wants, whether a period, a semicolon, or an added conjunction. A few semicolons whose second clause stands alone become periods. Schemas regenerated from source.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
runner | d5bcdea | Commit Preview URL Branch Preview URL |
Jul 16 2026, 02:10 AM |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (28)
📜 Recent review details⏰ Context from checks skipped due to timeout. (1)
🧰 Additional context used📓 Path-based instructions (1)**/CHANGELOG.md📄 CodeRabbit inference engine (Custom checks)
Files:
🧠 Learnings (7)📚 Learning: 2026-03-26T20:05:44.851ZApplied to files:
📚 Learning: 2026-04-21T15:16:40.277ZApplied to files:
📚 Learning: 2026-05-04T23:28:17.947ZApplied to files:
📚 Learning: 2026-06-01T17:42:48.461ZApplied to files:
📚 Learning: 2026-06-11T18:52:28.233ZApplied to files:
📚 Learning: 2026-05-15T01:31:48.037ZApplied to files:
📚 Learning: 2026-05-14T15:35:39.922ZApplied to files:
🪛 LanguageTooltests/docker/README.md[uncategorized] ~14-~14: Possible missing comma found. (AI_HYDRA_LEO_MISSING_COMMA) [uncategorized] ~34-~34: Loose punctuation mark. (UNLIKELY_OPENING_PUNCTUATION) [uncategorized] ~35-~35: Loose punctuation mark. (UNLIKELY_OPENING_PUNCTUATION) [uncategorized] ~36-~36: Loose punctuation mark. (UNLIKELY_OPENING_PUNCTUATION) 🔍 Remote MCP GitHub GrepAdditional review context
🔇 Additional comments (34)
📝 WalkthroughResolve install-directory collisions during installation
Tests, clippy, formatting, and schema-drift checks pass. WalkthroughThe change introduces collision-aware install planning through Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Detection
participant Resolver
participant InstallPlan
participant PackageManagers
Detection->>InstallPlan: record install-directory writers
Resolver->>InstallPlan: resolve collision policy
InstallPlan->>PackageManagers: create serialised lanes
PackageManagers-->>InstallPlan: return installation results
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 7 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (7 passed)
Comment |
Ensure failed waits terminate children before reader joins, keep shadow notices visible under `--no-warnings`, and preserve strict collision-policy behavior in docs and tests. Pin the nightly toolchain, harden Deno/semver/git edge cases, and bump the shared JSON schema contract to v2 with kind-specific conflict metadata.
What
node_modules/vendor install-dir collisions (bun + deno both writingnode_modules, for example) are now an install-time verdict computedagainst the effective PM set, instead of a detection-time warning that
every command flushed. Before, run/list/doctor nagged about an
install-time hazard they cannot act on, and
[install].pmsneversilenced it.
Changes
ctx.install_dirsrecords writers per dir as a fact;cmd::install::plan_installpicks a winner and shadows the rest.[install].on_collision = resolve(default) orerror, plusRUNNER_INSTALL_ON_COLLISION.resolvepicks the resolver's node PM(non-deno unless
[pm].node = "deno");errorexits non-zero.Install reaps a running child on wait error instead of orphaning it.
doctorreports the plan (install set, shadowed dir). The collisionwarning is confined to
installanddoctor, printed once perproject root across nested runners.
Detection
node_moduleswhenever apackage.jsonis present (thedocumented default is manual mode), not only on explicit
nodeModulesDir.bun > pnpm > yarn > npmorder.devEnginesversion ranges.Housekeeping
schemars(description)rather thanpost-hoc JSON stripping.
behind are fixed.
Testing
cargo test,cargo clippy --all-targets,cargo fmt --check, andthe schema drift guard all pass.
Commits:
feat(install)3176dda,refactor(install)abf22a1,style7307be2,
fix(release)f265f05.