Skip to content

feat: add support for catalogs with dlx#10434

Merged
zkochan merged 5 commits into
pnpm:mainfrom
Netail:feat/dlx-catalog
Jan 26, 2026
Merged

feat: add support for catalogs with dlx#10434
zkochan merged 5 commits into
pnpm:mainfrom
Netail:feat/dlx-catalog

Conversation

@Netail

@Netail Netail commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

Add support for the catalog: protocol when using pnpm dlx or pnpx

Closes # #10249

const resolvedPkgs = await Promise.all(pkgs.map(async (pkg) => {
const { alias, bareSpecifier } = parseWantedDependency(pkg) || {}
if (alias == null) return pkg
const resolvedBareSpecifier = resolveCatalogProtocol(catalogResolver, alias, bareSpecifier ?? '')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure if we should default this to an empty string; catalogResolver does not support undefined, but parseWantedDependency returns string or undefined

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like we only want to call resolveCatalogProtocol if bareSpecifier != null based on your explanation. Something like this should be more correct and less hacky than passing in an empty string?

Suggested change
const resolvedBareSpecifier = resolveCatalogProtocol(catalogResolver, alias, bareSpecifier ?? '')
const resolvedBareSpecifier = bareSpecifier != null
? resolveCatalogProtocol(catalogResolver, alias, bareSpecifier)
: bareSpecifier

@Netail Netail marked this pull request as ready for review January 9, 2026 16:11
@Netail Netail requested a review from zkochan as a code owner January 9, 2026 16:11
Copilot AI review requested due to automatic review settings January 9, 2026 16:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds support for the catalog: protocol when using pnpm dlx or pnpx, allowing users to reference catalog-defined versions when executing packages temporarily.

Key changes:

  • Integration of catalog resolver into the dlx command handler
  • Addition of retry and timeout configuration to the resolver
  • New test case validating catalog protocol resolution with dlx

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pnpm-lock.yaml Adds @pnpm/catalogs.resolver dependency to plugin-commands-script-runners
exec/plugin-commands-script-runners/package.json Declares @pnpm/catalogs.resolver as a workspace dependency
exec/plugin-commands-script-runners/tsconfig.json Adds TypeScript project reference to catalogs/resolver
exec/plugin-commands-script-runners/src/dlx.ts Implements catalog resolution by creating a catalogResolver and resolveCatalogProtocol helper function; also adds retry/timeout options to createResolver
exec/plugin-commands-script-runners/test/dlx.e2e.ts Adds test case verifying catalog protocol works with dlx command
CONTRIBUTING.md Minor improvement: adds shell syntax highlighting to code block
.changeset/curly-dryers-jam.md Documents the new feature in the changeset
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +404 to +421
test('dlx with catalog', async () => {
prepareEmpty()

await dlx.handler({
...DEFAULT_OPTS,
dir: path.resolve('project'),
storeDir: path.resolve('store'),
cacheDir: path.resolve('cache'),
dlxCacheMaxAge: Infinity,
catalogs: {
default: {
shx: '^0.3.4',
},
},
}, ['shx@catalog:'])

verifyDlxCache(createCacheKey('shx@0.3.4'))
})

Copilot AI Jan 9, 2026

Copy link

Choose a reason for hiding this comment

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

The test covers the happy path for catalog resolution, but doesn't include tests for error cases such as:

  1. Catalog entry not found (e.g., 'shx@catalog:' when shx is not in the default catalog)
  2. Named catalog not found (e.g., 'shx@catalog:nonexistent')
  3. Invalid catalog configuration (recursive catalog reference, workspace protocol, etc.)

These error conditions are handled in the resolveCatalogProtocol function and should be tested to ensure proper error messages are displayed to users when they misconfigure catalogs with dlx.

Copilot uses AI. Check for mistakes.
@zkochan zkochan requested a review from gluxon January 13, 2026 13:51
@gluxon gluxon self-assigned this Jan 13, 2026
@gluxon

gluxon commented Jan 13, 2026

Copy link
Copy Markdown
Member

I'll take a look at this and review. Thanks!

const resolvedPkgs = await Promise.all(pkgs.map(async (pkg) => {
const { alias, bareSpecifier } = parseWantedDependency(pkg) || {}
if (alias == null) return pkg
const resolvedBareSpecifier = resolveCatalogProtocol(catalogResolver, alias, bareSpecifier ?? '')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It sounds like we only want to call resolveCatalogProtocol if bareSpecifier != null based on your explanation. Something like this should be more correct and less hacky than passing in an empty string?

Suggested change
const resolvedBareSpecifier = resolveCatalogProtocol(catalogResolver, alias, bareSpecifier ?? '')
const resolvedBareSpecifier = bareSpecifier != null
? resolveCatalogProtocol(catalogResolver, alias, bareSpecifier)
: bareSpecifier

Comment thread exec/plugin-commands-script-runners/src/dlx.ts Outdated
Comment thread CONTRIBUTING.md Outdated

@gluxon gluxon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the updates!

Comment thread .changeset/curly-dryers-jam.md
Comment thread .changeset/curly-dryers-jam.md Outdated
Netail and others added 2 commits January 25, 2026 22:50
Co-authored-by: Brandon Cheng <gluxon@users.noreply.github.com>
Co-authored-by: Brandon Cheng <gluxon@users.noreply.github.com>
@zkochan zkochan merged commit 8eee416 into pnpm:main Jan 26, 2026
11 of 12 checks passed
@welcome

welcome Bot commented Jan 26, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

@Netail Netail deleted the feat/dlx-catalog branch January 26, 2026 07:25
zkochan pushed a commit that referenced this pull request Feb 6, 2026
* feat: add support for catalogs with dlx

* fix: feedback

* Update .changeset/curly-dryers-jam.md

Co-authored-by: Brandon Cheng <gluxon@users.noreply.github.com>

* Update .changeset/curly-dryers-jam.md

Close #10249

Co-authored-by: Brandon Cheng <gluxon@users.noreply.github.com>

---------

Co-authored-by: Brandon Cheng <gluxon@users.noreply.github.com>
@Netail

Netail commented Feb 11, 2026

Copy link
Copy Markdown
Contributor Author

@gluxon @zkochan Mhm okay, I don't think it works as expected yet.

We seem to be getting a ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_SPEC, while pnpm config list does show the dependency listed. Perhaps the catalogs are not fetched from the workspace file when using dlx?
I thought it did, as some other stuff is read from the workspace file

@gluxon

gluxon commented Feb 12, 2026

Copy link
Copy Markdown
Member

It looks like dlx has a special case when reading pnpm's config. I suspect that behavior is likely for performance.

ignoreNonAuthSettingsFromLocal: isDlxOrCreateCommand,

Here's the instructions for testing locally. When you have a fix up, it should be possible to check whether your fix works by running pd dlx.

https://github.com/pnpm/pnpm/blob/main/CONTRIBUTING.md#setting-up-the-environment

I generally recommend testing locally every PR you open before asking for a review. 🙂

@Netail

Netail commented Feb 12, 2026

Copy link
Copy Markdown
Contributor Author

It looks like dlx has a special case when reading pnpm's config. I suspect that behavior is likely for performance.

ignoreNonAuthSettingsFromLocal: isDlxOrCreateCommand,

Here's the instructions for testing locally. When you have a fix up, it should be possible to check whether your fix works by running pd dlx.

https://github.com/pnpm/pnpm/blob/main/CONTRIBUTING.md#setting-up-the-environment

I generally recommend testing locally every PR you open before asking for a review. 🙂

I think so, yes. Didn't knew it wouldn't fetch the workspace file. For me the pb command doesn't work, do I need to install something extra?

@zkochan

zkochan commented Feb 13, 2026

Copy link
Copy Markdown
Member

It is pd, not pb.

@Netail

Netail commented Feb 13, 2026

Copy link
Copy Markdown
Contributor Author

It is pd, not pb.

Woops, I mean pd.

Seems to be getting a ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_SPEC  No catalog entry 'esbuild' was found for catalog 'default'. when running pnpm link --dir ./pnpm/dev -g in the main branch & a zsh: command not found: pd when running pd

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.

4 participants