Problem
When two installed npm packages declare the same bin name, whichever one pantry shims last owns pantry/.bin/<name>. The npm shims are written from the parallel download phase (Installer.createNpmShims), so the winner depends on thread scheduling, not on the project.
pantry/.bin is on PATH in pantry-activated shells, so this decides which program a bare command runs.
Concrete case
Every Stacks project now has two packages that publish a bin named buddy:
@stacksjs/buddy, the Stacks framework CLI. It is reached through the production dependencystacks; in the framework repo it is a workspace package.@buddysh/buddy, a CI dependency bot. It is reached only through the devDependencybetter-dx.
In stacksjs/stacks today, pantry/.bin/buddy runs pantry/@buddysh/buddy/dist/bin/cli.js, so buddy dev starts the dependency bot instead of the framework CLI.
Expected
Collisions should resolve deterministically, using the project's dependency graph:
- A bin from one of the project's own workspace packages or direct dependencies beats one from a transitive dependency.
- A bin reachable through
dependenciesbeats one reachable only throughdevDependenciesor optional dependencies. - Otherwise the shallower dependency depth wins, then the package name as a stable tie-break. Install order never decides.
pantry should print a one-line warning naming both packages whenever it resolves a collision.