Skip to content

Resolve pi extension paths without hardcoding one specifier - #395

Merged
dannon merged 1 commit into
galaxyproject:mainfrom
dannon:fix/pi-mcp-adapter-subpath-resolve
Aug 3, 2026
Merged

Resolve pi extension paths without hardcoding one specifier#395
dannon merged 1 commit into
galaxyproject:mainfrom
dannon:fix/pi-mcp-adapter-subpath-resolve

Conversation

@dannon

@dannon dannon commented Jul 31, 2026

Copy link
Copy Markdown
Member

npm install -g @galaxyproject/loom is broken on npm right now, and has been since Jul 24. A fresh install dies on startup before printing anything:

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './index.ts' is not defined
by "exports" in .../node_modules/pi-mcp-adapter/package.json
    at file:///.../bin/loom.js:42:40

pi-mcp-adapter 2.12.0 (published 2026-07-24) added an exports map. Exports are a closed list, so the deep pi-mcp-adapter/index.ts subpath we resolve stopped being a path and started being an error. We depend on ^2.4.0, so every fresh install since then resolves to 2.12+ and hits it. I confirmed against the actual published 0.5.1 tarball, not just locally.

Our lockfile pins 2.9.0, which is precisely why nothing caught this in dev -- npm ci, tests, typecheck and packaging all use the pinned version and stay happy. smoke:pack is the only check that installs without the lockfile, and it's been failing on main for this. It was doing its job; we just don't run it in CI.

The fix

There's no single specifier that works for both package shapes:

pkg/index.ts bare pkg
pi-mcp-adapter 2.9.0 (pinned) resolves fails, no main
pi-mcp-adapter 2.12.0+ fails, exports resolves
pi-web-access 0.16.0 resolves fails, no main

A package with an exports map only answers the bare name; a package without one declares no main, so only the subpath resolves. So resolvePiExtensionDir tries bare first and falls back to the subpath, and if both fail it throws something actionable naming both attempts instead of a bare Node stack.

This covers pi-web-access too -- same pattern on the next line, no exports map yet, and it would break identically the day it grows one.

Verification

Both directions, since the whole bug was that only one half was ever exercised:

  • against the pinned 2.9.0 (subpath fallback): node bin/loom.js --help exits 0
  • npm run smoke:pack, which installs fresh and lands on 2.15.0 (bare path): fails on main, green here
  • full suite 1364 passed / 1 skipped, typecheck clean, lint 0 errors

Worth a follow-up, not in here

Dev runs 2.9.0 while every real user gets 2.15.0. That gap is what let this ship, and it'll let the next one ship too. Bumping the lockfile would close it but can surface genuine behavior changes in the adapter, so it deserves its own PR rather than riding along with a startup fix. smoke:pack also isn't in .github/workflows/build.yml -- if it were, this would have been caught on the first PR after Jul 24.

pi-mcp-adapter 2.12.0 added an "exports" map on Jul 24, and since exports are a
closed list, that turned the deep "pi-mcp-adapter/index.ts" subpath we resolve
into an error instead of a path. We depend on ^2.4.0, so every fresh install
since then resolves to 2.12+ and dies on startup with an
ERR_PACKAGE_PATH_NOT_EXPORTED stack before printing a single line -- meaning
`npm install -g @galaxyproject/loom` is broken on npm right now. Our lockfile
pins 2.9.0, which is exactly why nothing local caught it; smoke:pack, which
installs without the lockfile, is the one check that did.

There's no single specifier that covers both shapes. A package with an exports
map only answers the bare name, and a package without one (pi-mcp-adapter
<=2.11.0, and pi-web-access today) declares no "main", so only the subpath
resolves. So try bare first and fall back to the subpath. That also covers
pi-web-access, which is the same pattern one line down and would break the same
way the day it grows an exports map.

Verified both directions: against the pinned 2.9.0 the fallback path works, and
smoke:pack -- which installs fresh and lands on 2.15.0 -- goes from failing on
main to green.
@dannon
dannon marked this pull request as ready for review August 3, 2026 02:33
@dannon
dannon merged commit 7a349ed into galaxyproject:main Aug 3, 2026
3 checks passed
dannon added a commit that referenced this pull request Aug 10, 2026
Every check in the build job runs against the pinned tree, which is exactly the
tree no user has. #395 is what that costs: pi-mcp-adapter published an exports
map, our lockfile stayed on the version before it, and typecheck, tests, and
packaging all stayed green while `npm i -g @galaxyproject/loom` died on the
first line of startup. smoke:pack is the one check that installs without the
lockfile, and it caught that -- it just wasn't wired up to run anywhere.

Note this step is deliberately not hermetic. It hits the network and can go red
because a dependency published something broken rather than because the PR did.
That's the job: a failure here means someone installing right now would hit the
same thing.
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.

1 participant