#15034·pnpm

Rust CLI (v12): `pnpm run <TAB>` no longer completes package.json scripts (completion-server ignores the manifest)

Author: naborPMCreated Sep 17, 2026Updated Sep 17, 2026
Labelstype: bug

Last pnpm version that worked

11.9.0 (Node CLI, @pnpm/exe). Verified directly; presumably every Node-based release, since script completion for pnpm run was the behaviour behind #5426 and #7964 (both closed as completed).

pnpm version

12.4.2 (Rust CLI, installed via Homebrew, which builds pnpm/crates/cli from the v12.4.2 tag). Same on main as far as the source goes (see below).

Code to reproduce the issue

bash
mkdir repro && cd repro
printf '{"name":"repro","version":"1.0.0","scripts":{"hello":"echo hi","build":"echo b"}}' > package.json

# This is exactly what the generated fish/bash/zsh completion scripts run for `pnpm run <TAB>`:
SHELL=fish COMP_LINE="pnpm run " COMP_POINT=9 pnpm completion-server -- pnpm run ""
# -> prints nothing, exit 0 (same with SHELL=bash / SHELL=zsh, and with COMP_CWORD=2 set)

# Control: command and option completion still work in the same directory
SHELL=fish COMP_LINE="pnpm " COMP_POINT=5 pnpm completion-server -- pnpm ""            # access, add, ...
SHELL=fish COMP_LINE="pnpm run --" COMP_POINT=11 pnpm completion-server -- pnpm run --  # --if-present, ...

Comparison with the Node CLI in the same directory (11.9.0 downloaded by pnpm 12 through packageManager):

bash
SHELL=fish COMP_CWORD=2 COMP_LINE="pnpm run " COMP_POINT=9 <pnpm-11.9.0> completion-server -- pnpm run ""
# build
# hello

Through the shell itself (fish 4.9.3, completion file from pnpm completion fish of 12.4.2):

bash
fish -c 'complete -C "pnpm run "'   # empty
fish -c 'complete -C "pnpm "'       # access, add, adduser, ...

Expected behavior

pnpm run <TAB> (and pnpm run <prefix><TAB>) offers the script names from the nearest package.json, as the Node CLI does.

Actual behavior

completion-server returns nothing for the script position, so the shell offers no candidates. The generated completion scripts use complete -f / -o default off, so there is no fallback either.

Additional information

  • Cause, as far as I can tell: in pnpm/crates/cli/src/cli_args/completion.rs, complete_words derives candidates only from the clap Command tree (visible_subcommands, visible_options, option_values, visible_possible_values). Nothing in the module reads a manifest or the current directory, so no dynamic completion (scripts) is possible. The file is identical in this respect on main at the time of filing.
  • Pinning packageManager: [email protected] in the project does not restore it: completion-server is answered by the installed Rust binary before any delegation to the pinned version (consistent with #7959), so projects that are still on 11.x lose script completion as soon as the globally installed pnpm is 12.
  • Related: #14655 (asks for pnpm exec completion, which would need the same manifest/project awareness).
  • Environment: macOS 15 (Darwin 24.6.0), arm64, fish 4.9.3, pnpm 12.4.2 from Homebrew (/opt/homebrew/Cellar/pnpm/12.4.2).
  • Workaround I am using: a fish completion that adds jq -r '(.scripts // {}) | to_entries[] | "\(.key)\t\(.value)"' over the nearest package.json at the script position after run, on top of pnpm completion-server for commands and flags.

Node.js version

22.23.1 (not involved: the Rust binary answers completion-server itself without spawning Node).

Operating System

macOS