Skip to content

feat: add pnpm stage command#11863

Merged
zkochan merged 9 commits into
pnpm:mainfrom
JoviDeCroock:implement-npm-stage
May 23, 2026
Merged

feat: add pnpm stage command#11863
zkochan merged 9 commits into
pnpm:mainfrom
JoviDeCroock:implement-npm-stage

Conversation

@JoviDeCroock

@JoviDeCroock JoviDeCroock commented May 22, 2026

Copy link
Copy Markdown
Contributor

Note

This is largely authored by GPT5.5 based on the npm/cli PR's, afterwards it needed some guidance to better adhere to the repository standards.

Resolves #11796

Summary

Implements npm's newly released staged publishing flow in pnpm, following npm/cli#9379 and including the stage download --json package-name keying fix from npm/cli#9380/#9381.

I ran into some issues where workspace:* was kept around when using npm stage publish replacing my regular pnpm publish. Hence why I wanted to try and contribute this.

Adds pnpm stage with these subcommands:

  • pnpm stage publish [<tarball>|<dir>] — stage a package for publishing without OTP prompting
  • pnpm stage list [<package-spec>] — list staged package versions
  • pnpm stage view <stage-id> — inspect one staged package
  • pnpm stage approve <stage-id> — approve and publish a staged package, with OTP handling
  • pnpm stage reject <stage-id> — reject a staged package, with OTP handling
  • pnpm stage download <stage-id> — download the staged tarball for inspection

Implementation notes

  • Reuses pnpm's existing publish/pack path for stage publish and passes stage: true through to libnpmpublish.
  • Bumps libnpmpublish to ^11.2.0, which contains the npm staged-publish endpoint support.
  • Adds stage-specific registry calls for list/view/approve/reject/download.
  • Keeps stage publish free of OTP handling; OTP remains deferred to approve/reject.
  • Emits stageId in stage publish --json when the registry returns it.
  • Keys stage download --json output by package name, matching the npm follow-up fixes and avoiding an undefined top-level key.
  • Adds a changeset for @pnpm/releasing.commands and pnpm.

Summary by CodeRabbit

  • New Features

    • Added pnpm stage command with subcommands: publish, list, view, approve, reject, download
    • Staged publishing integrated into the publish flow and shown in CLI help
  • Tests

    • Added/expanded tests for stage publish (dry-run and JSON), list, view, approve/reject, and download behaviors
  • Chores

    • Workspace dependency bumped and changeset added for release planning

Review Change Stack

@JoviDeCroock JoviDeCroock requested a review from zkochan as a code owner May 22, 2026 18:57
Copilot AI review requested due to automatic review settings May 22, 2026 18:57
@welcome

welcome Bot commented May 22, 2026

Copy link
Copy Markdown

💖 Thanks for opening this pull request! 💖
Please be patient and we will get back to you as soon as we can.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@JoviDeCroock JoviDeCroock force-pushed the implement-npm-stage branch from f68a3ff to 8c11b4d Compare May 22, 2026 18:57
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new pnpm stage CLI with subcommands (publish, list, view, approve, reject, download), threads a stage mode through publish flows (headers/command choice and stageId in responses), updates CLI wiring/exports and workspace refs, and adds comprehensive tests using an ephemeral registry.

Changes

Staged Publishing Feature

Layer / File(s) Summary
CLI registration and workspace setup
.changeset/stage-publish.md, pnpm-workspace.yaml, pnpm/src/cmd/help.ts, pnpm/src/cmd/index.ts, releasing/commands/package.json, releasing/commands/src/index.ts, releasing/commands/tsconfig.json
Registers the stage command in the pnpm CLI and help, exports it from @pnpm/releasing.commands, bumps libnpmpublish to ^11.2.0, adds @pnpm/network.auth-header dependency, and adds a TS project reference for auth-header.
Publish mode extension for staging
releasing/commands/src/publish/publishPackedPkg.ts, releasing/commands/src/publish/recursivePublish.ts, releasing/commands/src/publish/otp.ts
publishPackedPkg and createPublishOptions gain a stage flag and stage-aware types/headers/command choice; staged publishes use context.publish() and populate summary.stageId, while non-staged retains OTP-aware publish flow. recursivePublish threads stage into argv by prefixing stage when requested; OtpPublishResponse gains optional stageId.
Stage command implementation and subcommands
releasing/commands/src/stage.ts
New stage command module exposes CLI option types, completion, help, and handler routing to publish, list, view, approve, reject, download. Implements registry selection, OTP-aware requests, paginated listing, UUID validation, tarball summarization (shasum/integrity/bundled deps), JSON vs human output, and rendering helpers.
Stage command test suite
releasing/commands/test/stage.test.ts
Jest tests with a local HTTP registry mock validating stage publish --json, stage publish --dry-run, stage list/view pagination and formatting, stage list version-spec rejection, stage approve/reject OTP/header enforcement, and stage download --json tarball writing and metadata assertions. Includes registry and request helpers.

Sequence Diagram(s)

The sequence diagrams visualizing CLI wiring and stage publish flow are embedded in the hidden review artifact above.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • pnpm/pnpm#11495: Modifies publish option/auth-token construction in the same publish flow touched here.
  • pnpm/pnpm#11478: Overlaps publish summary and publishPackedPkg changes.

Suggested reviewers

  • zkochan

Poem

🐇 I hopped through code to stage a little feat,
Six subcommands ready, registry calls neat,
Tarballs tallied, checksums safely spun,
Approve or reject — the rabbit's work is done,
Stage set, publish queued, I hop into the sun.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: add pnpm stage command' directly and clearly describes the main change: adding a new top-level 'stage' command to pnpm with all its subcommands (publish, list, view, approve, reject, download).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Adds support for npm’s staged publishing workflow to pnpm by introducing a new pnpm stage command (publish/list/view/approve/reject/download) and wiring staged publishing into the existing pack/publish pipeline.

Changes:

  • Introduces a new stage command in @pnpm/releasing.commands and registers it in the pnpm CLI/help output.
  • Extends the publish flow to support staged publishing (including returning stageId from the registry when available).
  • Updates dependencies/lockfiles (notably libnpmpublish^11.2.0) and adds Jest coverage for the new command.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
releasing/commands/src/stage.ts Implements pnpm stage subcommands and registry interactions (including tarball download + summarization).
releasing/commands/test/stage.test.ts Adds integration-style tests covering stage publish/list/view/approve/reject/download behaviors.
releasing/commands/src/publish/publishPackedPkg.ts Adds stage option support, sets staged publish headers/options, and captures stageId in summaries.
releasing/commands/src/publish/recursivePublish.ts Adjusts recursive publish argv to reflect stage publish when staging recursively.
releasing/commands/src/index.ts Exports the new stage command module.
releasing/commands/package.json Adds workspace dependency needed for auth header computation.
pnpm/src/cmd/index.ts Registers stage as a top-level pnpm command.
pnpm/src/cmd/help.ts Adds stage to the generated help command list.
pnpm-workspace.yaml Bumps libnpmpublish to ^11.2.0.
pnpm-lock.yaml Updates lockfile for libnpmpublish bump and new workspace dependency.
.changeset/stage-publish.md Declares a minor release for pnpm and @pnpm/releasing.commands due to the new command.
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 thread releasing/commands/src/stage.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@releasing/commands/src/stage.ts`:
- Around line 522-525: The JSON parsing in the stream.on('end') handler can
throw synchronously and escape the promise rejection path; wrap the manifest =
JSON.parse(Buffer.concat(chunks).toString()) call in a try/catch inside the
stream.on('end') callback (the block handling header.name ===
'package/package.json') and call reject(err) with the parse error (or emit an
error) so malformed package.json leads to the promise being rejected instead of
throwing.

In `@releasing/commands/test/stage.test.ts`:
- Around line 205-215: The server callback that calls handler(request) must
guard against rejections so responses are always closed: in the async
createServer callback (the function that reads the body into request and then
calls handler(request)), wrap the await handler(request) call in try/catch; on
catch call writeResponse(res, { status: 500, body: String(err) }) (or a minimal
error response) and ensure the response is ended so the test doesn't stall, then
rethrow or log as needed to make the test fail fast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 82f445dc-86ef-472f-8893-9a480eb25068

📥 Commits

Reviewing files that changed from the base of the PR and between 976504f and 8c11b4d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • .changeset/stage-publish.md
  • pnpm-workspace.yaml
  • pnpm/src/cmd/help.ts
  • pnpm/src/cmd/index.ts
  • releasing/commands/package.json
  • releasing/commands/src/index.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • releasing/commands/src/stage.ts
  • releasing/commands/test/stage.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run benchmark on ubuntu-latest
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use trailing commas in TypeScript code
Prefer functions over classes in TypeScript code
Declare functions after they are used, relying on function hoisting in TypeScript
Functions should have no more than two or three arguments; use a single options object instead for multiple parameters in TypeScript
Follow import order in TypeScript: 1) standard libraries, 2) external dependencies (alphabetically sorted), 3) relative imports
Write self-explanatory code in TypeScript; avoid comments that restate what the code already says. Use comments only for non-obvious reasons, hidden invariants, or workarounds
Use JSDoc for function contracts (preconditions, postconditions, edge cases), not for re-narrating the function body in TypeScript

Files:

  • pnpm/src/cmd/help.ts
  • pnpm/src/cmd/index.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • releasing/commands/src/index.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/stage.ts
  • releasing/commands/test/stage.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not use instanceof Error for error type checking in Jest tests; use util.types.isNativeError() instead in TypeScript

Files:

  • releasing/commands/test/stage.test.ts
🧠 Learnings (2)
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • pnpm/src/cmd/help.ts
  • pnpm/src/cmd/index.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • releasing/commands/src/index.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/stage.ts
  • releasing/commands/test/stage.test.ts
📚 Learning: 2026-05-05T23:03:04.286Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11479
File: __utils__/scripts/package.json:6-9
Timestamp: 2026-05-05T23:03:04.286Z
Learning: The pattern cross-env NODE_OPTIONS="$NODE_OPTIONS ..." in package.json scripts is an established convention in the pnpm/pnpm repository and is used across many packages (e.g., fs/hard-link-dir, worker, __utils__/scripts). Do not flag this as a cross-platform issue in individual files; if a change is needed, apply it as a repo-wide change in a separate PR. Scope this guidance to all package.json files in the repo; use the minimatch pattern '**/package.json' to identify relevant files and review changes at the repository level rather than per-file.

Applied to files:

  • releasing/commands/package.json
🪛 OpenGrep (1.21.0)
releasing/commands/src/stage.ts

[ERROR] 513-513: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔇 Additional comments (8)
.changeset/stage-publish.md (1)

1-7: LGTM!

pnpm-workspace.yaml (1)

223-223: LGTM!

pnpm/src/cmd/help.ts (1)

247-250: LGTM!

pnpm/src/cmd/index.ts (1)

22-22: LGTM!

Also applies to: 170-170

releasing/commands/package.json (1)

56-56: LGTM!

releasing/commands/src/index.ts (1)

4-4: LGTM!

releasing/commands/src/publish/publishPackedPkg.ts (1)

19-19: LGTM!

Also applies to: 50-50, 78-79, 91-91, 109-109, 113-126, 158-165, 195-195, 198-198, 201-201, 224-224, 230-233

releasing/commands/src/publish/recursivePublish.ts (1)

116-116: LGTM!

Also applies to: 132-132

Comment thread releasing/commands/src/stage.ts Outdated
Comment thread releasing/commands/test/stage.test.ts Outdated
@github-actions

github-actions Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Scenario: Isolated linker: fresh restore, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.346 ± 0.125 2.210 2.629 1.00
pacquet@main 2.358 ± 0.075 2.219 2.458 1.01 ± 0.06
pnpm 4.586 ± 0.067 4.507 4.682 1.95 ± 0.11
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.34632760892,
      "stddev": 0.12467107940163871,
      "median": 2.32572393792,
      "user": 2.77029644,
      "system": 3.45115922,
      "min": 2.21027521542,
      "max": 2.62886738542,
      "times": [
        2.31601781342,
        2.33543006242,
        2.21027521542,
        2.62886738542,
        2.47413014142,
        2.2434375044199997,
        2.36410399042,
        2.24673936642,
        2.28908081742,
        2.3551937924199997
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.3584218758199995,
      "stddev": 0.07505238960390247,
      "median": 2.35054293292,
      "user": 2.74734154,
      "system": 3.45497102,
      "min": 2.21893259242,
      "max": 2.45845517742,
      "times": [
        2.34877093842,
        2.39555470442,
        2.3505328944199997,
        2.35055297142,
        2.2773870444199997,
        2.4460219844199997,
        2.31815619242,
        2.41985425842,
        2.21893259242,
        2.45845517742
      ]
    },
    {
      "command": "pnpm",
      "mean": 4.586416998719999,
      "stddev": 0.06651876924969248,
      "median": 4.55849862492,
      "user": 7.73859044,
      "system": 4.004200320000001,
      "min": 4.50713754542,
      "max": 4.68165852142,
      "times": [
        4.50713754542,
        4.67069628042,
        4.54944307142,
        4.55099878242,
        4.51491857942,
        4.65008052942,
        4.5358256274199995,
        4.56599846742,
        4.63741258242,
        4.68165852142
      ]
    }
  ]
}

Scenario: Isolated linker: fresh restore, hot cache + hot store

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 683.5 ± 42.2 657.1 800.9 1.00
pacquet@main 719.7 ± 76.7 657.5 858.2 1.05 ± 0.13
pnpm 2437.4 ± 135.0 2301.6 2761.0 3.57 ± 0.30
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.6834689917400001,
      "stddev": 0.04215535469085949,
      "median": 0.6710384172400001,
      "user": 0.37682859999999996,
      "system": 1.46836914,
      "min": 0.6571289197400001,
      "max": 0.80086996074,
      "times": [
        0.80086996074,
        0.6906054557400001,
        0.66779901474,
        0.6571289197400001,
        0.6711350947400001,
        0.67327586874,
        0.6651990157400001,
        0.67094173974,
        0.67372750274,
        0.66400734474
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.71966333734,
      "stddev": 0.07674080257156707,
      "median": 0.6705865562400001,
      "user": 0.3796667,
      "system": 1.4665477399999998,
      "min": 0.6574542427400001,
      "max": 0.8581749537400001,
      "times": [
        0.82095047574,
        0.6688616027400001,
        0.78165365074,
        0.65872084174,
        0.6596287337400001,
        0.6723115097400001,
        0.8581749537400001,
        0.7512405587400001,
        0.6574542427400001,
        0.66763680374
      ]
    },
    {
      "command": "pnpm",
      "mean": 2.43741995024,
      "stddev": 0.13496512892093623,
      "median": 2.43106602674,
      "user": 2.9883540999999996,
      "system": 2.1754937400000003,
      "min": 2.3016253507399997,
      "max": 2.76096254374,
      "times": [
        2.45256325274,
        2.3016253507399997,
        2.3419058757399998,
        2.76096254374,
        2.44309885374,
        2.4632299297399998,
        2.41903319974,
        2.30520294074,
        2.52354253674,
        2.3630350187399998
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.957 ± 0.089 4.778 5.063 1.01 ± 0.03
pacquet@main 4.908 ± 0.086 4.761 5.059 1.00
pnpm 6.404 ± 0.107 6.205 6.530 1.30 ± 0.03
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.9572168311999985,
      "stddev": 0.08905605159296778,
      "median": 4.953987027599999,
      "user": 6.66269576,
      "system": 3.5060043399999996,
      "min": 4.7784364425999994,
      "max": 5.0627103086,
      "times": [
        5.0048889895999995,
        4.9300923716,
        4.916477297599999,
        5.0612300686,
        4.8753279186,
        4.950904222599999,
        5.0627103086,
        5.0350308596,
        4.7784364425999994,
        4.957069832599999
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.908264446099999,
      "stddev": 0.08621498153805772,
      "median": 4.894483470099999,
      "user": 6.65164056,
      "system": 3.48834294,
      "min": 4.761247742599999,
      "max": 5.058843449599999,
      "times": [
        4.761247742599999,
        4.9873054906,
        4.954674294599999,
        4.9680369876,
        4.903364250599999,
        4.8478955116,
        4.883983885599999,
        5.058843449599999,
        4.8856026896,
        4.8316901586
      ]
    },
    {
      "command": "pnpm",
      "mean": 6.4037400266999995,
      "stddev": 0.10666186957213439,
      "median": 6.4347946946,
      "user": 10.283634760000002,
      "system": 4.37835534,
      "min": 6.205159064599999,
      "max": 6.5298714875999995,
      "times": [
        6.2403401056,
        6.3650332056,
        6.205159064599999,
        6.409753010599999,
        6.5147670826,
        6.450027308599999,
        6.4358669666,
        6.452859612599999,
        6.5298714875999995,
        6.4337224226
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, hot cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 3.994 ± 0.147 3.820 4.327 1.01 ± 0.05
pacquet@main 3.958 ± 0.125 3.811 4.112 1.00
pnpm 4.231 ± 0.095 4.113 4.457 1.07 ± 0.04
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 3.9936052031200004,
      "stddev": 0.1474983433733279,
      "median": 3.97796665072,
      "user": 4.3003547399999995,
      "system": 2.2231088,
      "min": 3.82039515022,
      "max": 4.327191943220001,
      "times": [
        4.034314220220001,
        3.90861067322,
        4.327191943220001,
        4.083571254220001,
        3.9291066572199997,
        4.04809333522,
        4.026826644220001,
        3.91789525022,
        3.8400469032199998,
        3.82039515022
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 3.95815218142,
      "stddev": 0.12478903631253288,
      "median": 3.95481471172,
      "user": 4.28708624,
      "system": 2.2235854999999995,
      "min": 3.8112523172199997,
      "max": 4.11234773622,
      "times": [
        3.88000103622,
        3.85990417622,
        4.058871609220001,
        3.84290075822,
        4.07830347522,
        3.8112523172199997,
        4.029628387220001,
        4.11234773622,
        4.0883765182200005,
        3.81993580022
      ]
    },
    {
      "command": "pnpm",
      "mean": 4.23083682812,
      "stddev": 0.0945740783956454,
      "median": 4.21113651872,
      "user": 5.24638144,
      "system": 2.6317564000000004,
      "min": 4.11295795722,
      "max": 4.45664392022,
      "times": [
        4.21601483422,
        4.1621256112200005,
        4.18480532822,
        4.26414166022,
        4.11295795722,
        4.45664392022,
        4.275152016220001,
        4.26195276522,
        4.1683159852200005,
        4.20625820322
      ]
    }
  ]
}

Copilot AI review requested due to automatic review settings May 22, 2026 19:54
@JoviDeCroock JoviDeCroock changed the title feat: add npm stage command feat: add pnpm stage command May 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
releasing/commands/src/stage.ts (1)

412-438: 💤 Low value

Consider consolidating stageRequest parameters into an options object.

This function has 6 parameters. Per coding guidelines, functions should have no more than two or three arguments; use a single options object instead for multiple parameters.

♻️ Suggested refactor
+interface StageRequestOptions {
+  opts: StageOptions
+  registry: string
+  url: string
+  init: StageRequestInit
+  action: string
+  otp?: string
+}
+
 async function stageRequest (
-  opts: StageOptions,
-  registry: string,
-  url: string,
-  init: StageRequestInit,
-  action: string,
-  otp?: string
+  { opts, registry, url, init, action, otp }: StageRequestOptions
 ): Promise<Response> {

As per coding guidelines: "Functions should have no more than two or three arguments; use a single options object instead for multiple parameters in TypeScript."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@releasing/commands/src/stage.ts` around lines 412 - 438, The function
stageRequest currently takes six positional parameters; refactor it to accept a
single options object (e.g., StageRequestParams) that contains { opts:
StageOptions, registry: string, url: string, init: StageRequestInit, action:
string, otp?: string }, update the function signature and body to destructure
those fields, and adjust all call sites accordingly; ensure types are
exported/declared, preserve existing logic that uses createFetchFromRegistry,
getAuthHeader, throwIfOtpRequired, and throwStageRegistryError, and keep the
same request construction (headers, method, timeout) and error behavior after
migration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@releasing/commands/src/stage.ts`:
- Around line 412-438: The function stageRequest currently takes six positional
parameters; refactor it to accept a single options object (e.g.,
StageRequestParams) that contains { opts: StageOptions, registry: string, url:
string, init: StageRequestInit, action: string, otp?: string }, update the
function signature and body to destructure those fields, and adjust all call
sites accordingly; ensure types are exported/declared, preserve existing logic
that uses createFetchFromRegistry, getAuthHeader, throwIfOtpRequired, and
throwStageRegistryError, and keep the same request construction (headers,
method, timeout) and error behavior after migration.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 54818116-586d-4cfe-9907-3384b04f47fc

📥 Commits

Reviewing files that changed from the base of the PR and between 6dae5da and 7e961c5.

📒 Files selected for processing (2)
  • releasing/commands/src/stage.ts
  • releasing/commands/test/stage.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Agent
  • GitHub Check: Compile & Lint
  • GitHub Check: Analyze (javascript)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use trailing commas in TypeScript code
Prefer functions over classes in TypeScript code
Declare functions after they are used, relying on function hoisting in TypeScript
Functions should have no more than two or three arguments; use a single options object instead for multiple parameters in TypeScript
Follow import order in TypeScript: 1) standard libraries, 2) external dependencies (alphabetically sorted), 3) relative imports
Write self-explanatory code in TypeScript; avoid comments that restate what the code already says. Use comments only for non-obvious reasons, hidden invariants, or workarounds
Use JSDoc for function contracts (preconditions, postconditions, edge cases), not for re-narrating the function body in TypeScript

Files:

  • releasing/commands/test/stage.test.ts
  • releasing/commands/src/stage.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not use instanceof Error for error type checking in Jest tests; use util.types.isNativeError() instead in TypeScript

Files:

  • releasing/commands/test/stage.test.ts
🧠 Learnings (1)
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • releasing/commands/test/stage.test.ts
  • releasing/commands/src/stage.ts
🔇 Additional comments (26)
releasing/commands/src/stage.ts (15)

1-27: LGTM!


29-52: LGTM!


54-73: LGTM!

Also applies to: 74-153


155-184: LGTM!


186-215: LGTM!


217-251: LGTM!


253-290: LGTM!


292-310: LGTM!


312-356: LGTM!


358-373: LGTM!


374-410: LGTM!


440-511: LGTM!


540-545: LGTM!


513-539: LGTM!

Also applies to: 546-576


578-635: LGTM!

releasing/commands/test/stage.test.ts (11)

1-28: LGTM!


29-60: LGTM!


62-112: LGTM!


114-117: LGTM!


119-164: LGTM!


166-207: LGTM!


209-230: LGTM!


233-243: LGTM!


256-261: LGTM!


245-255: LGTM!

Also applies to: 262-271


273-300: LGTM!

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

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread releasing/commands/src/stage.ts Outdated
Comment thread releasing/commands/src/stage.ts Outdated
Comment thread releasing/commands/src/publish/publishPackedPkg.ts Outdated
@zkochan zkochan force-pushed the implement-npm-stage branch from 7e961c5 to 2197e2e Compare May 23, 2026 16:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@releasing/commands/src/publish/publishPackedPkg.ts`:
- Around line 112-120: The staged-publish path calls context.publish() directly
and thus bypasses the web-auth/doneUrl wrapper in publishWithOtpHandling(),
causing staged publishes to miss browser-based auth; change the logic so that
when isStage is true you still call publishWithOtpHandling({ context, manifest:
publishedManifest, publishOptions, tarballData, /* new flag */ skipOtpRetries:
true }) (or add an equivalent parameter to publishWithOtpHandling) so OTP
retry/prompt behavior is suppressed but the web-auth flow is preserved; update
publishWithOtpHandling signature and StagePublishResponse typing as needed to
accept and propagate the skipOtpRetries flag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 21f12109-21fd-422c-bf39-46a8bc95970f

📥 Commits

Reviewing files that changed from the base of the PR and between 7e961c5 and 2197e2e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .changeset/stage-publish.md
  • pnpm-workspace.yaml
  • pnpm/src/cmd/help.ts
  • pnpm/src/cmd/index.ts
  • releasing/commands/package.json
  • releasing/commands/src/index.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • releasing/commands/src/stage.ts
  • releasing/commands/test/stage.test.ts
  • releasing/commands/tsconfig.json
✅ Files skipped from review due to trivial changes (2)
  • .changeset/stage-publish.md
  • releasing/commands/tsconfig.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use trailing commas in TypeScript code
Prefer functions over classes in TypeScript code
Declare functions after they are used, relying on function hoisting in TypeScript
Functions should have no more than two or three arguments; use a single options object instead for multiple parameters in TypeScript
Follow import order in TypeScript: 1) standard libraries, 2) external dependencies (alphabetically sorted), 3) relative imports
Write self-explanatory code in TypeScript; avoid comments that restate what the code already says. Use comments only for non-obvious reasons, hidden invariants, or workarounds
Use JSDoc for function contracts (preconditions, postconditions, edge cases), not for re-narrating the function body in TypeScript

Files:

  • releasing/commands/src/index.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • pnpm/src/cmd/index.ts
  • pnpm/src/cmd/help.ts
  • releasing/commands/test/stage.test.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/stage.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not use instanceof Error for error type checking in Jest tests; use util.types.isNativeError() instead in TypeScript

Files:

  • releasing/commands/test/stage.test.ts
🧠 Learnings (2)
📚 Learning: 2026-05-05T23:03:04.286Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11479
File: __utils__/scripts/package.json:6-9
Timestamp: 2026-05-05T23:03:04.286Z
Learning: The pattern cross-env NODE_OPTIONS="$NODE_OPTIONS ..." in package.json scripts is an established convention in the pnpm/pnpm repository and is used across many packages (e.g., fs/hard-link-dir, worker, __utils__/scripts). Do not flag this as a cross-platform issue in individual files; if a change is needed, apply it as a repo-wide change in a separate PR. Scope this guidance to all package.json files in the repo; use the minimatch pattern '**/package.json' to identify relevant files and review changes at the repository level rather than per-file.

Applied to files:

  • releasing/commands/package.json
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • releasing/commands/src/index.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • pnpm/src/cmd/index.ts
  • pnpm/src/cmd/help.ts
  • releasing/commands/test/stage.test.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/stage.ts
🪛 OpenGrep (1.21.0)
releasing/commands/src/stage.ts

[ERROR] 529-529: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔇 Additional comments (8)
pnpm-workspace.yaml (1)

223-223: LGTM!

Also applies to: 395-395, 436-436

pnpm/src/cmd/help.ts (1)

247-250: LGTM!

pnpm/src/cmd/index.ts (1)

22-22: LGTM!

Also applies to: 169-170

releasing/commands/package.json (1)

56-56: LGTM!

releasing/commands/src/index.ts (1)

4-4: LGTM!

releasing/commands/src/publish/recursivePublish.ts (1)

116-116: LGTM!

Also applies to: 132-132

releasing/commands/src/stage.ts (1)

63-65: Resolve: --registry is accepted for pnpm stage via forwarded publish CLI option types
releasing/commands/src/stage.ts forwards cliOptionsTypes() to publishCommand.cliOptionsTypes(), and publish.ts’s cliOptionsTypes() is built from rcOptionsTypes(); publish.ts already includes the registry option in its option types.

releasing/commands/test/stage.test.ts (1)

1-300: LGTM!

Comment thread releasing/commands/src/publish/publishPackedPkg.ts Outdated
- Type stageId via OtpPublishResponse so publishPackedPkg no longer needs a cast.
- Hoist fetchFromRegistry + auth header into a per-subcommand StageContext.
- Send npm-auth-type: web on all stage requests, not just approve/reject.
- Consolidate stageRequest / stageRequestWithOtp / stageJsonRequest into (context, params) form.
Copilot AI review requested due to automatic review settings May 23, 2026 16:25

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
releasing/commands/src/publish/publishPackedPkg.ts (1)

113-120: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve the web-auth wrapper on the staged publish path.

This branch still skips publishWithOtpHandling(), so staged publishes bypass the doneUrl/browser-auth flow that createPublishContext() is explicitly wired to support. Users without a preconfigured token can still fail pnpm stage publish instead of being taken through web auth.

Suggested shape
-  const response = isStage
-    ? await context.publish(publishedManifest, tarballData, publishOptions)
-    : await publishWithOtpHandling({
-      context,
-      manifest: publishedManifest,
-      publishOptions,
-      tarballData,
-    })
+  const response = await publishWithOtpHandling({
+    context,
+    manifest: publishedManifest,
+    publishOptions,
+    tarballData,
+    skipOtpRetries: isStage,
+  })

Then keep OTP prompting/retries disabled inside publishWithOtpHandling() when skipOtpRetries is set, but still run the existing web-auth flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@releasing/commands/src/publish/publishPackedPkg.ts` around lines 113 - 120,
The staged publish path currently calls context.publish directly and bypasses
the web-auth wrapper; change the isStage branch so it calls
publishWithOtpHandling(...) as well, passing the same context,
publishedManifest, tarballData and publishOptions but set skipOtpRetries: true
for staged publishes so OTP prompting/retries stay disabled while still running
the createPublishContext/browser-auth/doneUrl flow; ensure
publishWithOtpHandling is invoked for both staged and non-staged publishes (only
toggle skipOtpRetries when isStage).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@releasing/commands/src/publish/publishPackedPkg.ts`:
- Around line 113-120: The staged publish path currently calls context.publish
directly and bypasses the web-auth wrapper; change the isStage branch so it
calls publishWithOtpHandling(...) as well, passing the same context,
publishedManifest, tarballData and publishOptions but set skipOtpRetries: true
for staged publishes so OTP prompting/retries stay disabled while still running
the createPublishContext/browser-auth/doneUrl flow; ensure
publishWithOtpHandling is invoked for both staged and non-staged publishes (only
toggle skipOtpRetries when isStage).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1d3d3ecc-5530-425f-8097-d758e4ed9806

📥 Commits

Reviewing files that changed from the base of the PR and between 2197e2e and 38558f9.

📒 Files selected for processing (3)
  • releasing/commands/src/publish/otp.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/stage.ts
✅ Files skipped from review due to trivial changes (1)
  • releasing/commands/src/publish/otp.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use trailing commas in TypeScript code
Prefer functions over classes in TypeScript code
Declare functions after they are used, relying on function hoisting in TypeScript
Functions should have no more than two or three arguments; use a single options object instead for multiple parameters in TypeScript
Follow import order in TypeScript: 1) standard libraries, 2) external dependencies (alphabetically sorted), 3) relative imports
Write self-explanatory code in TypeScript; avoid comments that restate what the code already says. Use comments only for non-obvious reasons, hidden invariants, or workarounds
Use JSDoc for function contracts (preconditions, postconditions, edge cases), not for re-narrating the function body in TypeScript

Files:

  • releasing/commands/src/stage.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
🧠 Learnings (1)
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • releasing/commands/src/stage.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
🔇 Additional comments (1)
releasing/commands/src/stage.ts (1)

227-238: LGTM!

Also applies to: 255-259, 265-270, 276-282, 288-293, 350-429

@github-actions

github-actions Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

zkochan added 2 commits May 23, 2026 19:09
The registry responds to stage approve/reject with 401 and a body of
`{ authUrl, doneUrl }` when the user must complete a browser-based
authentication, but `www-authenticate` does not contain "otp" in that
case. The previous check missed this and surfaced the response as a
generic STAGE_REGISTRY_ERROR. Detect web-auth responses by body shape so
withOtpHandling can drive the polling flow.
Add tests that lock in the OTP-trigger detection on the stage command:
- 401 with `{authUrl, doneUrl}` enters the web-auth flow, exercised here
  via the full polling-completion path (registry returns a token, the
  retry request carries it as npm-otp).
- 401 with web-auth body but no TTY surfaces as OTP_NON_INTERACTIVE.
- 401 without any OTP signals stays a STAGE_REGISTRY_ERROR so we don't
  over-trigger the OTP flow on unrelated unauthorized responses.
Copilot AI review requested due to automatic review settings May 23, 2026 17:20

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Calling `context.publish()` directly for staged publishes bypassed
`publishWithOtpHandling`, so users without a preconfigured token had no
path through the browser-based authentication flow on `pnpm stage
publish`. Route the staged publish through the same wrapper as the
regular publish; `OtpPublishResponse.stageId` carries the registry's
identifier when set.
The 631-line `stage.ts` carried six subcommands, tarball parsing,
auth/request plumbing, error class, OTP detection, and rendering helpers
in one file. Reorganized to match the existing `publish/` folder layout:

- `stage/{index,help,publish,list,view,approve,reject,download,context,
  request,parsing,rendering,errors,types}.ts` — one concept per file.
- `tarball/{publishSummary,summarizeTarball}.ts` — shared between
  `publish` and `stage` instead of duplicated. `PublishSummary` and
  `extractBundledDependencies` now live with the tarball helper rather
  than inside the publish subfolder, so other commands can reuse them
  without reaching into `publish/`.

Behavior unchanged. Also dropped `StageRegistryError`'s redundant
`statusCode` field (was identical to `status`) to bring it in line with
`FailedToPublishError`.
Copilot AI review requested due to automatic review settings May 23, 2026 17:51

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@JoviDeCroock

Copy link
Copy Markdown
Contributor Author

Thank you so much for helping get this over the line, lmk if I can do anything.

@zkochan zkochan merged commit 508e6d8 into pnpm:main May 23, 2026
6 of 8 checks passed
@welcome

welcome Bot commented May 23, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

jerome-benoit added a commit to tinylibs/tinybench that referenced this pull request May 30, 2026
`pnpm stage publish` ships natively in pnpm v11.3.0 (May 2026, PR
pnpm/pnpm#11863) with full subcommand parity to `npm stage`. The project
is already pinned to `pnpm@11.3.0` in `packageManager`, so the feature
is available without a version bump.

* Replace the four `npm stage publish` invocations with their `pnpm`
  equivalents — flags (`--no-git-checks`, `--tag next|beta|alpha`) are
  identical.
* Drop the two-step `npm install -g npm@~11.10.0 && npm install -g
  npm@11.15.0` workaround for npm/cli#9151; only pnpm is needed in the
  publish job now.
* Single package manager across the workflow; `pnpm stage publish` also
  rewrites `workspace:*` correctly should the project ever move to a
  workspace layout.
github-merge-queue Bot pushed a commit to tinylibs/tinybench that referenced this pull request May 30, 2026
* chore: enable staged publishing

Also bumps all the actions using a sha rather than a mutable tag.

* chore: pr feedback

* ci(release): use native pnpm stage publish

`pnpm stage publish` ships natively in pnpm v11.3.0 (May 2026, PR
pnpm/pnpm#11863) with full subcommand parity to `npm stage`. The project
is already pinned to `pnpm@11.3.0` in `packageManager`, so the feature
is available without a version bump.

* Replace the four `npm stage publish` invocations with their `pnpm`
  equivalents — flags (`--no-git-checks`, `--tag next|beta|alpha`) are
  identical.
* Drop the two-step `npm install -g npm@~11.10.0 && npm install -g
  npm@11.15.0` workaround for npm/cli#9151; only pnpm is needed in the
  publish job now.
* Single package manager across the workflow; `pnpm stage publish` also
  rewrites `workspace:*` correctly should the project ever move to a
  workspace layout.

---------

Co-authored-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
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.

Support pnpm stage publish

4 participants