fix(review-queue): atomic stale-safe review transition #131

Open
kreativmonkey wants to merge 131 commits from kreativmonkey/fix-issue-95 into main
Owner

Queue completions now use an explicit review_complete signal with a status-guarded draft→pending UPDATE in both stores; a stale action on a post that already left the draft state conflicts with 409 (review_conflict) instead of overwriting newer composer-scheduled state.

review_complete must map to exactly one explicit action — publish_now: true, or draft: false with an explicitly supplied scheduled_at — and always requires write:schedule. Missing/incomplete/contradictory patches are rejected with 400 before Prepare, so no implicit past timestamp publishes without the publish-now marker.

Past-time rejection is now a Prepare option (RejectPastScheduledAt) so drafts and publish_now stay exempt while schedule paths fail on the past; agent-tools schedule/modify adopt it. OpenAPI, auth/scope DOX, and frontend queue payloads updated accordingly.

Total Go coverage unchanged by this branch (make cover not run locally; store suite covered via sqlite + postgres tests).

CI runs the full suite (incl. make test-postgres) on this branch.

Queue completions now use an explicit `review_complete` signal with a status-guarded `draft→pending` UPDATE in both stores; a stale action on a post that already left the draft state conflicts with 409 (`review_conflict`) instead of overwriting newer composer-scheduled state. `review_complete` must map to exactly one explicit action — `publish_now: true`, or `draft: false` with an explicitly supplied `scheduled_at` — and always requires `write:schedule`. Missing/incomplete/contradictory patches are rejected with 400 before Prepare, so no implicit past timestamp publishes without the publish-now marker. Past-time rejection is now a Prepare option (`RejectPastScheduledAt`) so drafts and `publish_now` stay exempt while schedule paths fail on the past; agent-tools schedule/modify adopt it. OpenAPI, auth/scope DOX, and frontend queue payloads updated accordingly. Total Go coverage unchanged by this branch (make cover not run locally; store suite covered via sqlite + postgres tests). CI runs the full suite (incl. `make test-postgres`) on this branch.
🤖 I have created a release *beep* *boop*
---


## [0.1.3](https://github.com/Goloom-App/goloom/compare/v0.1.2...v0.1.3)
(2026-06-27)


### Features

* **admin:** inspect, retry and acknowledge failed publishes
([1db093b](1db093bb9a))
* **helm:** add Kubernetes Helm chart + docs
([bc53f71](bc53f7132e))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR contains the following updates:

| Update | Change |
|---|---|
| lockFileMaintenance | All locks refreshed |

🔧 This Pull Request updates lock files to use the latest dependency
versions.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 4am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Reworks the landing page after reviewer feedback that the purpose was
unclear and the design read as generic AI marketing.

## Changes
- **Clarify purpose**: reframe around scheduling one post across
*multiple* accounts/networks, explicitly contrasted with Mastodon's
single-account native scheduler. Drop ambiguous "social planning"
wording.
- **Binary-first quickstart**: lead with the static binary instead of
Docker (Docker/K8s noted as optional) — addresses anti-Docker/monolith
feedback.
- **De-slop visuals**: cyan→magenta gradient → calm single-hue cyan;
mesh background + button glow removed; gradient hero text and all emoji
icons dropped; flatter buttons.
- **Sober copy** across hero, value props, features, architecture, CTA.
- **Screenshot zoom**: dependency-free CSS lightbox (click to view full
size).
- **Legal**: slim `/legal` page (MIT license, no-warranty disclaimer,
static-site note), linked from landing + docs footers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The site favicon used an older mark (three squares, single cyan→magenta
gradient) that no longer matches the app. Replace it with the real
goloom logo from `frontend/public/favicon.svg` — three stacked squares
with distinct sky/violet/orange gradients — so the website is consistent
with the app sidebar and PWA icons.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.62.0` →
`8.62.1`](https://renovatebot.com/diffs/npm/typescript-eslint/8.62.0/8.62.1)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.62.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.62.0/8.62.1?slim=true)
|

---

### Release Notes

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.62.1`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8621-2026-06-29)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.62.0...v8.62.1)

This was a version bump only for typescript-eslint to align it with
other projects, there were no code changes.

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.1)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
In case someone want to build the image themself
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker/metadata-action](https://redirect.github.com/docker/metadata-action)
| action | major | `v5` → `v6` |

---

### Release Notes

<details>
<summary>docker/metadata-action (docker/metadata-action)</summary>

###
[`v6.1.0`](https://redirect.github.com/docker/metadata-action/releases/tag/v6.1.0)

[Compare
Source](https://redirect.github.com/docker/metadata-action/compare/v6...v6.1.0)

- Bump
[@&#8203;docker/actions-toolkit](https://redirect.github.com/docker/actions-toolkit)
from 0.79.0 to 0.90.0 in
[#&#8203;613](https://redirect.github.com/docker/metadata-action/pull/613)
- Bump brace-expansion from 1.1.12 to 5.0.6 in
[#&#8203;658](https://redirect.github.com/docker/metadata-action/pull/658)
[#&#8203;630](https://redirect.github.com/docker/metadata-action/pull/630)
- Bump csv-parse from 6.1.0 to 6.2.1 in
[#&#8203;617](https://redirect.github.com/docker/metadata-action/pull/617)
- Bump fast-xml-parser from 5.4.2 to 5.8.0 in
[#&#8203;620](https://redirect.github.com/docker/metadata-action/pull/620)
- Bump flatted from 3.3.3 to 3.4.2 in
[#&#8203;623](https://redirect.github.com/docker/metadata-action/pull/623)
- Bump glob from 10.3.15 to 10.5.0 in
[#&#8203;621](https://redirect.github.com/docker/metadata-action/pull/621)
- Bump handlebars from 4.7.8 to 4.7.9 in
[#&#8203;629](https://redirect.github.com/docker/metadata-action/pull/629)
- Bump lodash from 4.17.23 to 4.18.1 in
[#&#8203;639](https://redirect.github.com/docker/metadata-action/pull/639)
- Bump moment-timezone from 0.6.0 to 0.6.1 in
[#&#8203;619](https://redirect.github.com/docker/metadata-action/pull/619)
- Bump picomatch from 4.0.3 to 4.0.4 in
[#&#8203;626](https://redirect.github.com/docker/metadata-action/pull/626)
- Bump postcss from 8.5.6 to 8.5.10 in
[#&#8203;649](https://redirect.github.com/docker/metadata-action/pull/649)
- Bump tar from 6.2.1 to 7.5.15 in
[#&#8203;657](https://redirect.github.com/docker/metadata-action/pull/657)
- Bump undici from 6.23.0 to 6.25.0 in
[#&#8203;614](https://redirect.github.com/docker/metadata-action/pull/614)
- Bump vite from 7.3.1 to 7.3.2 in
[#&#8203;637](https://redirect.github.com/docker/metadata-action/pull/637)

**Full Changelog**:
<https://github.com/docker/metadata-action/compare/v6.0.0...v6.1.0>

###
[`v6.0.0`](https://redirect.github.com/docker/metadata-action/releases/tag/v6.0.0)

[Compare
Source](https://redirect.github.com/docker/metadata-action/compare/v6...v6)

- Node 24 as default runtime (requires [Actions Runner
v2.327.1](https://redirect.github.com/actions/runner/releases/tag/v2.327.1)
or later) by [@&#8203;crazy-max](https://redirect.github.com/crazy-max)
in
[#&#8203;605](https://redirect.github.com/docker/metadata-action/pull/605)
- List inputs now preserve `#` inside values while still supporting
full-line `#` comments by
[@&#8203;crazy-max](https://redirect.github.com/crazy-max) in
[#&#8203;607](https://redirect.github.com/docker/metadata-action/pull/607)
- Switch to ESM and update config/test wiring by
[@&#8203;crazy-max](https://redirect.github.com/crazy-max) in
[#&#8203;602](https://redirect.github.com/docker/metadata-action/pull/602)
- Bump lodash from 4.17.21 to 4.17.23 in
[#&#8203;588](https://redirect.github.com/docker/metadata-action/pull/588)
- Bump [@&#8203;actions/core](https://redirect.github.com/actions/core)
from 1.11.1 to 3.0.0 in
[#&#8203;599](https://redirect.github.com/docker/metadata-action/pull/599)
- Bump
[@&#8203;actions/github](https://redirect.github.com/actions/github)
from 6.0.1 to 9.0.0 in
[#&#8203;597](https://redirect.github.com/docker/metadata-action/pull/597)
- Bump
[@&#8203;docker/actions-toolkit](https://redirect.github.com/docker/actions-toolkit)
from 0.68.0 to 0.79.0 in
[#&#8203;604](https://redirect.github.com/docker/metadata-action/pull/604)
- Bump
[@&#8203;isaacs/brace-expansion](https://redirect.github.com/isaacs/brace-expansion)
from 5.0.0 to 5.0.1 in
[#&#8203;600](https://redirect.github.com/docker/metadata-action/pull/600)
- Bump semver from 7.7.3 to 7.7.4 in
[#&#8203;603](https://redirect.github.com/docker/metadata-action/pull/603)

**Full Changelog**:
<https://github.com/docker/metadata-action/compare/v5.10.0...v6.0.0>

###
[`v6`](https://redirect.github.com/docker/metadata-action/compare/v5.10.0...v6)

[Compare
Source](https://redirect.github.com/docker/metadata-action/compare/v5.10.0...v6)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Invitations existed in the backend (create + accept) but had no UI and
no way to review or withdraw them. Team owners can now invite people by
email from team settings: the one-time invite link (?invite=<token>) is
shown for sharing, pending invitations are listed with their expiry, and
each one can be revoked again.

- store: ListTeamInvitations / DeleteTeamInvitation (postgres + sqlite)
- api: GET + DELETE /v1/teams/{teamID}/invitations[/{invitationID}]
  (owner-only) and audit events invitation.create / invitation.revoke
- frontend: invitation card in team settings, audit filter entries
- docs: invitation endpoints added to the OpenAPI spec

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The auto-created personal workspace was a second kind of team with its
own rules: a generated name ("Personal · <uid>") that could not be
changed, no members, no invitations, and special-cased account
migration. Onboarding (follow-up commit) replaces it: new users create
their first team themselves or join one via invitation.

- stop auto-creating a personal team on OIDC sign-in and admin bootstrap
- startup migration converts existing personal workspaces into regular
  teams: markers cleared, generated names replaced with the owner's
  display name (email local part as fallback, unique-name collisions
  get a numeric suffix); custom names are kept
- drop the personal special cases from team update, member management,
  invitations and account migration; moving an account between teams
  now requires owning the source team (or admin) and editor/owner
  access in the target
- remove is_personal / personal_for_user_id from the domain model, API
  responses, agent tools and frontend (DB columns remain for the
  migration and can be dropped in a later release)
- e2e: global setup seeds a team on fresh databases

BREAKING CHANGE: teams no longer carry is_personal /
personal_for_user_id fields, and new users start without a team.
Existing personal workspaces are migrated to regular teams (renamed
after their owner) on first startup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New users no longer get an auto-created workspace, so guide them
instead: after the first sign-in without a team, a welcome step asks
them to create their team (name prefilled from their profile) before
entering the app. Users arriving through an invite link skip the wizard
— redeeming the invitation already puts them into a team, and the
wizard stays hidden while the invite token is being processed.

The e2e spec boots a dedicated server on a fresh database, because the
shared Playwright server is seeded with a team.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A six-step introduction (dashboard, calendar & composer, accounts,
team, analytics, settings & AI) opens automatically the first time a
user lands in the app with a team — right after the onboarding wizard,
or immediately for users who joined via an invitation. The tour can be
skipped at any point and replayed from the settings; completion is
remembered per browser.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every push to dev now produces a testable image alongside the release
flow from main:
- Forgejo CI: non-main branches publish to the instance registry under
  their branch name (e.g. :dev) instead of :latest; the Dockhand deploy
  stays main-only
- GitHub: new dev-image workflow pushes ghcr.io/<repo>:dev plus a
  per-commit sha tag (linux/amd64 + linux/arm64)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test(e2e): pre-seed the tour-done flag via Playwright storage state
Some checks failed
CI/CD Workflow / Detect changed paths (push) Successful in 9s
CI/CD Workflow / Security (Secrets: gitleaks) (push) Successful in 16s
CI/CD Workflow / Test Postgres Store (push) Has been cancelled
CI/CD Workflow / Security (Go: govulncheck + gosec) (push) Has been cancelled
CI/CD Workflow / Build and Publish Docker Image (push) Has been cancelled
CI/CD Workflow / Trigger Dockhand Deployment (push) Has been cancelled
CI/CD Workflow / Test Frontend (Node.js) (push) Has been cancelled
CI/CD Workflow / Test Backend (Go) (push) Has been cancelled
CI/CD Workflow / E2E (Playwright + Go) (push) Has been cancelled
eec5193305
Setting the flag in signIn() only covered specs using that helper; specs
with their own sign-in flow got blocked by the auto-opening tour dialog.
The storage state applies to every context on the shared server's
origin, while onboarding.spec.ts (own server, different origin) still
exercises wizard and tour.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ci: lowercase the dev image name
All checks were successful
CI/CD Workflow / Detect changed paths (push) Successful in 11s
CI/CD Workflow / Security (Secrets: gitleaks) (push) Successful in 12s
CI/CD Workflow / Test Backend (Go) (push) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (push) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (push) Has been skipped
CI/CD Workflow / Test Postgres Store (push) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (push) Has been skipped
CI/CD Workflow / Build and Publish Docker Image (push) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (push) Has been skipped
38f5e9b9e6
Image references must be lowercase, but github.repository is
"Goloom-App/goloom" — the first :dev build failed on the tag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dev
Post length was measured as raw rune count for every provider, so a
Mastodon post with a long link was rejected (or flagged in the
composer) even though Mastodon counts every URL as a fixed 23
characters. Character limits are now checked with the platform's own
rules, in the shared validation pipeline (REST, MCP, agent tools) and
in the composer's counters:

- Mastodon: every http(s) URL counts as 23 characters regardless of its
  real length, remote mentions (@user@domain) count only the local
  part, everything else in grapheme clusters
- Bluesky: grapheme clusters (the 300-char limit is grapheme-based, so
  emoji sequences no longer overcount); URLs get no discount
- Friendica / Pixelfed: plain grapheme count — neither platform
  discounts URLs (Pixelfed validates the raw caption length despite
  its Mastodon-compatible API)

The AI engine keeps its conservative rune-based truncation: rune count
is always >= the provider-aware count, so generated content stays valid.

Fixes #22

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs(website): document onboarding and email invitations
Some checks failed
CI/CD Workflow / Detect changed paths (push) Successful in 8s
CI/CD Workflow / Security (Secrets: gitleaks) (push) Successful in 10s
CI/CD Workflow / Test Frontend (Node.js) (push) Successful in 1m53s
CI/CD Workflow / Test Backend (Go) (push) Successful in 1m57s
CI/CD Workflow / Test Postgres Store (push) Failing after 1m20s
CI/CD Workflow / Security (Go: govulncheck + gosec) (push) Successful in 2m20s
CI/CD Workflow / E2E (Playwright + Go) (push) Successful in 9m17s
CI/CD Workflow / Build and Publish Docker Image (push) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (push) Has been skipped
d32d3e20ec
- first-login: new onboarding step (create your first team, invited
  users skip it, platform tour with replay from settings)
- teams guide: invitation walkthrough (owner-only, one-time invite
  link, email binding, 7-day expiry, revoking) including the API
  endpoints, and a note that every team is a regular team

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dev
Rework of the onboarding experience based on first-use feedback:

- no more flash of the app shell after sign-in: a loading screen covers
  the gap until the first dashboard load decides between onboarding
  and the app
- the static feature-list dialog is replaced by an interactive guided
  tour that dims the app, spotlights the element to use next, and
  explains it in a tooltip beside it; steps advance when the user
  actually clicks the highlighted control (or reaches the target
  section for multi-click paths like menus)
- the flow is role-aware: administrators are walked through platform
  setup first (admin area, register a provider) before connecting an
  account; regular users go straight to accounts and the composer
- targets that are unavailable (e.g. on mobile layouts) degrade to a
  centered card, Escape skips, and the tour remains replayable from
  the settings

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codifies the branching model: features are developed on feature
branches and merged into main after testing. Every push to main
publishes ghcr.io/goloom-app/goloom:nightly (and :nightly on the
Forgejo registry) built from the latest main state; version tags via
release-please remain the only thing that moves :latest. The dev-image
workflow becomes the nightly workflow; documented in README and
AGENTS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chore(dev): justfile with the common developer tasks
Some checks failed
CI/CD Workflow / Detect changed paths (push) Successful in 9s
CI/CD Workflow / Security (Secrets: gitleaks) (push) Successful in 10s
CI/CD Workflow / Test Frontend (Node.js) (push) Successful in 1m37s
CI/CD Workflow / Test Backend (Go) (push) Successful in 1m50s
CI/CD Workflow / Build and Publish Docker Image (push) Has been cancelled
CI/CD Workflow / Trigger Dockhand Deployment (push) Has been cancelled
CI/CD Workflow / E2E (Playwright + Go) (push) Has been cancelled
CI/CD Workflow / Test Postgres Store (push) Has been cancelled
CI/CD Workflow / Security (Go: govulncheck + gosec) (push) Has been cancelled
38c810312f
`nix develop` + `just` is the standard workflow now: the dev shell
already ships just, the shellHook points to it, and the recipes wrap
the existing Makefile/CI commands (build, run, tests incl. postgres,
e2e, lint, coverage, security scans, docs). `just try` boots a
throwaway instance on a fresh database with dev-only secrets for quick
manual testing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chore(dev): expose nix fmt formatter, ignore .direnv
All checks were successful
CI/CD Workflow / Detect changed paths (push) Successful in 10s
CI/CD Workflow / Security (Secrets: gitleaks) (push) Successful in 12s
CI/CD Workflow / Test Backend (Go) (push) Has been skipped
CI/CD Workflow / Test Frontend (Node.js) (push) Has been skipped
CI/CD Workflow / E2E (Playwright + Go) (push) Has been skipped
CI/CD Workflow / Test Postgres Store (push) Has been skipped
CI/CD Workflow / Security (Go: govulncheck + gosec) (push) Has been skipped
CI/CD Workflow / Build and Publish Docker Image (push) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (push) Has been skipped
18751a6b6f
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dev
chore(main): release 0.2.0
domain 50%->82.5%, rss 31%->95.2%, logging 0%->70.6%, socialtokens 0%->83.3%

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
api 39.6%->56.4%, provider ->56.9%

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sqlite 49.2%->66.0%, scheduler 43.8%->59.1%; the parallel postgres suite
exposed diverging announcement-skip semantics between the two stores —
the tests pin the correct behaviour (occurrence skip implies announcement
skip), sqlite fix follows separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deleting a template occurrence skipped the main post but sqlite still
materialized its announcement; postgres already treated an occurrence
skip as announcement skip. Align sqlite with the postgres semantics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ai 59.5%->77.2%, sse 60.2%->93.5%, mcp 54.7%->69.8%

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
handleGetProactiveSettings/handleUpsertProactiveSettings existed but were
never wired into the router, so the frontend calls to
/v1/teams/{teamID}/proactive-settings returned 404.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test: expand coverage across api, stores, scheduler and ai (42% -> 54%)
chore(main): release 0.2.1
The landing page previously paired a plain text feature grid with a
separate gallery of three nearly empty screenshots (no accounts, zero
analytics, E2E team name). Rebuild it around alternating feature
sections, each backed by a screenshot of the real UI on demo data.

- api: add POST /v1/admin/e2e/demo-seed (admin-only, idempotent) that
  seeds the "Solstice Roasters" demo team: three connected accounts,
  published posts with 30d engagement history, a filled month of
  scheduled posts, review-queue drafts, an RSS feed and two recurring
  templates. Published posts are created as drafts and marked posted
  directly so the scheduler never publishes against the fake accounts.
  The team name intentionally sorts after "E2E AA Seed Team" so the
  other specs keep their default team.
- e2e: website-screenshots.spec.ts seeds the demo team, switches to it,
  dismisses the status banner and captures six views (dashboard,
  calendar, composer with live previews, analytics, review queue,
  automation).
- website: new FeatureShowcase component with alternating text and
  click-to-zoom screenshot rows; FeatureGrid slimmed to the secondary
  capabilities; ScreenshotShowcase removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(website): stalw.art-style feature showcase with demo-data screenshots
chore(main): release 0.2.2
A static-site feed (e.g. the Binärgewitter podcast) can be deployed hours
after the declared pubDate of its newest item. By then last_fetched_at has
moved past that pubDate and filterRSSItemsSince drops the item forever.
Red tests: novelty must come from the rss_imported_items dedupe within a
lookback window, already-imported items must not eat the daily budget, and
the first fetch must baseline all current items.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Novelty is now decided by the rss_imported_items dedupe inside a 7-day
lookback window instead of pubDate > last_fetched_at. Static-site feeds
(e.g. the Binärgewitter podcast) deploy items hours after their declared
pubDate; the old comparison skipped those items forever because every
5-minute poll advanced last_fetched_at past them.

- createPostFromRSSItem reports whether it actually created something, so
  already-imported items no longer consume the daily post budget
- the first fetch baselines all current items into rss_imported_items so
  the lookback window cannot import a feed's backlog later

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The import job only logged a global started/completed pair; every per-feed
skip path (daily limit, already imported, empty candidate set) was DEBUG or
silent, which made the Binärgewitter diagnosis needlessly hard. Red tests:
a per-feed INFO summary with item/candidate/created/skip counts, the daily
limit at INFO with its numbers, and a first-fetch baseline summary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every poll now emits one summary line per feed with items_in_feed,
candidates, created, already_imported, failed and the remaining daily
budget — INFO when there were candidates, DEBUG for the all-quiet case.
The daily-limit skip moves from DEBUG to INFO with its numbers, and the
first fetch logs how many items it baselined and whether it published
the latest one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(scheduler): import RSS items that appear in the feed after their pubDate
feat(scheduler): per-feed summary logging for RSS imports
chore(deps): update pnpm to v11.10.0
fix(deps): update frontend non-major dependencies
api/demo_seed.go is the admin-triggered demo-content seeder: fixed,
non-interactive content with its own targets — exactly the automation
path the allowlist exists for. Unblocks TestNoUnvalidatedPostCreation,
red on main since the demo-seed endpoint landed in PR #32.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port of the old Forgejo CI (.forgejo/workflows/ci.yaml) minus the
image/deploy jobs, which nightly-image.yml and release.yml already
cover on GitHub. Jobs: change detection (plain git), Go vet + tests,
Postgres store suite against a service container, frontend lint +
build, Playwright e2e, govulncheck + gosec, and an ungated gitleaks
history scan. Runs on PRs against main and on pushes to main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The frontend and website rules for rangeStrategy=replace + pnpmDedupe
were identical except for the file path; one npm-wide rule covers both
(they are the only two package.json files in the repo).

The astro-ecosystem rule sat before the website non-major group, but
packageRules apply in order with the last match winning — astro minor
updates therefore landed in the website group, contradicting the rule's
own single-PR requirement. It now comes last.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ci: add PR gate on GitHub Actions
chore(renovate): dedupe npm rules and fix astro group precedence
The guided tour's seen-state is currently a localStorage key, so it
resets with cleared site data and leaks across users sharing a browser.
Red tests: SetUserTourDone store round-trip (sqlite+postgres, surviving
re-login upserts) and a PUT /v1/me/tour endpoint reflected by /v1/me.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tour's seen-state was a localStorage key, so it reset whenever site
data was cleared (which is why it felt cookie-bound), replayed on every
new browser or device, and was wrongly suppressed for a new user on a
shared browser.

- users.tour_done column (sqlite + postgres, idempotent migrations)
- PUT /v1/me/tour persists the flag; /v1/me reports it (openapi updated)
- the open/skip decision is extracted into tourGate() with the server
  flag as source of truth; a pre-existing localStorage marker is synced
  to the account once instead of replaying the tour
- finish/skip and 'restart tour' write through to the API

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(webui): persist the guided-tour flag on the user account
chore(main): release 0.2.3
Red specs: (1) Edit silently no-ops for drafts that arrive after the
dashboard load — the queue polls every 30s but openEditor only searches
the stale posts cache. (2) The card clamps long content with no way to
read it; selecting a card should show the full text in the app's
preview sidebar, which is not wired up for the review queue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Edit silently did nothing for drafts that arrived after the dashboard
load: the queue polls every 30s but openEditor only searched the stale
posts cache. Posts are now fetched on demand and merged into the cache
(ensurePostLoaded), and switching to the review queue refreshes the
dashboard data like the other content sections.

The card clamps long content to three lines and selecting it (card
click or eye button) shows the full text in the app's preview sidebar,
which is now enabled for the review queue; drafts without target
accounts render as plain text there instead of an empty account list.

Card layout: header with badges and destinations, clamped body, footer
with the suggested time left and grouped actions right (edit, schedule
group, publish, discard) instead of one crowded button row.

Also: signIn e2e helper recovers when a 401 race parks the session on
the calendar section, and the discard spec asserts its own item
disappears instead of requiring a globally empty queue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chore(deps): lock file maintenance
fix(webui): review queue — edit for late drafts, preview sidebar, card layout
chore(main): release 0.2.4
Surface the running goloom version in the sidebar footer, above the user
menu. When a newer release exists it turns into an accent-tinted link to
the release notes.

The update check runs server-side and cached: a ReleaseChecker polls the
GitHub releases API (default every 24h) so a single server request covers
all clients instead of every browser reaching out to GitHub. Exposed via
the public GET /v1/version endpoint ({current, latest, update_available}).
Dev builds and unparseable tags never trigger a hint.

Opt out with UPDATE_CHECK_ENABLED=false for air-gapped/self-hosted setups
(no outbound phone-home). Version compare is a small dependency-free
vMAJOR.MINOR.PATCH parser.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI installs with pnpm's minimumReleaseAge supply-chain policy (24h), which
rejects packages published within the cutoff. Renovate had no matching gate,
so it opened PRs (e.g. #44, typescript-eslint 8.63.0) whose CI then failed
purely because the package was too new — red checks with nothing to fix but
wait.

Set Renovate's own minimumReleaseAge to 3 days (comfortable margin over the
24h pnpm gate) with internalChecksFilter=strict, so updates are held until
they are old enough to install. This stops the recurring spurious CI failures
on fresh releases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chore(renovate): hold updates until they pass the release-age gate
feat(ui): show version and update hint in sidebar footer
The landing was competent but read a little generic: a pure system-font
stack and a single cyan accent — while the logo mark is actually tri-colour
(cyan, violet, amber) and the app's accent is violet. The site wasn't using
its own identity.

Keep the layout the same; refine colour, type and depth:

- Type (self-hosted, no runtime CDN — fitting for a self-hosted product):
  Bricolage Grotesque for display/headings, IBM Plex Sans for body, IBM Plex
  Mono for the terminal/code. Latin woff2 subsets under public/fonts, OFL.
  Starlight docs adopt the same families for one coherent product voice.
- Colour: reclaim the tri-hue brand from the logo. Cyan still leads; violet
  and amber appear sparingly as rhythm — a rotating hue bar across the value
  pillars and small logo-square markers on the feature cards, with hue-matched
  hover glows.
- Atmosphere: a calm three-point ambient (one faint pool per hue) replaces the
  single flat glow, plus a ~3.5% film-grain overlay and colour-tinted card
  shadows. CTA gets a subtle tri-hue wash.
- Polish: gradient+shadow primary button with lift, brand ::selection, and a
  visible :focus-visible ring for accessibility.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a proper Datenschutzerklärung at /privacy for the marketing site and
link it from both footers and the license page. Content reflects what the
static GitHub Pages site actually does: no cookies, no analytics, no
tracking, self-hosted fonts — the only processing is GitHub's unavoidable
server-log handling (IP), documented with legal basis Art. 6(1)(f), the
US transfer safeguards, and the visitor's GDPR rights.

Scope is limited to this website; self-hosted goloom instances are their
operators' own responsibility. The controller block is a clearly marked
TODO placeholder — Art. 13 GDPR requires a single named person or entity
(not the contributor list), to be filled in before publishing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(website): tri-hue brand palette + self-hosted typography
feat(website): add GDPR privacy policy page
chore(main): release 0.2.5
chore(deps): update pnpm to v11.12.0
fix(deps): update module github.com/mmcdole/gofeed to v1.4.0
chore(deps): update frontend non-major dependencies
fix(deps): update module github.com/coreos/go-oidc/v3 to v3.20.0
chore(deps): lock file maintenance
chore(deps): update actions/setup-go action to v7
fix(deps): update module modernc.org/sqlite to v1.54.0
chore(deps): update actions/setup-node action to v7
chore(deps): update pnpm to v11.15.0
chore(deps): lock file maintenance
materializeTemplateOccurrence bumped counter_next once per occurrence
even when that occurrence's post already existed (mainExists). In steady
state next_materialize_at moves forward so occurrences are never
revisited, but a template edit that changes the recurrence recomputes
next_materialize_at to the next occurrence after now — which is earlier
than where a materialize horizon had advanced it, and the already
materialized future posts are not deleted.

The next tick then re-walks those occurrences: the duplicate guard
prevents new posts, yet the counter was still advanced each time,
inflating the edition number with no posts to match and drifting the
main counter ahead of the announcement counter.

Advance the counter only when a new main post is actually created;
re-walked occurrences just step next_materialize_at past themselves.
The announcement counter follows the same rule (advance only on a fresh
round). Adds a regression test that materializes a horizon, simulates the
backward reset, and asserts the counter and post count stay put.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
govulncheck flags GO-2026-5970 (infinite loop on invalid input) in
golang.org/x/text < v0.39.0, reachable via the postgres store through
pgxpool -> norm.Form. Bump the transitive dependency to the fixed
v0.39.0. Verified locally: govulncheck reports no vulnerabilities.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(scheduler): don't advance edition counter when re-materializing
## Problem

PR #56 (Renovate pnpm bump) failed CI. Investigating surfaced **two**
issues:

1. **`ci.yml` had a second, hardcoded pnpm pin.**
`test-frontend`/`test-e2e` activated pnpm via `corepack prepare
pnpm@11.12.0 --activate` — a copy of the version next to
`frontend/package.json`'s `packageManager` field. Any Renovate bump of
`packageManager` desyncs the two and breaks CI.
2. **The pinned pnpm 11.12.0 is a broken release.** Its `@pnpm/exe`
build shipped without a binary, so pnpm refuses to provision it and
every frontend install fails regardless of how pnpm is set up. (This is
what Renovate #56 was trying to escape.)

## Fix

- Both jobs now use `pnpm/action-setup@v6` with `version: 11`, matching
`pages.yml` and `release.yml`. No more second version to keep in sync —
future `packageManager` bumps no longer need a workflow edit.
- Bump `frontend/package.json` `packageManager` to `pnpm@11.15.1`
(current, non-broken). Deps unchanged → `pnpm-lock.yaml` stays valid
under `--frozen-lockfile` (verified locally: install + lint + build
pass).

## Notes

- Rebased on latest `main`, which already carries
`golang.org/x/text@v0.39.0`, so the Go security scan (`GO-2026-5970`)
passes here.
- After merge, Renovate #56 can be rebased: its pnpm row drops (already
≥ 11.15.0 on main) and only the `typescript-eslint` bump remains.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.63.0` →
`8.64.0`](https://renovatebot.com/diffs/npm/typescript-eslint/8.63.0/8.64.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.64.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.63.0/8.64.0?slim=true)
|

---

### Release Notes

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.64.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.64.0)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.63.0...v8.64.0)

#### 8.64.0 (2026-07-13)

##### 🚀 Features

- support parsing `import defer`
([#&#8203;12513](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12513))
- **eslint-plugin:** \[no-loop-func] support `using` / `await using`
declarations and deprecate the rule
([#&#8203;12500](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12500))
- **typescript-estree:** throw for invalid definite assignment in class
properties
([#&#8203;12543](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12543))

##### 🩹 Fixes

- **eslint-plugin:** \[require-array-sort-compare] handle constrained
arrays
([#&#8203;12512](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12512))

##### ❤️ Thank You

- Evyatar Daud
[@&#8203;StyleShit](https://redirect.github.com/StyleShit)
- 송재욱

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.64.0)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjUuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm))
| [`11.15.0` →
`11.15.1`](https://renovatebot.com/diffs/npm/pnpm/11.15.0/11.15.1) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.15.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.15.0/11.15.1?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.15.1`](https://redirect.github.com/pnpm/pnpm/compare/v11.15.0...v11.15.1)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.15.0...v11.15.1)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
🤖 I have created a release *beep* *boop*
---


## [0.2.6](https://github.com/Goloom-App/goloom/compare/v0.2.5...v0.2.6)
(2026-07-23)


### Bug Fixes

* **ci:** pnpm setup via action-setup + bump off broken pnpm 11.12.0
([#63](https://github.com/Goloom-App/goloom/issues/63))
([b06992f](b06992f06d))
* **deps:** bump golang.org/x/text to v0.39.0 for GO-2026-5970
([fc832c7](fc832c748d))
* **deps:** update module github.com/coreos/go-oidc/v3 to v3.20.0
([44e01c7](44e01c732e))
* **deps:** update module github.com/coreos/go-oidc/v3 to v3.20.0
([5b173c4](5b173c426e))
* **deps:** update module github.com/mmcdole/gofeed to v1.4.0
([fa1f427](fa1f427662))
* **deps:** update module github.com/mmcdole/gofeed to v1.4.0
([7f41d11](7f41d110c1))
* **deps:** update module modernc.org/sqlite to v1.54.0
([4eb70f0](4eb70f0727))
* **deps:** update module modernc.org/sqlite to v1.54.0
([5f152a7](5f152a749c))
* **scheduler:** don't advance edition counter when re-materializing
([7fb5311](7fb5311f7b))
* **scheduler:** don't advance edition counter when re-materializing
([61e92e8](61e92e8033))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…st sqlite

The Deployment only switched to Recreate when database.type was sqlite,
but the media persistence volume is ReadWriteOnce regardless of the
database backend. With postgres, the default RollingUpdate surged a new
pod before the old one released the volume, causing a permanent
Multi-Attach error and a stuck rollout until Helm's upgrade timeout.

Reproduced on the homelab: v0.2.6 rollout stuck in ContainerCreating on
a different node than the running v0.2.5 pod, "Multi-Attach error ...
already used by pod(s)", 4 failed attempts auto-rolled-back by Flux.

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [recharts](https://redirect.github.com/recharts/recharts) | [`3.9.2` →
`3.10.0`](https://renovatebot.com/diffs/npm/recharts/3.9.2/3.10.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/recharts/3.10.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/recharts/3.9.2/3.10.0?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.64.0` →
`8.65.0`](https://renovatebot.com/diffs/npm/typescript-eslint/8.64.0/8.65.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.65.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.64.0/8.65.0?slim=true)
|

---

### Release Notes

<details>
<summary>recharts/recharts (recharts)</summary>

###
[`v3.10.0`](https://redirect.github.com/recharts/recharts/releases/tag/v3.10.0)

[Compare
Source](https://redirect.github.com/recharts/recharts/compare/v3.9.2...v3.10.0)

#### What's Changed

##### Legend position

Legend now supports `position` and `offset` props, same as Label and
LabeList. This replaces the previous `align` and `verticalAlign` for a
more convenient positioning, and fixes couple visual bugs too. See
<https://recharts.github.io/en-US/examples/LegendPosition/>

- Legend position and offset by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7564](https://redirect.github.com/recharts/recharts/pull/7564)

##### XAxis auto height

XAxis now supports height="auto" prop, similar to YAxis width="auto".

- feat(XAxis): support height="auto" to size the axis to its tick labels
by [@&#8203;kimlj](https://redirect.github.com/kimlj) in
[#&#8203;7570](https://redirect.github.com/recharts/recharts/pull/7570)

##### Other features

- feat(Sankey): support accessibilityLayer, title and desc props by
[@&#8203;MahinAnowar](https://redirect.github.com/MahinAnowar) in
[#&#8203;7546](https://redirect.github.com/recharts/recharts/pull/7546)

##### Bugfixes

- fix: clear stale active bar layer state by
[@&#8203;pupuking723](https://redirect.github.com/pupuking723) in
[#&#8203;7547](https://redirect.github.com/recharts/recharts/pull/7547)
- fix(Brush): slide snaps back to original position on mouseup when
start/endIndex are controlled by
[@&#8203;MaksZhukov](https://redirect.github.com/MaksZhukov) in
[#&#8203;7542](https://redirect.github.com/recharts/recharts/pull/7542)
- fix(Tooltip): find the active sector in the angle-axis wrap-around gap
by [@&#8203;MahinAnowar](https://redirect.github.com/MahinAnowar) in
[#&#8203;7550](https://redirect.github.com/recharts/recharts/pull/7550)
- fix(Brush): keep controlled startIndex/endIndex on data updates by
[@&#8203;momomuchu](https://redirect.github.com/momomuchu) in
[#&#8203;7530](https://redirect.github.com/recharts/recharts/pull/7530)
- Fix Legend type by
[@&#8203;PavelVanecek](https://redirect.github.com/PavelVanecek) in
[#&#8203;7560](https://redirect.github.com/recharts/recharts/pull/7560)
- fix(Label): pass computed position attributes to custom label content
by [@&#8203;MahinAnowar](https://redirect.github.com/MahinAnowar) in
[#&#8203;7549](https://redirect.github.com/recharts/recharts/pull/7549)
- fix(CartesianAxis): skip renderedTicks dispatch when tick values are
unchanged by [@&#8203;kimlj](https://redirect.github.com/kimlj) in
[#&#8203;7565](https://redirect.github.com/recharts/recharts/pull/7565)
- fix: prevent getBandSizeOfAxis from collapsing band size due to
floating-point tick gaps by
[@&#8203;xianjianlf2](https://redirect.github.com/xianjianlf2) in
[#&#8203;7556](https://redirect.github.com/recharts/recharts/pull/7556)
- fix(Area): connectNulls connects across stacked points where every
series is null by [@&#8203;kimlj](https://redirect.github.com/kimlj) in
[#&#8203;7566](https://redirect.github.com/recharts/recharts/pull/7566)

#### New Contributors

- [@&#8203;MahinAnowar](https://redirect.github.com/MahinAnowar) made
their first contribution in
[#&#8203;7546](https://redirect.github.com/recharts/recharts/pull/7546)
- [@&#8203;MaksZhukov](https://redirect.github.com/MaksZhukov) made
their first contribution in
[#&#8203;7542](https://redirect.github.com/recharts/recharts/pull/7542)
- [@&#8203;momomuchu](https://redirect.github.com/momomuchu) made their
first contribution in
[#&#8203;7530](https://redirect.github.com/recharts/recharts/pull/7530)
- [@&#8203;kimlj](https://redirect.github.com/kimlj) made their first
contribution in
[#&#8203;7565](https://redirect.github.com/recharts/recharts/pull/7565)
- [@&#8203;xianjianlf2](https://redirect.github.com/xianjianlf2) made
their first contribution in
[#&#8203;7556](https://redirect.github.com/recharts/recharts/pull/7556)

**Full Changelog**:
<https://github.com/recharts/recharts/compare/v3.9.2...v3.10.0>

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.65.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8650-2026-07-20)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.64.0...v8.65.0)

##### 🚀 Features

- add warning when TS 7 is detected
([#&#8203;12529](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12529))

##### ❤️ Thank You

- Josh Goldberg ✨
- Kirk Waiblinger
[@&#8203;kirkwaiblinger](https://redirect.github.com/kirkwaiblinger)

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.65.0)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm))
| [`11.15.1` →
`11.17.0`](https://renovatebot.com/diffs/npm/pnpm/11.15.1/11.17.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.17.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.15.1/11.17.0?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.17.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.17.0):
pnpm 11.17

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.16.0...v11.17.0)

##### Minor Changes

- Added a new setting, `update.githubActionsServer`, for specifying the
base URL of the GitHub server that hosts the repositories of the GitHub
Actions referenced by the workflow files (for example, a GitHub
Enterprise Server). When the setting is not defined, the URL is read
from the `GITHUB_SERVER_URL` environment variable, falling back to
`https://github.com`. The URL must use the `https://` or `http://`
protocol
[#&#8203;13220](https://redirect.github.com/pnpm/pnpm/issues/13220).

`pnpm outdated` and `pnpm update` no longer fail when the refs of a
GitHub Action's repository cannot be read (for example, when the
action's repository is private or hosted on a different GitHub server).
Such actions are now skipped with a warning.

Setting `update.githubActions` to `false` now makes `pnpm outdated` and
the interactive `pnpm update` skip GitHub Actions dependencies.

##### Patch Changes

- The token poll for web-based authentication no longer reads the body
of non-OK or still-pending (HTTP 202) responses, and caps the token
response body it does read at 64 KiB, so a malicious or compromised
registry cannot exhaust memory through the poll
[pnpm/pnpm#12721](https://redirect.github.com/pnpm/pnpm/issues/12721).

- Fixed `catalog:` references in dependencies and overrides failing to
resolve when installing through a pnpr server, which errored with "No
catalog entry '<name>' was found for catalog 'default'." even though the
catalog entry existed. Also fixed a crash on Windows when installing a
nested workspace member (e.g. `packages/foo`) through a pnpr server
[#&#8203;13232](https://redirect.github.com/pnpm/pnpm/issues/13232).

- Republished every package: the tarballs published by the v11.13.1
through v11.16.0 releases were missing most of their compiled files due
to a packing bug
[#&#8203;13164](https://redirect.github.com/pnpm/pnpm/issues/13164).

- Revert script ordering change for `pnpm run --sequential /regex/`

- Support the `from-git` argument in the `pnpm version` command.

- When the authentication URL cannot be rendered as a QR code (for
example when it exceeds the maximum QR data capacity), web-based login
now displays the URL alone with a warning instead of aborting
authentication
[pnpm/pnpm#12721](https://redirect.github.com/pnpm/pnpm/issues/12721).

<!-- sponsors -->

##### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

##### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.16.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.16.0):
pnpm 11.16

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.15.1...v11.16.0)

#### Minor Changes

- The first release of a package now publishes the version written in
its manifest verbatim, instead of bumping off it. `pnpm version -r` and
`pnpm change status` check the registry for each release's current
version; when that version is not yet published, the package debuts at
it and its pending changesets apply only from the next release. A newly
added package seeded at `1100.0.0` with a `minor` changeset is therefore
published as `1100.0.0` rather than skipping straight to `1100.1.0`.

- Added a `--changeset` flag to `pnpm update`. Set `update.changeset` to
`true` in `pnpm-workspace.yaml` to enable this behavior by default, and
use `--no-changeset` to override the setting for one update. After the
update completes, pnpm writes a `.changeset/pnpm-update-<suffix>.md`
file declaring a patch bump for every workspace package whose
`dependencies` or `optionalDependencies` were changed by the update and
a major bump when `peerDependencies` changed, including packages that
consume an updated catalog entry via the `catalog:` protocol. Private
packages, packages without a name, and packages listed in the `ignore`
array of `.changeset/config.json` are skipped. If
`.changeset/config.json` does not exist, a warning is printed and no
changeset is generated.

- Added GitHub Actions dependencies to `pnpm outdated` and interactive
`pnpm update`. Non-interactive updates can include them with
`--include-github-actions` or by setting `update.githubActions` to
`true` in `pnpm-workspace.yaml`. Updated actions are pinned to exact
commit hashes with their release tags preserved in comments.

- Added `update` and `audit` settings sections to `pnpm-workspace.yaml`,
superseding the awkwardly named `updateConfig`, `auditConfig`, and
top-level `auditLevel` settings:

  ```yaml
  update:
    ignoreDeps: # was updateConfig.ignoreDependencies
      - webpack
      - "@&#8203;babel/*"

  audit:
    level: high # was auditLevel
    ignore: # was auditConfig.ignoreGhsas
      - GHSA-xxxx-yyyy-zzzz
  ```

`update.ignoreDeps` lists dependency name patterns that `pnpm update`
and `pnpm outdated` should skip. `audit.level` and `audit.ignore` tune
`pnpm audit`.

The deprecated `updateConfig`, `auditConfig`, and `auditLevel` settings
keep working until the next major version. When both a new section value
and its deprecated counterpart are set, the new section takes precedence
and a warning is printed. Both the TypeScript CLI and the Rust config
surface (pacquet) recognize the new sections.

#### Patch Changes

- Fixed `pnpm add --save-exact`/`--save-prefix` and `pnpm update`
writing a package's version with the `peerDependencies` range's prefix
(e.g. `^19.2.7` instead of the requested `19.2.7`) whenever the same
package also appeared in `peerDependencies`. A real
`dependencies`/`devDependencies`/`optionalDependencies` entry now takes
precedence over a same-named `peerDependencies` entry when computing the
current specifiers
[#&#8203;13108](https://redirect.github.com/pnpm/pnpm/issues/13108).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Update | Change |
|---|---|
| lockFileMaintenance | All locks refreshed |

🔧 This Pull Request updates lock files to use the latest dependency
versions.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 4am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
## Summary
- 13 changelog lines across releases v0.2.2–v0.2.6 were listed twice,
each duplicate pair pointing at a merge commit and its single real child
commit.
- Root cause: some PRs were historically merged with "Create a merge
commit" instead of squash. The merge commit's body (`Merge pull request
#N from ...` + `feat(x): ...`) is itself conventional-commit-shaped, so
release-please's commit parser picked it up as a second, separate entry
alongside the actual implementing commit.
- Kept the real (single-parent) commit in each pair, dropped the
merge-commit line. No other content changed.
- The repo now only allows squash-merge (`allow_merge_commit: false`,
`allow_rebase_merge: false`), so this specific mechanism shouldn't recur
for future releases.

## Test plan
- [x] Re-ran a normalized-text duplicate scan
(case/punctuation-insensitive) over the resulting CHANGELOG.md — zero
duplicates remain.
- [x] `git diff` reviewed line-by-line — only the 13 intended duplicate
lines removed, nothing else touched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Summary
- Sidebar footer version indicator only linked out when an update was
available; once you're on the latest version it fell back to plain,
non-clickable text.
- Now it always links to the running version's own GitHub release page
(`.../releases/tag/<current>`), same styling as the "update available"
state.

## Test plan
- [x] `tsc --noEmit`
- [x] Updated `e2e/shell-navigation.spec.ts` — the "up to date" test now
asserts the release link instead of asserting no link
- [x] Full `shell-navigation.spec.ts` suite (5/5) passing locally

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
🤖 I have created a release *beep* *boop*
---


## [0.2.7](https://github.com/Goloom-App/goloom/compare/v0.2.6...v0.2.7)
(2026-07-24)


### Features

* **ui:** link the sidebar version to its own GitHub release too
([#72](https://github.com/Goloom-App/goloom/issues/72))
([874cbde](874cbde8a1))


### Bug Fixes

* **deps:** update frontend non-major dependencies
([#66](https://github.com/Goloom-App/goloom/issues/66))
([51b3793](51b379350c))
* **helm:** use Recreate strategy for any single-writer volume, not ju…
([#67](https://github.com/Goloom-App/goloom/issues/67))
([b5bff19](b5bff1960c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[github.com/modelcontextprotocol/go-sdk](https://redirect.github.com/modelcontextprotocol/go-sdk)
| `v1.6.1` → `v1.7.0` |
![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fmodelcontextprotocol%2fgo-sdk/v1.7.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fmodelcontextprotocol%2fgo-sdk/v1.6.1/v1.7.0?slim=true)
|

---

### Release Notes

<details>
<summary>modelcontextprotocol/go-sdk
(github.com/modelcontextprotocol/go-sdk)</summary>

###
[`v1.7.0`](https://redirect.github.com/modelcontextprotocol/go-sdk/releases/tag/v1.7.0)

[Compare
Source](https://redirect.github.com/modelcontextprotocol/go-sdk/compare/v1.6.1...v1.7.0)

This release brings full support for protocol version **`2026-07-28`**.
The wire protocol is largely rewritten: a stateless model with
per-request `_meta`, a new `server/discover` RPC replacing the
`initialize` handshake, multi-round-trip requests (MRTR) replacing
server-initiated calls, a unified `subscriptions/listen` stream
replacing free-floating change notifications, standardised HTTP headers,
and the formal deprecation of the roots, sampling, and logging features.

The streamable HTTP transport accepts requests at protocol version
`2026-07-28` only when `StreamableHTTPOptions.Stateless = true`. If you
want to expose the new protocol over HTTP, set `Stateless = true`; if
you want to keep stateful sessions, your clients will negotiate down to
`2025-11-25`.

Backward compatibility with `2025-11-25` and earlier is preserved on
every endpoint. The SDK negotiates the highest mutually-supported
version at connect time. The new protocol is enabled by default for new
clients; existing legacy clients and servers continue to work unchanged.

This release consolidates everything shipped in `v1.7.0-pre.1`,
`v1.7.0-pre.2`, and `v1.7.0-pre.3`. Thank you to everyone who exercised
the pre-releases and filed feedback.

`v1.7.0-pre.3` is already [successfully
used](https://github.blog/changelog/2026-07-23-github-mcp-server-supports-the-next-mcp-specification/)
by GitHub, serving more than half a million users.

#### Make MCP Stateless
([SEP-2575](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2575))
& Sessionless
([SEP-2567](https://modelcontextprotocol.io/seps/2567-sessionless-mcp))

The `initialize`/`notifications/initialized` handshake is removed in
`2026-07-28`. Each request now carries
`_meta.io.modelcontextprotocol/{protocolVersion,clientInfo,clientCapabilities}`
so the server can validate the peer without state. A new
`server/discover` RPC lets clients learn the server's supported versions
and capabilities up front; the SDK falls back to legacy `initialize` if
discover fails. Resumability (`Last-Event-ID`, standalone GET) is
removed; `ping`, `logging/setLevel`, `resources/subscribe`, and
`resources/unsubscribe` are also removed on this revision and rejected
with `MethodNotFound`.

- mcp: Implement support for SEP-2575 on client side by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;975](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/975))
- mcp: Implement server-side support for discover method (SEP-2575) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;987](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/987))
- mcp: Implement stateless server (SEP-2575) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;965](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/965))
- mcp: add support for logging level (SEP-2575) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;997](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/997))
- mcp: Remove resumability and introduce
`MissingRequiredClientCapability` error data by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1005](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1005))
- mcp: remove session header handling in stateless mode by
[@&#8203;maciej-kisiel](https://redirect.github.com/maciej-kisiel)
([#&#8203;952](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/952))
- mcp: do not call DELETE for sessionless & doc adjustments by
[@&#8203;maciej-kisiel](https://redirect.github.com/maciej-kisiel)
([#&#8203;960](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/960))
- mcp: Implement retry on advised supportedVersions in
`UnsupportedProtocolVersion` error by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;989](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/989))
- mcp: Enable legacy initialize fallback on any error by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1014](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1014))

#### Subscriptions listen
([SEP-2575](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2575))

The legacy `tools/list_changed`, `prompts/list_changed`,
`resources/list_changed`, and `resources/updated` notifications are
replaced by a single long-lived `subscriptions/listen` request whose
response stream multiplexes every change notification the client opted
into, each tagged with `io.modelcontextprotocol/subscriptionId`. The SDK
opens this stream automatically on `Client.Connect` when the
corresponding list-changed handler is set; servers route notifications
only to subscribed sessions.

- mcp: Implement `subscriptions/listen` rpc (SEP-2575) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1007](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1007))
- mcp: refactor notification of subscribed sessions by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1018](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1018))

#### Multi Round-Trip Requests
([SEP-2322](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2322))

Server-to-client requests for elicitation, sampling, and roots are no
longer issued as fresh JSON-RPC requests. Instead a tool/prompt/resource
handler returns an `InputRequiredResult` whose `inputRequests` field
carries the requests; the client fulfils each and retries the original
call with `inputResponses` populated. The SDK ships client- and
server-side middleware that handles this transparently in both
directions, including a server-side compatibility shim that lets MRTR
handlers also work against legacy clients.

- feat: multi-round-trip request implementation (SEP-2322) by
[@&#8203;yarolegovich](https://redirect.github.com/yarolegovich)
([#&#8203;950](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/950))

#### Cacheable list results
([SEP-2549](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2549))

`tools/list`, `prompts/list`, `resources/list`,
`resources/templates/list`, `resources/read`, and `server/discover`
results now carry `ttlMs` and `cacheScope` fields. Clients honour them
as freshness hints to reduce polling; shared intermediaries use
`cacheScope` to decide whether responses may be cached.

- mcp: add ttl for list results (SEP-2549) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1008](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1008))
- mcp: add Cacheable fields to `DiscoverResult` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1022](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1022))

#### HTTP standardization
([SEP-2243](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2243))

The streamable HTTP transport now mirrors selected fields from the
JSON-RPC body into HTTP headers (`Mcp-Method`, `Mcp-Name`,
`Mcp-Protocol-Version`, `Mcp-Param-*`) so network intermediaries can
route and observe MCP traffic without deep packet inspection. Tools can
declare per-parameter passthrough via `x-mcp-header` annotations on
their input schema. Body↔header mismatches return `-32020
HeaderMismatch`.

- mcp: HTTP Header Standardization for `x-mcp-header` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;915](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/915))
- mcp: fix http-standardization (SEP-2243) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1010](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1010))

#### Deprecation of roots, sampling, and logging
([SEP-2577](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2577))

Roots, sampling, and logging are formally deprecated on the `2026-07-28`
revision. The SDK continues to expose the corresponding Go types for
backward compatibility with older peers, but new servers should not rely
on them.

- mcp: Deprecate roots, sampling and logging (SEP-2577) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1017](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1017))

#### Behavior changes guarded by MCPGODEBUG

Seven escape-hatch flags are added in this release to restore behavior
that changed as part of spec-compliance fixes. All will be removed in
**v1.9.0**.

- **`customresnotfounderrcode=1`** — restore the old `-32002` code for
`ResourceNotFoundError`.
- **`hintomitempty=1`** — restore `omitempty` on
`ToolAnnotations.ReadOnlyHint` and `IdempotentHint`. The default now
always serializes these fields because the Go types are bare `bool` (not
`*bool`), so omitting `false` made it indistinguishable from "unset".
- **`allowsessionsinstateless=1`** — restore session-id handling on
stateless streamable HTTP servers (read/write `Mcp-Session-Id`, accept
`DELETE`). The default behavior is now what the spec requires: stateless
servers ignore session IDs entirely and return `405 Method Not Allowed`
for `DELETE`.
- **`nomethodnotfoundcodeinerror=1`** — restore the previous STDIO
behavior where the JSON-RPC `MethodNotFound` (`-32601`) code is omitted
from the error response for unhandled methods. The default now includes
the code.
- **`noprotocolerrorbody=1`** — restore the previous streamable HTTP
client behavior of not decoding the JSON-RPC error body of a non-2xx
HTTP response. The default now surfaces the underlying JSON-RPC error.
- **`nowrapinvalidparams=1`** — restore the previous behavior of
returning raw `unmarshalParams` errors from receiving handlers instead
of wrapping them as a JSON-RPC `-32602 Invalid params` error. Introduced
by
[#&#8203;1087](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1087).
- **`disablecompleteparamsvalidation=1`** — restore the previous
behavior of accepting `completion/complete` responses without validating
the presence of the `completion` params object. Introduced by
[#&#8203;1080](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1080).

#### Other Changes to the SDK

Streamable HTTP transport:

- mcp: allow opt-in to cancel handler ctx on aborted POST by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1099](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1099))
- mcp: enforce body size limit in Streamable connection by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1055](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1055))
- mcp: close HTTP response body from DELETE request in
`streamableClientConn.Close` by
[@&#8203;blackwell-systems](https://redirect.github.com/blackwell-systems)
([#&#8203;929](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/929))
- mcp: write SSE comment on standalone stream so HTTP/2 reverse proxies
flush HEADERS frame by
[@&#8203;jchangx](https://redirect.github.com/jchangx)
([#&#8203;938](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/938))
- mcp: refactor streamable handler control flow by
[@&#8203;maciej-kisiel](https://redirect.github.com/maciej-kisiel)
([#&#8203;949](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/949))
- mcp: add MCPGODEBUG for opt-in Content-Type check by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1012](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1012))
- fix: prevent duplicate in-flight request IDs by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1011](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1011))
- fix: reject duplicate initialize requests by
[@&#8203;he-yufeng](https://redirect.github.com/he-yufeng)
([#&#8203;962](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/962))
- fix(jsonrpc2): decode requests when method key is present by
[@&#8203;piyushbag](https://redirect.github.com/piyushbag)
([#&#8203;1000](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1000))

Custom methods and MCPGODEBUG-guarded fixes:

- mcp: Allow registration of custom JSON-RPC methods by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;956](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/956))
- mcp: wrap `unmarshalParams` with jsonrpc error by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1087](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1087))
- mcp: add param check for `CompleteResult` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1080](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1080))

Additional spec-compliance fixes:

- mcp: update return meta in `DiscoverResult` (SEP-2575) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1097](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1097))
- mcp: add return type to `subscriptions/listen` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1088](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1088))
- mcp: reject calls to `server/discover` for `<2026-07-28` requests by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1084](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1084))
- mcp: include `resultType` on new-protocol responses by
[@&#8203;ychampion](https://redirect.github.com/ychampion)
([#&#8203;1060](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1060))
- mcp: infer elicit mode from `ElicitParams` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1078](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1078))
- mcp: do not `ApplyDefault` when `res.Content == nil` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1069](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1069))
- mcp: do not exclude Notifications from carrying `InitializeParams` in
Meta by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1049](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1049))
- mcp: cap negotiated `protocolVersion` in legacy initialize to
`protocolVersion20251125` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1051](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1051))
- mcp: make `NotificationSubscriptions` a mandatory field by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1050](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1050))
- mcp: do not enforce TTL on cached tool by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1053](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1053))
- mcp: block server-initiated requests (SEP-2322) by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1057](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1057))
- fix: extra wrapper for input response map by
[@&#8203;yarolegovich](https://redirect.github.com/yarolegovich)
([#&#8203;1045](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1045))
- fix: do not `omitempty` `ReadOnlyHint` in `ToolAnnotations` by
[@&#8203;pvlbzn](https://redirect.github.com/pvlbzn)
([#&#8203;908](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/908))
- fix: add implementation description metadata by
[@&#8203;he-yufeng](https://redirect.github.com/he-yufeng)
([#&#8203;981](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/981))
- fix(mcp): prevent SIGSEGV in `AddTool` when schema is nil by
[@&#8203;wucm667](https://redirect.github.com/wucm667)
([#&#8203;918](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/918))
- mcp: `tool.InputSchema` and `tool.OutputSchema` validation (SEP-2106)
by [@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1009](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1009))
- mcp: update JSON-RPC error codes to align with updated MCP
specification by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1016](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1016))
- mcp: bump protocol version from `2026-06-30` to `2026-07-28` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1015](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1015))
- mcp: add `2026-07-28` to the supported protocol versions by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1020](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1020))
- mcp: derive Mcp-Protocol-Version header from the outgoing message by
\[[@&#8203;jan-xyz](https://redirect.github.com/jan-xyz)]

Auth and OAuth:

- auth: support OAuth2 session persistence by
[@&#8203;smlx](https://redirect.github.com/smlx)
([#&#8203;1058](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1058))
- mcp: align resource not found error code with
[SEP-2164](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2164)
by [@&#8203;yarolegovich](https://redirect.github.com/yarolegovich)
([#&#8203;931](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/931))
- mcp: OIDC-Flavored Refresh Token Guidance
([SEP-2207](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2207))
by [@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;939](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/939))
- mcp: add client-side scope accumulation
([SEP-2350](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2350))
by [@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;944](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/944))
- mcp: add optional issuer validator for pre-registered client
validation
([SEP-2352](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2352))
by [@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;946](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/946))
- auth: issuer mix-up mitigation
([SEP-2468](https://redirect.github.com/modelcontextprotocol/modelcontextprotocol/pull/2468))
by [@&#8203;max-stytch](https://redirect.github.com/max-stytch)
([#&#8203;859](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/859))
- auth: compare auth server metadata issuer ignoring trailing slash by
[@&#8203;gainsley](https://redirect.github.com/gainsley)
([#&#8203;955](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/955))
- auth: bind refreshing token source to a background context, not the
request ctx by [@&#8203;toabctl](https://redirect.github.com/toabctl)
([#&#8203;988](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/988))
- auth: add `ClockSkew` option to `RequireBearerTokenOptions` by
[@&#8203;BorisTyshkevich](https://redirect.github.com/BorisTyshkevich)
([#&#8203;969](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/969))
- auth: add `AllowMissingExpiration` option to
`RequireBearerTokenOptions` by
[@&#8203;BorisTyshkevich](https://redirect.github.com/BorisTyshkevich)
([#&#8203;971](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/971))
- oauthex: add `MatchesResource` helper (RFC 9728/8707 audience
comparison) by
[@&#8203;BorisTyshkevich](https://redirect.github.com/BorisTyshkevich)
([#&#8203;970](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/970))
- fix: handle `oauth2.RetrieveError` during token refresh by
[@&#8203;smlx](https://redirect.github.com/smlx)
([#&#8203;917](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/917))

Session, keepalive and misc:

- mcp: use `golang.org/x/time/rate` for `LoggingHandler` rate limiting
by [@&#8203;wucm667](https://redirect.github.com/wucm667)
([#&#8203;927](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/927))
- mcp: add configurable keepalive failure threshold by
[@&#8203;tdabasinskas](https://redirect.github.com/tdabasinskas)
([#&#8203;982](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/982))
- mcp: remove outdated comment by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1003](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1003))

Conformance tests, documentation and CI:

- mcp: add integration for server conformance tests by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1054](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1054))
- mcp: add conformance tests on client by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1063](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1063))
- mcp: Upgrade conformance test to latest available deployment by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1021](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1021))
- mcp: add documentation for new protocol version by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1019](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1019))
- mcp: update docs references by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1023](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1023))
- docs: update docs by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1089](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1089))
- docs: update `troubleshoot.md` to include `resultType` by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1081](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1081))
- ci: update dependabot rules by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1059](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1059))
- ci: fix nightly runs by
[@&#8203;guglielmo-san](https://redirect.github.com/guglielmo-san)
([#&#8203;1086](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1086))
- build(deps): bump `github/codeql-action` from 4.35.1 to 4.35.2 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;922](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/922))
- build(deps): bump `github/codeql-action` from 4.35.2 to 4.36.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;986](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/986))
- build(deps): bump the codeql-action group with 3 updates by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;1064](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1064))
- build(deps): bump `actions/cache` from 5.0.4 to 5.0.5 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;923](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/923))
- build(deps): bump `actions/cache` from 5.0.5 to 6.1.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;1065](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1065))
- build(deps): bump `actions/setup-node` from 6.3.0 to 6.4.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;921](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/921))
- build(deps): bump `actions/upload-artifact` from 7.0.0 to 7.0.1 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;920](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/920))
- build(deps): bump `actions/checkout` from 6.0.2 to 7.0.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;1040](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1040))
- build(deps): bump `actions/setup-python` from 6.2.0 to 6.3.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;1038](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1038))
- build(deps): bump `actions/setup-go` from 6.4.0 to 6.5.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;1066](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1066))
- build(deps): bump `github/codeql-action/upload-sarif` from 4.36.0 to
4.36.2 by [@&#8203;dependabot](https://redirect.github.com/dependabot)
([#&#8203;1039](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1039))

#### New Contributors

-
[@&#8203;MatyasVondraOutreach](https://redirect.github.com/MatyasVondraOutreach)
made their first contribution in
[#&#8203;877](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/877)
- [@&#8203;rafaeljusto](https://redirect.github.com/rafaeljusto) made
their first contribution in
[#&#8203;878](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/878)
- [@&#8203;begelundmuller](https://redirect.github.com/begelundmuller)
made their first contribution in
[#&#8203;856](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/856)
- [@&#8203;Dinesht04](https://redirect.github.com/Dinesht04) made their
first contribution in
[#&#8203;883](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/883)
- [@&#8203;N-Masi](https://redirect.github.com/N-Masi) made their first
contribution in
[#&#8203;896](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/896)
- [@&#8203;jpugliesi](https://redirect.github.com/jpugliesi) made their
first contribution in
[#&#8203;888](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/888)
-
[@&#8203;blackwell-systems](https://redirect.github.com/blackwell-systems)
made their first contribution in
[#&#8203;929](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/929)
- [@&#8203;smlx](https://redirect.github.com/smlx) made their first
contribution in
[#&#8203;917](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/917)
- [@&#8203;yarolegovich](https://redirect.github.com/yarolegovich) made
their first contribution in
[#&#8203;931](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/931)
- [@&#8203;wucm667](https://redirect.github.com/wucm667) made their
first contribution in
[#&#8203;918](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/918)
- [@&#8203;jchangx](https://redirect.github.com/jchangx) made their
first contribution in
[#&#8203;938](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/938)
- [@&#8203;gainsley](https://redirect.github.com/gainsley) made their
first contribution in
[#&#8203;955](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/955)
- [@&#8203;he-yufeng](https://redirect.github.com/he-yufeng) made their
first contribution in
[#&#8203;962](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/962)
- [@&#8203;pvlbzn](https://redirect.github.com/pvlbzn) made their first
contribution in
[#&#8203;908](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/908)
- [@&#8203;max-stytch](https://redirect.github.com/max-stytch) made
their first contribution in
[#&#8203;859](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/859)
- [@&#8203;tdabasinskas](https://redirect.github.com/tdabasinskas) made
their first contribution in
[#&#8203;982](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/982)
- [@&#8203;BorisTyshkevich](https://redirect.github.com/BorisTyshkevich)
made their first contribution in
[#&#8203;971](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/971)
- [@&#8203;piyushbag](https://redirect.github.com/piyushbag) made their
first contribution in
[#&#8203;1000](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1000)
- [@&#8203;toabctl](https://redirect.github.com/toabctl) made their
first contribution in
[#&#8203;988](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/988)
- [@&#8203;ychampion](https://redirect.github.com/ychampion) made their
first contribution in
[#&#8203;1060](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1060)
- [@&#8203;jan-xyz](https://redirect.github.com/jan-xyz) made their
first contribution in
[#&#8203;1107](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1107)
- [@&#8203;george1410](https://redirect.github.com/george1410) made
their first contribution in
[#&#8203;1106](https://redirect.github.com/modelcontextprotocol/go-sdk/pull/1106)

**Full Changelog**:
<https://github.com/modelcontextprotocol/go-sdk/compare/v1.6.0...v1.7.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | `v1.54.0` →
`v1.55.0` |
![age](https://developer.mend.io/api/mc/badges/age/go/modernc.org%2fsqlite/v1.55.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/modernc.org%2fsqlite/v1.54.0/v1.55.0?slim=true)
|

---

### Release Notes

<details>
<summary>cznic/sqlite (modernc.org/sqlite)</summary>

###
[`v1.55.0`](https://gitlab.com/cznic/sqlite/compare/v1.54.0...v1.55.0)

[Compare
Source](https://gitlab.com/cznic/sqlite/compare/v1.54.0...v1.55.0)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Update | Change |
|---|---|
| lockFileMaintenance | All locks refreshed |

🔧 This Pull Request updates lock files to use the latest dependency
versions.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 4am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm))
| [`11.15.1` →
`11.17.0`](https://renovatebot.com/diffs/npm/pnpm/11.15.1/11.17.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.17.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.15.1/11.17.0?slim=true)
|
| [recharts](https://redirect.github.com/recharts/recharts) | [`3.10.0`
→ `3.10.1`](https://renovatebot.com/diffs/npm/recharts/3.10.0/3.10.1) |
![age](https://developer.mend.io/api/mc/badges/age/npm/recharts/3.10.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/recharts/3.10.0/3.10.1?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.17.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.17.0):
pnpm 11.17

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.16.0...v11.17.0)

##### Minor Changes

- Added a new setting, `update.githubActionsServer`, for specifying the
base URL of the GitHub server that hosts the repositories of the GitHub
Actions referenced by the workflow files (for example, a GitHub
Enterprise Server). When the setting is not defined, the URL is read
from the `GITHUB_SERVER_URL` environment variable, falling back to
`https://github.com`. The URL must use the `https://` or `http://`
protocol
[#&#8203;13220](https://redirect.github.com/pnpm/pnpm/issues/13220).

`pnpm outdated` and `pnpm update` no longer fail when the refs of a
GitHub Action's repository cannot be read (for example, when the
action's repository is private or hosted on a different GitHub server).
Such actions are now skipped with a warning.

Setting `update.githubActions` to `false` now makes `pnpm outdated` and
the interactive `pnpm update` skip GitHub Actions dependencies.

##### Patch Changes

- The token poll for web-based authentication no longer reads the body
of non-OK or still-pending (HTTP 202) responses, and caps the token
response body it does read at 64 KiB, so a malicious or compromised
registry cannot exhaust memory through the poll
[pnpm/pnpm#12721](https://redirect.github.com/pnpm/pnpm/issues/12721).

- Fixed `catalog:` references in dependencies and overrides failing to
resolve when installing through a pnpr server, which errored with "No
catalog entry '<name>' was found for catalog 'default'." even though the
catalog entry existed. Also fixed a crash on Windows when installing a
nested workspace member (e.g. `packages/foo`) through a pnpr server
[#&#8203;13232](https://redirect.github.com/pnpm/pnpm/issues/13232).

- Republished every package: the tarballs published by the v11.13.1
through v11.16.0 releases were missing most of their compiled files due
to a packing bug
[#&#8203;13164](https://redirect.github.com/pnpm/pnpm/issues/13164).

- Revert script ordering change for `pnpm run --sequential /regex/`

- Support the `from-git` argument in the `pnpm version` command.

- When the authentication URL cannot be rendered as a QR code (for
example when it exceeds the maximum QR data capacity), web-based login
now displays the URL alone with a warning instead of aborting
authentication
[pnpm/pnpm#12721](https://redirect.github.com/pnpm/pnpm/issues/12721).

<!-- sponsors -->

##### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

##### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.16.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.16.0):
pnpm 11.16

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.15.1...v11.16.0)

#### Minor Changes

- The first release of a package now publishes the version written in
its manifest verbatim, instead of bumping off it. `pnpm version -r` and
`pnpm change status` check the registry for each release's current
version; when that version is not yet published, the package debuts at
it and its pending changesets apply only from the next release. A newly
added package seeded at `1100.0.0` with a `minor` changeset is therefore
published as `1100.0.0` rather than skipping straight to `1100.1.0`.

- Added a `--changeset` flag to `pnpm update`. Set `update.changeset` to
`true` in `pnpm-workspace.yaml` to enable this behavior by default, and
use `--no-changeset` to override the setting for one update. After the
update completes, pnpm writes a `.changeset/pnpm-update-<suffix>.md`
file declaring a patch bump for every workspace package whose
`dependencies` or `optionalDependencies` were changed by the update and
a major bump when `peerDependencies` changed, including packages that
consume an updated catalog entry via the `catalog:` protocol. Private
packages, packages without a name, and packages listed in the `ignore`
array of `.changeset/config.json` are skipped. If
`.changeset/config.json` does not exist, a warning is printed and no
changeset is generated.

- Added GitHub Actions dependencies to `pnpm outdated` and interactive
`pnpm update`. Non-interactive updates can include them with
`--include-github-actions` or by setting `update.githubActions` to
`true` in `pnpm-workspace.yaml`. Updated actions are pinned to exact
commit hashes with their release tags preserved in comments.

- Added `update` and `audit` settings sections to `pnpm-workspace.yaml`,
superseding the awkwardly named `updateConfig`, `auditConfig`, and
top-level `auditLevel` settings:

  ```yaml
  update:
    ignoreDeps: # was updateConfig.ignoreDependencies
      - webpack
      - "@&#8203;babel/*"

  audit:
    level: high # was auditLevel
    ignore: # was auditConfig.ignoreGhsas
      - GHSA-xxxx-yyyy-zzzz
  ```

`update.ignoreDeps` lists dependency name patterns that `pnpm update`
and `pnpm outdated` should skip. `audit.level` and `audit.ignore` tune
`pnpm audit`.

The deprecated `updateConfig`, `auditConfig`, and `auditLevel` settings
keep working until the next major version. When both a new section value
and its deprecated counterpart are set, the new section takes precedence
and a warning is printed. Both the TypeScript CLI and the Rust config
surface (pacquet) recognize the new sections.

#### Patch Changes

- Fixed `pnpm add --save-exact`/`--save-prefix` and `pnpm update`
writing a package's version with the `peerDependencies` range's prefix
(e.g. `^19.2.7` instead of the requested `19.2.7`) whenever the same
package also appeared in `peerDependencies`. A real
`dependencies`/`devDependencies`/`optionalDependencies` entry now takes
precedence over a same-named `peerDependencies` entry when computing the
current specifiers
[#&#8203;13108](https://redirect.github.com/pnpm/pnpm/issues/13108).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

</details>

<details>
<summary>recharts/recharts (recharts)</summary>

###
[`v3.10.1`](https://redirect.github.com/recharts/recharts/compare/v3.10.0...v3.10.1)

[Compare
Source](https://redirect.github.com/recharts/recharts/compare/v3.10.0...v3.10.1)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
## Summary
- limit recurring horizon regenerate to posts from now through the
materialization horizon
- let occurrence skips replace announcement-only skips in SQLite and
Postgres
- add regressions for past posted blockers and skip upgrade behavior

## Tests
- go test ./internal/scheduler/...
- go test ./internal/store/sqlite
- make test-postgres
- go test ./...
- go vet ./...
- go build ./...
- make cover (total 54.2%)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[github.com/mmcdole/gofeed](https://redirect.github.com/mmcdole/gofeed)
| `v1.4.0` → `v1.4.1` |
![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fmmcdole%2fgofeed/v1.4.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fmmcdole%2fgofeed/v1.4.0/v1.4.1?slim=true)
|

---

### Release Notes

<details>
<summary>mmcdole/gofeed (github.com/mmcdole/gofeed)</summary>

###
[`v1.4.1`](https://redirect.github.com/mmcdole/gofeed/releases/tag/v1.4.1)

[Compare
Source](https://redirect.github.com/mmcdole/gofeed/compare/v1.4.0...v1.4.1)

This patch fixes namespace handling for Atom links embedded in RSS
feeds. Atom self and WebSub hub links are now preserved in
`Feed.Extensions["atom"]["link"]` even when a feed uses a local default
namespace or a different prefix.

It also makes prefixed Atom and RDF documents parse consistently,
preserves compatibility with commonly seen `content:encoded` namespace
variants, and updates `golang.org/x/net` to v0.57.0.

#### Changes

- Fix namespace-aware Atom extension parsing.
([#&#8203;339](https://redirect.github.com/mmcdole/gofeed/issues/339))
- Update `golang.org/x/net` to v0.57.0.
([#&#8203;336](https://redirect.github.com/mmcdole/gofeed/issues/336))

**Full changelog:**
<https://github.com/mmcdole/gofeed/compare/v1.4.0...v1.4.1>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4yNC4wIiwidXBkYXRlZEluVmVyIjoiNDQuMjQuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
## What

"Skip next" did not skip the next round. This fixes it, with the
characterization test from the first commit reframed to match.

## The bug

Two defects stacked on each other:

**1. Wrong target.** The UI sent `item.next_materialize_at` as the
occurrence to skip. That field is the *materialization cursor* — the
first round **not yet** materialized — not the next round coming up.
With a horizon active those are different dates, so the skip landed on a
slot that had no posts yet. The imminent announcement and main post
stayed in the calendar, nothing was renumbered, and weeks later a round
nobody meant to drop disappeared instead. "Shift next" had the same bug.

**2. Skip was materialize-time only.** `IsPostTemplateOccurrenceSkipped`
is consulted in exactly one place — `materializeTemplateOccurrence`,
when the cursor first walks over an occurrence. A round already
materialized was never revisited: no deletion, no counter reset, no
re-materialization. So even with the right target, the skip row alone
changed nothing.

## The fix

Skip and shift now go through the scheduler:

- **Frontend** resolves the occurrence from the linked posts (earliest
`pending`/`draft`/`failed` round) and falls back to the cursor only when
nothing is materialized yet. Both skip and shift use it.
- **`SkipPostTemplateOccurrence`** records the skip, then tears down
every materialized round **from that occurrence onwards** and re-walks
the horizon. Everything after the skipped slot has to be rewritten,
because dropping a slot shifts each later edition number down by one.
- **The cursor is rewound** to the skipped occurrence carrying the
counters that round owned. The re-walk then steps over the slot without
burning the edition number and hands it to the next round — which is the
semantics the skip branch in `template_materialize.go` already
implemented but never got to apply.

Guard rails: published/publishing rounds block the tear-down with `409
skip_blocked_posted`, and in-flight AI enhancement for the deleted
rounds is cancelled (`cancelPendingRecurringAIJobsFrom`). Without a
scheduler wired in, the endpoint still records the skip and answers
`204` exactly as before.

## Effect

Skipping edition 385 on a 1st+3rd-Wednesday template, verified against a
real sqlite store (not mocks):

```
before: 08-19=#385  09-02=#386  09-16=#387  10-07=#388
after:  09-02=#385  09-16=#386  10-07=#387
```

The slot is dropped, its announcement goes with it, and 385 moves to the
next date instead of being burned.

## Tests

- `template_skip_test.go` — drop-and-renumber, unmaterialized round
records only, blocked by posted round, shift keeps edition at the new
time. Driven through a stateful mock store so the re-walk is exercised,
not stubbed.
- `template_skip_integration_test.go` — the same flow against a real
sqlite store, which is what catches SQL-level mismatches (skip-row
timestamp round-trip, linked-post delete, materialization rewind) that
mocks cannot. Also asserts the skip survives a second materializer tick.
- `post_templates_skip_test.go` — handler routes through the scheduler,
passes the shift target, maps blocked to 409, and still records the skip
when no scheduler is present.
- `TestSkipNext_skipsBeyondHorizonNotImminentOccurrence` → renamed to
`TestMaterialize_cursorRunsAheadOfMaterializedRounds`. The cursor
running ahead is still true and worth pinning; it is just no longer what
skip reads.

## API change

`POST /post-templates/{id}/skip` now answers `200` with `{deleted_posts,
regenerated_occurrences}` when a scheduler is present (still `204`
without one). The endpoint is not in `docs/api/openapi.yaml` —
post-templates are not documented there at all — so there is no spec to
update.

New i18n keys: `recurring.skipNextConfirm` (skip is destructive now, so
it asks first) and error `skip_blocked_posted`, both de + en.

## Note

Verified: `go build ./...`, `go test ./...`, `go vet`, `gofmt` on all
touched files, plus `tsc --noEmit` and `eslint` clean on the frontend.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Sebastian Preisner <preisner@puzzle-itc.de>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This PR contains the following updates:

| Update | Change |
|---|---|
| lockFileMaintenance | All locks refreshed |

🔧 This Pull Request updates lock files to use the latest dependency
versions.

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 4am on monday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm))
| [`11.17.0` →
`11.21.0`](https://renovatebot.com/diffs/npm/pnpm/11.17.0/11.21.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.21.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.17.0/11.21.0?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.21.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.21.0):
pnpm 11.21

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.20.0...v11.21.0)

#### Minor Changes

- Added interactive group selection to `pnpm update --global
--interactive`.

- Running `pnpm setup`, `pnpm self-update`, or a command that modifies
the global installation (such as `pnpm add --global`) through `sudo` now
prints a warning. pnpm keeps global packages and configuration in the
invoking user's home directory, so running these commands as root
silently operates on the root user's home directory instead of yours.
They will fail with `ERR_PNPM_SUDO_NOT_SUPPORTED` in pnpm v12. Read-only
global commands (such as `pnpm bin --global`) are unaffected.

#### Patch Changes

- Fixed pnpm failing to start under asynchronous Node.js module loaders
when no `.pnpmfile.mjs` exists
[pnpm/pnpm#11701](https://redirect.github.com/pnpm/pnpm/issues/11701).

- Fixed `minimumReleaseAge` fallback for custom dist-tags so the
selected version does not exceed the registry’s original tag target.

- Removing a dependency from `package.json` and reinstalling no longer
re-resolves the dependency graph. The importer's entry is dropped from
`pnpm-lock.yaml`, anything it made unreachable is pruned, and a catalog
entry that loses its last referent is removed — all without registry
access. Installs still fall back to a full resolution when a package
that stays resolves a peer dependency through the removed one, since
that would change the surviving package's entry rather than only prune.

- Changing a catalog entry to a different exact version no longer
re-resolves the dependency graph. The package is replaced in
`pnpm-lock.yaml` directly, reusing the same check the `pnpm.overrides`
fast path applies: every locked dependency of the package must still
satisfy the new version's manifest. Installs fall back to a full
resolution when anything other than the catalog reaches the package — an
importer that depends on it directly, or another package that depends on
it — since the graph would then need both versions.

- Fixed a CI regression where `github:owner/repo` dependencies (and
other shorthand Git specifiers) would fail to install with `Permission
denied (publickey)` on CI runners that lack SSH keys. The Git resolver
no longer records an SSH URL unless the user explicitly wrote one (e.g.
`git+ssh://` or `git@host:...`):

- The repository visibility probe (an HTTP HEAD request) now retries
transient failures such as `429 Too Many Requests`, so host throttling
of CI runners is no longer mistaken for a private repository.
- For non-SSH specifiers, anonymous HTTPS `git ls-remote` access is now
tried before SSH, so a public repository whose visibility probe fails
still resolves to a portable HTTPS URL instead of an SSH URL that only
works where SSH keys are configured.
- When every probe fails, the resolver falls back to HTTPS for shorthand
and HTTPS-style specifiers, and only guesses SSH when the user
explicitly provided an SSH URL.
- A repository that could not be confirmed public is no longer resolved
to the host's anonymous archive URL (e.g. `codeload.github.com`, which
would fail to download for a private repository); it stays a regular
`git` resolution so installs can use ambient Git credentials such as
credential helpers and tokens.

Note that a private repository that is reachable both over authenticated
HTTPS and over SSH now resolves to its HTTPS URL, where previous
versions recorded the SSH URL.

Fixes
[pnpm/pnpm#13276](https://redirect.github.com/pnpm/pnpm/issues/13276).

  <!-- cspell:ignore publickey -->

- `ng build` and `nuxt build` now work under the global virtual store:
pnpm's built-in compatibility extensions add the `tslib` dependency that
`@angular/build` uses without declaring and the `unplugin` dependency
that `@nuxt/vite-builder` v4 uses without declaring.

- Fixed `link:` dependencies under `enableGlobalVirtualStore` so linked
children are materialized and slots remain isolated by their resolved
link targets.

- An install that skips resolution because `pnpm-lock.yaml` is already
up to date now reacts fully to packages the lockfile removed — for
example after pulling a lockfile in which a dependency was deleted. The
hoist layer is recomputed, so a package that became hoistable when a
direct dependency was removed is hoisted, and `pendingBuilds` entries
for removed packages are dropped instead of staying pending forever.

- The held-back-update warning printed by `pnpm update` no longer fires
when `minimumReleaseAge` is the actual reason a newer version was not
picked. The warning's baseline now applies the same maturity cutoff as
the pick itself, so it no longer wrongly attributes the hold-back to
"your manifests and already installed dependencies" or recommends an
override that would defeat the age gate. See
[#&#8203;13071](https://redirect.github.com/pnpm/pnpm/issues/13071).

- Checking whether `ignoredOptionalDependencies` is up to date no longer
reorders the configured patterns. The check sorted them in place, which
could move an `!` exclusion ahead of the pattern it excludes from and
flip which optional dependencies were ignored.

- Changing `autoInstallPeers`, `dedupePeers`, `peersSuffixMaxLength`,
`excludeLinksFromLockfile`, or `injectWorkspacePackages` no longer
re-resolves the dependency graph when the lockfile proves the setting
cannot affect it: no package or project declares a peer dependency for
the peer settings, and no project depends on a directory or on another
workspace project for the link and injection settings. The new setting
is recorded in `pnpm-lock.yaml` and the install proceeds from the
existing resolution. Every other case still falls back to a full
resolution.

- Adding, editing, or removing an entry in `patchedDependencies` no
longer re-resolves the dependency graph. Resolution never reads a patch
— it only records the patch file's hash against the package it matches —
so the install now rewrites the affected entries in `pnpm-lock.yaml` and
materializes the patched package from the store instead. Installs still
fall back to a full resolution when the patched package is reachable as
a peer dependency, and when the new configuration would leave a patch
unused while `allowUnusedPatches` is off, so `ERR_PNPM_UNUSED_PATCH` is
still reported.

- Resolving a private git repository no longer blocks on an interactive
credential prompt: `git ls-remote` now fails fast with an authentication
error when git has no credentials for the repository
[#&#8203;13522](https://redirect.github.com/pnpm/pnpm/issues/13522).

- Lockfile verification now honors offline mode by using cached registry
metadata instead of reaching the registry. When the required metadata is
not available locally, verification reports the same
`ERR_PNPM_NO_OFFLINE_META` condition used by offline resolution.

- POSIX shell shims now follow symbolic links before computing
`basedir`, preventing execution failures when a shim is invoked via an
external symlink on `PATH`
[#&#8203;13405](https://redirect.github.com/pnpm/pnpm/issues/13405).

- The automatic `packageManager` version switch works again on
registries whose tarball URLs point at a different host than the
registry itself (load-balanced feed proxies, Artifactory-style mirrors).
Package-manager entries are now always recorded with integrity-only
resolutions — the download URL is derived from the trusted bootstrap
registry instead — and entries persisted in an invalid shape by an
earlier pnpm are discarded and re-resolved instead of failing every
command
[#&#8203;13619](https://redirect.github.com/pnpm/pnpm/issues/13619).

- Registries that serve no npm signature metadata (private mirrors and
feed proxies commonly strip `dist.signatures`) no longer break the
automatic `packageManager` version switch and `pnpm self-update`
[#&#8203;13147](https://redirect.github.com/pnpm/pnpm/issues/13147).
When the configured registry cannot provide a verifiable signature, pnpm
now fetches the signature from `registry.npmjs.org` and verifies it
against the same embedded npm keys over the installed integrity — which
proves exactly the same thing. If no signature can be obtained from
either source (for example, both are unreachable, or the registry
publishes only a `shasum`), pnpm proceeds with a warning instead of
failing, but only when the packages resolve through a registry
configured in the user's own (non-project) configuration; the download
stays pinned by the lockfile integrity, and a signature that exists but
does not validate still fails the switch.

- `pnpm fetch`, and any install run with `virtualStoreOnly`, no longer
writes a `.pnp.cjs` loader under `nodeLinker: pnp`. These installs
populate the virtual store without linking the project, so the loader
would have claimed the project resolves out of a store it was never
linked into. The importer links and `node_modules/.package-map.json`
were already skipped; the PnP loader now follows the same rule.

- Prevent pnpm from removing project files when `modulesDir` resolves to
the project root.

- Speed up installs after adding `ignoredOptionalDependencies` patterns
by removing newly ignored optional dependencies and pruning packages
that are no longer reachable without resolving the dependency graph
again.

- When a failed install re-copies a bin script from the store, rerunning
`pnpm install` now reapplies the executable bit to the bin instead of
leaving it non-executable
[#&#8203;12742](https://redirect.github.com/pnpm/pnpm/issues/12742).

- `pnpm root -g` and `pnpm bin -g` now print warnings to stderr instead
of stdout, so their stdout stays a clean, machine-readable path.
Previously, running either command with `--global` in a project that
pins a package manager (e.g. via the `packageManager` field) printed a
warning like `[WARN] Using --global skips the package manager check for
this project` ahead of the path, breaking programs that capture the
output as a path
[#&#8203;13672](https://redirect.github.com/pnpm/pnpm/issues/13672).

In pnpm 12, `pnpm root -g` and `pnpm prefix -g` are now supported (they
previously failed with `ERR_PNPM_CLI_ROOT_GLOBAL_UNSUPPORTED` /
`ERR_PNPM_CLI_PREFIX_GLOBAL_UNSUPPORTED`), and the reporter output of
`dlx`, `create`, `config`, `sbom`, `with`, `store`, `prefix`, `root`,
and `bin` goes to stderr, matching pnpm 11.

- `pnpm setup` no longer makes Node.js print a
`MODULE_TYPELESS_PACKAGE_JSON` warning about `dist/worker.js` on every
command. The `package.json` it writes next to a standalone executable
now declares `"type": "module"`.

- `pnpm update` without saving no longer records a version that the
manifest's range excludes. The kept range stays authoritative: a
requested version outside it is skipped with a warning, and a requested
range, a dist tag, or `--latest` resolves within it instead of past it.
Previously each of these could write a lockfile entry that contradicted
its own specifier, which the next `pnpm install --frozen-lockfile`
rejected with `ERR_PNPM_OUTDATED_LOCKFILE`
[#&#8203;12764](https://redirect.github.com/pnpm/pnpm/issues/12764).

- `pnpm version -r --json` now outputs `[]` instead of human-readable
text when no pending changes exist
[`pnpm/pnpm#13217`](https://redirect.github.com/pnpm/pnpm/issues/13217).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.20.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.20.0):
pnpm 11.20

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.19.0...v11.20.0)

#### Minor Changes

- **Security fix.** Affects projects using `namedRegistries` on pnpm
11.1.0–11.19.x. It is **semi-breaking** for those projects — see "If you
use named registries" below.

The lockfile recorded no marker for which registry a package came from.
Packages were keyed by `name@version` alone, and entry lookup went
through `refToRelative(ref, name)`, so a dependency you declared against
one registry could be satisfied by an entry that was actually resolved
from another. When two registries served the same name and version, both
collapsed onto a single `packages:` entry and whichever resolved first
decided the tarball every consumer got.

That is a package-substitution risk: a package you expect from your
private registry could be installed from a different registry that
publishes the same name and version, and the lockfile recorded nothing
that would let you tell.

Packages resolved from a named registry are now recorded under
registry-qualified keys (`<name>@<registryName>:<version>`, e.g.
`foo@work:1.0.0`), so each registry gets its own entry and the lockfile
pins which one a dependency came from.

The lockfile format version is unchanged. Registry-qualified keys appear
only for packages resolved from a named registry, so a project that does
not use `namedRegistries` sees no difference, and older pnpm versions
keep reading the file.

##### If you use named registries

Your next non-frozen install re-keys those entries, which shows up as a
lockfile diff. Commit it — that diff is the fix being applied. Review
it: an entry that moves to a registry you did not expect is worth
investigating.

Everyone working on the project should be on this version or newer
before you do. An older pnpm reads the re-keyed lockfile fine — frozen
installs are unaffected — but it does not produce registry-qualified
keys itself, so any install that updates the lockfile writes those
entries back to the old shape, and the next install on a current pnpm
re-qualifies them. The result is a lockfile that flips back and forth,
and while it is in the old shape the project is exposed again. Because
the lockfile format version is deliberately unchanged, pnpm cannot
detect this and warn you about it.

There is no setting to keep the old behavior: the old shape is the
vulnerability.

Tarball URLs that follow the standard registry layout are no longer
written to the lockfile for named-registry packages; they are recomputed
from the `namedRegistries` setting on demand.

To use named registries, map your aliases in `pnpm-workspace.yaml`:

```yaml
namedRegistries:
  work: https://npm.enterprise.example.com/
```

##### New built-in `npmjs:` alias

`npmjs:` now resolves to `https://registry.npmjs.org/` with no
configuration, alongside the existing `gh:` alias for GitHub Packages.
It pins a dependency to the public registry even when `registry` points
elsewhere, such as an internal proxy:

```json
{ "dependencies": { "left-pad": "npmjs:^1.3.0" } }
```

`npm:` cannot do this — it is the alias protocol (`npm:<name>@<range>`)
and resolves through whatever `registry` points at.

**If you mirror or proxy npmjs, point the alias at your mirror:**

```yaml
namedRegistries:
  npmjs: https://npm.internal.example.com/
```

Built-in registry URLs are also the prefixes a lockfile's recorded
tarball URL is matched against when pnpm verifies a package. Without the
override, an entry whose tarball URL is on `registry.npmjs.org` is
verified against the public registry rather than your mirror. This only
affects lockfiles that record such URLs — a canonical URL for your
configured registry is omitted from the lockfile and unaffected — and
only when a tarball-URL, `minimumReleaseAge`, or `trustPolicy` check
runs. Overriding the alias is the same escape hatch GHES users already
have for `gh`.

Every alias the lockfile references must stay in `namedRegistries`:
reading an entry whose alias is gone fails with
`ERR_PNPM_MISSING_NAMED_REGISTRY` rather than silently falling back to
the default registry, since that would fetch a different package.
Renaming an alias re-resolves the packages that used it.

Named registry aliases that shadow a reserved dependency specifier
prefix (`file`, `link`, `workspace`, `runtime`, `npm`, `jsr`, ...) are
now rejected with `ERR_PNPM_RESERVED_NAMED_REGISTRY_NAME` instead of
being silently shadowed by the corresponding resolver.

`pnpm licenses` and `pnpm sbom` now keep the two artifacts apart as
well: license records carry the registry alias, and SBOM components
carry the purl `repository_url` qualifier.

#### Patch Changes

- An empty `http-proxy`, `https-proxy`, `proxy`, or `no-proxy` value —
from the `.npmrc`, `pnpm-workspace.yaml`, the CLI, or the `HTTP_PROXY` /
`HTTPS_PROXY` / `PROXY` / `NO_PROXY` environment variables — no longer
fails the install with `ERR_PNPM_INVALID_PROXY`. Empty settings read as
unset, so a shell exporting `HTTP_PROXY=` disables the proxy, and an
empty `proxy=` in the `.npmrc` no longer suppresses `HTTPS_PROXY`
[#&#8203;13533](https://redirect.github.com/pnpm/pnpm/issues/13533).

`proxy=false` in the `.npmrc` or `proxy: false` in `pnpm-workspace.yaml`
now turns proxying off instead of being read as a proxy host named
`false`. `false` and `null` on `https-proxy` / `http-proxy` / `no-proxy`
read as unset, and on the command line they are ordinary host names,
since a flag carries its value verbatim.

- The env lockfile no longer pins `@pnpm/exe` alongside `pnpm` when the
wanted pnpm version is 12 or newer. From v12 the unscoped `pnpm` package
is itself the native executable, so `@pnpm/exe` is not published for it
and resolving it would fail. The engine identity check now verifies the
native binary through whichever package ships it.

- `lexCompare` and `nerfDart` are now published as
`@pnpm/text.ordinal-comparator` and `@pnpm/config.registry-auth-key`.
Use these instead of `@pnpm/util.lex-comparator` and
`@pnpm/config.nerf-dart`.

- Fixed the order in which pnpm matches a lockfile's recorded tarball
URL against known registry URLs. Two registry URLs of equal length were
previously ordered arbitrarily, so which one a tarball URL matched could
differ between runs.

- Dependency resolution is faster: package metadata is now filtered once
per packument instead of once per dependency edge when
`minimumReleaseAge` is active, and parsed semver versions and ranges are
reused instead of re-parsed on every comparison.

- Security: `pnpm rebuild` now refuses a lockfile whose `packages` key
carries a path traversal in the package name (e.g.
`../../../escaped@1.0.0`), instead of running that package's lifecycle
scripts and linking its bins in a directory outside the virtual store.
Such a name is rejected with `ERR_PNPM_INVALID_DEPENDENCY_NAME`.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.19.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.19.0):
pnpm 11.19

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.18.0...v11.19.0)

#### Minor Changes

- `pnpm login` no longer requires an interactive terminal when the
registry supports web-based login: without a TTY it prints the
authentication URL (skipping the QR code and the "Press ENTER to open
the URL in your browser" prompt) and polls the registry until the
browser approval completes. Only the classic username/password login
still fails with `ERR_PNPM_LOGIN_NON_INTERACTIVE` in a non-interactive
terminal.

- The `save-prefix` setting now accepts `=`: newly added dependencies
are saved with an explicit `=` operator (`=1.2.3`) instead of the
setting being silently treated as the default `^`.

#### Patch Changes

- `allowBuilds` entries can now approve git-hosted packages that pnpm
downloads as a tarball, such as `github:` dependencies (which are
fetched from `codeload.github.com` rather than cloned), by their
repository URL without the resolved commit hash. This matches the
hashless `git+` matching already supported for cloned git dependencies.
For example:

  ```yaml
  allowBuilds:
    "foo@git+https://github.com/org/foo.git": true
  ```

This approves the package whether pnpm clones it or downloads a tarball,
so the entry no longer has to be updated every time the pinned commit
changes. GitLab and Bitbucket tarball downloads are matched the same
way. Approving or denying a specific resolved commit by its full tarball
dep path continues to work.

- `pnpm outdated --include-github-actions` no longer blocks on an
interactive git credential prompt when a workflow uses a private action
repo.

- Prevented `minimumReleaseAge` from replacing `latest` with a
SemVer-greater version than the registry tag target
[#&#8203;13034](https://redirect.github.com/pnpm/pnpm/issues/13034).

- Fixed empty `bundledDependencies` and `bundleDependencies` arrays
causing nondeterministic lockfile changes. See
[#&#8203;13123](https://redirect.github.com/pnpm/pnpm/issues/13123).

- The install summary no longer prints `(X is available)` when the
registry's `dist-tags.latest` is still held back by the active
`minimumReleaseAge` policy. The hint only ever names the actual latest
tag, so an immature latest suppresses the hint instead of advertising
the version pnpm just refused to install
[#&#8203;11698](https://redirect.github.com/pnpm/pnpm/issues/11698).

- `pnpm update` keeps the explicit `=` operator of an exact version pin:
a dependency saved as `=3.5.1` now updates to `=3.5.2` instead of the
bare `3.5.2`. See
[#&#8203;13168](https://redirect.github.com/pnpm/pnpm/issues/13168).

- Preserve a workspace dependency's `link:` entry when a run does not
target it — e.g. `pnpm update <other-pkg>` (with or without
`--recursive`), or a plain install after a root/catalog dependency
change — with `injectWorkspacePackages`, instead of spuriously rewriting
it to a peer-suffixed `file:` protocol. See
[#&#8203;10433](https://redirect.github.com/pnpm/pnpm/issues/10433).

- Workspace dependencies declared with a relative path (e.g. `"foo":
"workspace:../foo"`) are no longer silently dropped from the workspace
projects graph, so `--filter` selection and the topological order of
recursive commands take them into account.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.18.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.18.0):
pnpm 11.18

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.17.0...v11.18.0)

#### Minor Changes

- Fixed an installed optional dependency being left without one of its
own required dependencies. When a package reached through
`optionalDependencies` is installable on the current system but one of
its regular `dependencies` is not, a lockfile-based install skipped that
dependency and installed the parent anyway, so importing the parent
failed with `MODULE_NOT_FOUND`. The dependency is now installed, and an
install-check warning reports the incompatibility. A dependency is still
only skipped when every path to it is optional, or when the package that
pulls it in was itself skipped
[#&#8203;13286](https://redirect.github.com/pnpm/pnpm/issues/13286).

- `pnpm setup` now appends `PNPM_HOME` and the global bin directory to
the GitHub Actions environment files (`GITHUB_ENV` and `GITHUB_PATH`),
so later steps in the same job can run `pnpm add --global` and other
global commands
[#&#8203;9191](https://redirect.github.com/pnpm/pnpm/issues/9191).

- Added support for `publishConfig.name`, which publishes a package
under a different name than the one its manifest carries in the
workspace. It is for a project whose published name is already taken by
a sibling project, which otherwise has to be renamed by a build step
just before publishing. Only the published artifact is renamed —
dependents, `pnpm-lock.yaml`, and release tooling keep addressing the
project by its manifest name — and the new name reaches the packed
manifest, the tarball filename, and everything that addresses the
package at the registry: the already-published check of `pnpm publish
-r`, its registry selection, and the release-planning probes of `pnpm
change status` and `pnpm version -r`
[#&#8203;13345](https://redirect.github.com/pnpm/pnpm/issues/13345).

- `pnpm self-update` no longer takes any instruction from the project it
is run in:

- pnpm is fetched through the same trusted registry and auth
configuration used when switching pnpm versions, so a project `.npmrc`
or `pnpm-workspace.yaml` can no longer redirect the download or attach
credentials to it, and the project's default `.pnpmfile.(c|m)js` is no
longer loaded. Pnpmfiles from trusted sources (the `pnpmfile` setting,
the global pnpmfile, config dependencies) still apply.
- The `minimumReleaseAge` settings in `pnpm-workspace.yaml` no longer
affect `self-update`. They still govern the project's own dependencies;
for `self-update` the cooldown now comes from the built-in default, your
global config, a `PNPM_CONFIG_*` environment variable, or a command-line
flag. This fixes `self-update` failing inside a workspace that raises
the cutoff while succeeding everywhere else, and stops a repository from
either waiving the cooldown or keeping you on an outdated pnpm by
raising it.
- The same applies to the `trustPolicy` settings and to `ci`: a project
can no longer weaken the trust check that guards the pnpm download, nor
re-enable the confirmation prompt that a CI run suppresses.

When `self-update` refuses a version that is younger than the cutoff, an
interactive run now offers to update anyway; non-interactive runs still
fail. CI never prompts, even on a runner that attaches a TTY.

#### Patch Changes

- Fixed `pnpm licenses list` to report every version when the same
package is installed under multiple aliases
[pnpm/pnpm#13438](https://redirect.github.com/pnpm/pnpm/issues/13438).

- Sort `pnpm dedupe --check` snapshot changes for stable output across
pnpm implementations.

- Strip Unicode formatting characters from registry- and
manifest-derived terminal output.

- Speed up installs after compatible catalog or direct dependency range
changes by retaining the locked version without resolving the dependency
graph again.

- Speed up installs after safe override changes by reusing unambiguous
compatible dependency resolutions, pruning obsolete dependencies,
applying independent replacements and removals together, and handling
parent-scoped `"-"` overrides without full lockfile resolution.

- Installing a local `file:` directory dependency with the global
virtual store enabled no longer fails with `TypeError: Cannot read
properties of undefined (reading 'split')`
[#&#8203;13335](https://redirect.github.com/pnpm/pnpm/issues/13335).

Local directory dependencies — `file:` directories and injected
workspace packages — now get a global-virtual-store slot of their own
per project. They used to share one slot across every project that
depended on a directory of the same name, so a project could end up
linked to another project's copy of the dependency.

- The `Workspace` column of `pnpm update --interactive` now falls back
to the project's path when its `name` is only whitespace, as it already
did for a missing or empty one — all three render an equally blank label
otherwise.

- Checking GitHub Actions dependencies for updates is now opt-in for
every command. Neither `pnpm outdated` nor `pnpm update` reads the
workflow files unless `--include-github-actions` is passed or
`update.githubActions` is set to `true` in `pnpm-workspace.yaml`.
Reading them runs `git ls-remote` against every referenced repository,
which fails in environments where GitHub is not reachable the way pnpm
assumes (a GitHub Enterprise Server, a custom certificate authority, or
an offline network)
[#&#8203;13254](https://redirect.github.com/pnpm/pnpm/issues/13254).

  `pnpm outdated` accepts the `--include-github-actions` option too.

- `pnpm update --interactive` now measures its table in terminal columns
rather than in characters. A package name, workspace name, or version
containing wide characters (CJK, most emoji) no longer knocks its row's
columns out of line with the rest of the group, and a wide character in
a version no longer aborts the command with `Subject parameter value
width cannot be greater than the container width`
[#&#8203;13357](https://redirect.github.com/pnpm/pnpm/issues/13357).

- The `Workspace` column of `pnpm update --interactive` is more
informative in two cases. A dependency outdated at the same version in
several workspace projects is offered as one choice, since selecting it
updates every project — that choice now names all of them instead of
only the first. And a workspace project without a `name` is now labelled
with its path rather than left blank, so several unnamed projects can be
told apart.

- An auto-installed *optional* peer is no longer hoisted at a version
the workspace root's own dependency on that package excludes.
`resolvePeersFromWorkspaceRoot` already made the workspace root's
specifier decide which version a missing *required* peer is installed
at; the optional-peer picker ignored it and always took the highest
version present anywhere in the graph. In a workspace whose root pins
`postcss: 8.5.10`, an importer that depends on `webpack` and declares no
`postcss` of its own got `postcss@8.5.22` hoisted for
`terser-webpack-plugin`'s optional `postcss` peer, leaving two
`postcss@8.5.x` instances in the graph
[#&#8203;13320](https://redirect.github.com/pnpm/pnpm/issues/13320).

- `overrides` now also govern peers that pnpm auto-installs. Previously
an override only rewrote dependencies declared in a manifest, so a peer
nobody declares — installed because `autoInstallPeers` is on — resolved
against its declared peer range and could bring in a second copy of the
very package the override pinned. For example, with `overrides: { react:
npm:react@19.2.0 }` and a lone `lucide-react` dependency, pnpm installed
`react@18.3.1`; it now installs the pinned `react@19.2.0`
[#&#8203;13320](https://redirect.github.com/pnpm/pnpm/issues/13320).

- Under `resolvePeersFromWorkspaceRoot`, a workspace root dependency
declared with `link:` or `file:` (or the path form of `workspace:`, such
as `workspace:../pkg`) now satisfies another project's missing peer
dependency at the linked package's own version, instead of being hoisted
as a path. Those specifiers are relative to the project that declares
them, so the same specifier reached a different directory — or none —
from the project the peer was hoisted into, leaving a broken link. The
root now has the same authority over the peer as it has when it declares
the package with a version range
[#&#8203;13373](https://redirect.github.com/pnpm/pnpm/issues/13373).

- Installs through a pnpr server now apply the project's whole
verification policy. `minimumReleaseAgeExclude`,
`minimumReleaseAgeIgnoreMissingTime`, `trustPolicy`,
`trustPolicyExclude`, `trustPolicyIgnoreAfter`, and `trustLockfile` were
ignored, so excluded packages were still held back and a lockfile
containing them could be rejected.

`trustPolicy: no-downgrade` no longer fails with
`TRUST_POLICY_INCOMPATIBLE_WITH_PNPR` when a pnpr server is configured.

`--frozen-lockfile` and `--no-prefer-frozen-lockfile` are now honored on
the pnpr path, instead of resolving and rewriting the lockfile anyway.
Since `frozenLockfile` defaults to `true` on CI, a CI install through a
pnpr server now fails on an out-of-date lockfile rather than updating
it.

- Workspace installs through a pnpr server no longer crash with `Cannot
read properties of undefined (reading 'filter')` after linking, when
`minimumReleaseAge` is active
[#&#8203;13275](https://redirect.github.com/pnpm/pnpm/issues/13275).

- Fixed `pnpm dedupe` updating valid catalog resolutions when another
matching version exists in the lockfile.

- `pnpm -r run "/pattern/" --no-bail` no longer exits zero when one of a
project's matched scripts fails and a later one passes. The run summary
carries a single status per project, and the passing script overwrote
the recorded failure.

- Restored the store block a first install prints, naming how packages
were materialized and where the stores live
[#&#8203;13315](https://redirect.github.com/pnpm/pnpm/issues/13315):

  ```text
Packages are hard linked from the content-addressable store to the
virtual store.
    Content-addressable store is at: ~/.local/share/pnpm/store/v11
    Virtual store is at:             node_modules/.pnpm
  ```

- The root project's `pnpm:devPreinstall` script now runs before
resolution and linking, as it does in pnpm 11. It is skipped under
`--ignore-scripts`, `--lockfile-only` and `--dry-run`, by `pnpm fetch`
and `pnpm rebuild`, and by a repeat install that is already up to date.
Workspaces that use the hook to prepare state the install depends on —
such as [next.js](https://redirect.github.com/vercel/next.js), which
generates a placeholder `next` bin with it — were left with dependents
linked against files that were never created
[#&#8203;13313](https://redirect.github.com/pnpm/pnpm/issues/13313).

- Prevented `pnpm dedupe --check` from removing an incompatible
`node_modules` directory.

- `pnpm update --workspace` no longer links dependencies the user never
named:

- Running it with `updateConfig.ignoreDependencies` configured no longer
fails with `ERR_PNPM_WORKSPACE_PACKAGE_NOT_FOUND` for a dependency that
is only published to the registry. Such dependencies keep their
specifiers, as they already did when no dependencies were ignored.
- Passing package selectors that match no direct dependency no longer
falls back to linking every workspace dependency.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4yNC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://pnpm.io)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm11/pnpm))
| [`11.17.0` →
`11.21.0`](https://renovatebot.com/diffs/npm/pnpm/11.17.0/11.21.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.21.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.17.0/11.21.0?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.65.0` →
`8.67.0`](https://renovatebot.com/diffs/npm/typescript-eslint/8.65.0/8.67.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.67.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.65.0/8.67.0?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.21.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.21.0):
pnpm 11.21

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.20.0...v11.21.0)

#### Minor Changes

- Added interactive group selection to `pnpm update --global
--interactive`.

- Running `pnpm setup`, `pnpm self-update`, or a command that modifies
the global installation (such as `pnpm add --global`) through `sudo` now
prints a warning. pnpm keeps global packages and configuration in the
invoking user's home directory, so running these commands as root
silently operates on the root user's home directory instead of yours.
They will fail with `ERR_PNPM_SUDO_NOT_SUPPORTED` in pnpm v12. Read-only
global commands (such as `pnpm bin --global`) are unaffected.

#### Patch Changes

- Fixed pnpm failing to start under asynchronous Node.js module loaders
when no `.pnpmfile.mjs` exists
[pnpm/pnpm#11701](https://redirect.github.com/pnpm/pnpm/issues/11701).

- Fixed `minimumReleaseAge` fallback for custom dist-tags so the
selected version does not exceed the registry’s original tag target.

- Removing a dependency from `package.json` and reinstalling no longer
re-resolves the dependency graph. The importer's entry is dropped from
`pnpm-lock.yaml`, anything it made unreachable is pruned, and a catalog
entry that loses its last referent is removed — all without registry
access. Installs still fall back to a full resolution when a package
that stays resolves a peer dependency through the removed one, since
that would change the surviving package's entry rather than only prune.

- Changing a catalog entry to a different exact version no longer
re-resolves the dependency graph. The package is replaced in
`pnpm-lock.yaml` directly, reusing the same check the `pnpm.overrides`
fast path applies: every locked dependency of the package must still
satisfy the new version's manifest. Installs fall back to a full
resolution when anything other than the catalog reaches the package — an
importer that depends on it directly, or another package that depends on
it — since the graph would then need both versions.

- Fixed a CI regression where `github:owner/repo` dependencies (and
other shorthand Git specifiers) would fail to install with `Permission
denied (publickey)` on CI runners that lack SSH keys. The Git resolver
no longer records an SSH URL unless the user explicitly wrote one (e.g.
`git+ssh://` or `git@host:...`):

- The repository visibility probe (an HTTP HEAD request) now retries
transient failures such as `429 Too Many Requests`, so host throttling
of CI runners is no longer mistaken for a private repository.
- For non-SSH specifiers, anonymous HTTPS `git ls-remote` access is now
tried before SSH, so a public repository whose visibility probe fails
still resolves to a portable HTTPS URL instead of an SSH URL that only
works where SSH keys are configured.
- When every probe fails, the resolver falls back to HTTPS for shorthand
and HTTPS-style specifiers, and only guesses SSH when the user
explicitly provided an SSH URL.
- A repository that could not be confirmed public is no longer resolved
to the host's anonymous archive URL (e.g. `codeload.github.com`, which
would fail to download for a private repository); it stays a regular
`git` resolution so installs can use ambient Git credentials such as
credential helpers and tokens.

Note that a private repository that is reachable both over authenticated
HTTPS and over SSH now resolves to its HTTPS URL, where previous
versions recorded the SSH URL.

Fixes
[pnpm/pnpm#13276](https://redirect.github.com/pnpm/pnpm/issues/13276).

  <!-- cspell:ignore publickey -->

- `ng build` and `nuxt build` now work under the global virtual store:
pnpm's built-in compatibility extensions add the `tslib` dependency that
`@angular/build` uses without declaring and the `unplugin` dependency
that `@nuxt/vite-builder` v4 uses without declaring.

- Fixed `link:` dependencies under `enableGlobalVirtualStore` so linked
children are materialized and slots remain isolated by their resolved
link targets.

- An install that skips resolution because `pnpm-lock.yaml` is already
up to date now reacts fully to packages the lockfile removed — for
example after pulling a lockfile in which a dependency was deleted. The
hoist layer is recomputed, so a package that became hoistable when a
direct dependency was removed is hoisted, and `pendingBuilds` entries
for removed packages are dropped instead of staying pending forever.

- The held-back-update warning printed by `pnpm update` no longer fires
when `minimumReleaseAge` is the actual reason a newer version was not
picked. The warning's baseline now applies the same maturity cutoff as
the pick itself, so it no longer wrongly attributes the hold-back to
"your manifests and already installed dependencies" or recommends an
override that would defeat the age gate. See
[#&#8203;13071](https://redirect.github.com/pnpm/pnpm/issues/13071).

- Checking whether `ignoredOptionalDependencies` is up to date no longer
reorders the configured patterns. The check sorted them in place, which
could move an `!` exclusion ahead of the pattern it excludes from and
flip which optional dependencies were ignored.

- Changing `autoInstallPeers`, `dedupePeers`, `peersSuffixMaxLength`,
`excludeLinksFromLockfile`, or `injectWorkspacePackages` no longer
re-resolves the dependency graph when the lockfile proves the setting
cannot affect it: no package or project declares a peer dependency for
the peer settings, and no project depends on a directory or on another
workspace project for the link and injection settings. The new setting
is recorded in `pnpm-lock.yaml` and the install proceeds from the
existing resolution. Every other case still falls back to a full
resolution.

- Adding, editing, or removing an entry in `patchedDependencies` no
longer re-resolves the dependency graph. Resolution never reads a patch
— it only records the patch file's hash against the package it matches —
so the install now rewrites the affected entries in `pnpm-lock.yaml` and
materializes the patched package from the store instead. Installs still
fall back to a full resolution when the patched package is reachable as
a peer dependency, and when the new configuration would leave a patch
unused while `allowUnusedPatches` is off, so `ERR_PNPM_UNUSED_PATCH` is
still reported.

- Resolving a private git repository no longer blocks on an interactive
credential prompt: `git ls-remote` now fails fast with an authentication
error when git has no credentials for the repository
[#&#8203;13522](https://redirect.github.com/pnpm/pnpm/issues/13522).

- Lockfile verification now honors offline mode by using cached registry
metadata instead of reaching the registry. When the required metadata is
not available locally, verification reports the same
`ERR_PNPM_NO_OFFLINE_META` condition used by offline resolution.

- POSIX shell shims now follow symbolic links before computing
`basedir`, preventing execution failures when a shim is invoked via an
external symlink on `PATH`
[#&#8203;13405](https://redirect.github.com/pnpm/pnpm/issues/13405).

- The automatic `packageManager` version switch works again on
registries whose tarball URLs point at a different host than the
registry itself (load-balanced feed proxies, Artifactory-style mirrors).
Package-manager entries are now always recorded with integrity-only
resolutions — the download URL is derived from the trusted bootstrap
registry instead — and entries persisted in an invalid shape by an
earlier pnpm are discarded and re-resolved instead of failing every
command
[#&#8203;13619](https://redirect.github.com/pnpm/pnpm/issues/13619).

- Registries that serve no npm signature metadata (private mirrors and
feed proxies commonly strip `dist.signatures`) no longer break the
automatic `packageManager` version switch and `pnpm self-update`
[#&#8203;13147](https://redirect.github.com/pnpm/pnpm/issues/13147).
When the configured registry cannot provide a verifiable signature, pnpm
now fetches the signature from `registry.npmjs.org` and verifies it
against the same embedded npm keys over the installed integrity — which
proves exactly the same thing. If no signature can be obtained from
either source (for example, both are unreachable, or the registry
publishes only a `shasum`), pnpm proceeds with a warning instead of
failing, but only when the packages resolve through a registry
configured in the user's own (non-project) configuration; the download
stays pinned by the lockfile integrity, and a signature that exists but
does not validate still fails the switch.

- `pnpm fetch`, and any install run with `virtualStoreOnly`, no longer
writes a `.pnp.cjs` loader under `nodeLinker: pnp`. These installs
populate the virtual store without linking the project, so the loader
would have claimed the project resolves out of a store it was never
linked into. The importer links and `node_modules/.package-map.json`
were already skipped; the PnP loader now follows the same rule.

- Prevent pnpm from removing project files when `modulesDir` resolves to
the project root.

- Speed up installs after adding `ignoredOptionalDependencies` patterns
by removing newly ignored optional dependencies and pruning packages
that are no longer reachable without resolving the dependency graph
again.

- When a failed install re-copies a bin script from the store, rerunning
`pnpm install` now reapplies the executable bit to the bin instead of
leaving it non-executable
[#&#8203;12742](https://redirect.github.com/pnpm/pnpm/issues/12742).

- `pnpm root -g` and `pnpm bin -g` now print warnings to stderr instead
of stdout, so their stdout stays a clean, machine-readable path.
Previously, running either command with `--global` in a project that
pins a package manager (e.g. via the `packageManager` field) printed a
warning like `[WARN] Using --global skips the package manager check for
this project` ahead of the path, breaking programs that capture the
output as a path
[#&#8203;13672](https://redirect.github.com/pnpm/pnpm/issues/13672).

In pnpm 12, `pnpm root -g` and `pnpm prefix -g` are now supported (they
previously failed with `ERR_PNPM_CLI_ROOT_GLOBAL_UNSUPPORTED` /
`ERR_PNPM_CLI_PREFIX_GLOBAL_UNSUPPORTED`), and the reporter output of
`dlx`, `create`, `config`, `sbom`, `with`, `store`, `prefix`, `root`,
and `bin` goes to stderr, matching pnpm 11.

- `pnpm setup` no longer makes Node.js print a
`MODULE_TYPELESS_PACKAGE_JSON` warning about `dist/worker.js` on every
command. The `package.json` it writes next to a standalone executable
now declares `"type": "module"`.

- `pnpm update` without saving no longer records a version that the
manifest's range excludes. The kept range stays authoritative: a
requested version outside it is skipped with a warning, and a requested
range, a dist tag, or `--latest` resolves within it instead of past it.
Previously each of these could write a lockfile entry that contradicted
its own specifier, which the next `pnpm install --frozen-lockfile`
rejected with `ERR_PNPM_OUTDATED_LOCKFILE`
[#&#8203;12764](https://redirect.github.com/pnpm/pnpm/issues/12764).

- `pnpm version -r --json` now outputs `[]` instead of human-readable
text when no pending changes exist
[`pnpm/pnpm#13217`](https://redirect.github.com/pnpm/pnpm/issues/13217).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.20.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.20.0):
pnpm 11.20

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.19.0...v11.20.0)

#### Minor Changes

- **Security fix.** Affects projects using `namedRegistries` on pnpm
11.1.0–11.19.x. It is **semi-breaking** for those projects — see "If you
use named registries" below.

The lockfile recorded no marker for which registry a package came from.
Packages were keyed by `name@version` alone, and entry lookup went
through `refToRelative(ref, name)`, so a dependency you declared against
one registry could be satisfied by an entry that was actually resolved
from another. When two registries served the same name and version, both
collapsed onto a single `packages:` entry and whichever resolved first
decided the tarball every consumer got.

That is a package-substitution risk: a package you expect from your
private registry could be installed from a different registry that
publishes the same name and version, and the lockfile recorded nothing
that would let you tell.

Packages resolved from a named registry are now recorded under
registry-qualified keys (`<name>@<registryName>:<version>`, e.g.
`foo@work:1.0.0`), so each registry gets its own entry and the lockfile
pins which one a dependency came from.

The lockfile format version is unchanged. Registry-qualified keys appear
only for packages resolved from a named registry, so a project that does
not use `namedRegistries` sees no difference, and older pnpm versions
keep reading the file.

##### If you use named registries

Your next non-frozen install re-keys those entries, which shows up as a
lockfile diff. Commit it — that diff is the fix being applied. Review
it: an entry that moves to a registry you did not expect is worth
investigating.

Everyone working on the project should be on this version or newer
before you do. An older pnpm reads the re-keyed lockfile fine — frozen
installs are unaffected — but it does not produce registry-qualified
keys itself, so any install that updates the lockfile writes those
entries back to the old shape, and the next install on a current pnpm
re-qualifies them. The result is a lockfile that flips back and forth,
and while it is in the old shape the project is exposed again. Because
the lockfile format version is deliberately unchanged, pnpm cannot
detect this and warn you about it.

There is no setting to keep the old behavior: the old shape is the
vulnerability.

Tarball URLs that follow the standard registry layout are no longer
written to the lockfile for named-registry packages; they are recomputed
from the `namedRegistries` setting on demand.

To use named registries, map your aliases in `pnpm-workspace.yaml`:

```yaml
namedRegistries:
  work: https://npm.enterprise.example.com/
```

##### New built-in `npmjs:` alias

`npmjs:` now resolves to `https://registry.npmjs.org/` with no
configuration, alongside the existing `gh:` alias for GitHub Packages.
It pins a dependency to the public registry even when `registry` points
elsewhere, such as an internal proxy:

```json
{ "dependencies": { "left-pad": "npmjs:^1.3.0" } }
```

`npm:` cannot do this — it is the alias protocol (`npm:<name>@<range>`)
and resolves through whatever `registry` points at.

**If you mirror or proxy npmjs, point the alias at your mirror:**

```yaml
namedRegistries:
  npmjs: https://npm.internal.example.com/
```

Built-in registry URLs are also the prefixes a lockfile's recorded
tarball URL is matched against when pnpm verifies a package. Without the
override, an entry whose tarball URL is on `registry.npmjs.org` is
verified against the public registry rather than your mirror. This only
affects lockfiles that record such URLs — a canonical URL for your
configured registry is omitted from the lockfile and unaffected — and
only when a tarball-URL, `minimumReleaseAge`, or `trustPolicy` check
runs. Overriding the alias is the same escape hatch GHES users already
have for `gh`.

Every alias the lockfile references must stay in `namedRegistries`:
reading an entry whose alias is gone fails with
`ERR_PNPM_MISSING_NAMED_REGISTRY` rather than silently falling back to
the default registry, since that would fetch a different package.
Renaming an alias re-resolves the packages that used it.

Named registry aliases that shadow a reserved dependency specifier
prefix (`file`, `link`, `workspace`, `runtime`, `npm`, `jsr`, ...) are
now rejected with `ERR_PNPM_RESERVED_NAMED_REGISTRY_NAME` instead of
being silently shadowed by the corresponding resolver.

`pnpm licenses` and `pnpm sbom` now keep the two artifacts apart as
well: license records carry the registry alias, and SBOM components
carry the purl `repository_url` qualifier.

#### Patch Changes

- An empty `http-proxy`, `https-proxy`, `proxy`, or `no-proxy` value —
from the `.npmrc`, `pnpm-workspace.yaml`, the CLI, or the `HTTP_PROXY` /
`HTTPS_PROXY` / `PROXY` / `NO_PROXY` environment variables — no longer
fails the install with `ERR_PNPM_INVALID_PROXY`. Empty settings read as
unset, so a shell exporting `HTTP_PROXY=` disables the proxy, and an
empty `proxy=` in the `.npmrc` no longer suppresses `HTTPS_PROXY`
[#&#8203;13533](https://redirect.github.com/pnpm/pnpm/issues/13533).

`proxy=false` in the `.npmrc` or `proxy: false` in `pnpm-workspace.yaml`
now turns proxying off instead of being read as a proxy host named
`false`. `false` and `null` on `https-proxy` / `http-proxy` / `no-proxy`
read as unset, and on the command line they are ordinary host names,
since a flag carries its value verbatim.

- The env lockfile no longer pins `@pnpm/exe` alongside `pnpm` when the
wanted pnpm version is 12 or newer. From v12 the unscoped `pnpm` package
is itself the native executable, so `@pnpm/exe` is not published for it
and resolving it would fail. The engine identity check now verifies the
native binary through whichever package ships it.

- `lexCompare` and `nerfDart` are now published as
`@pnpm/text.ordinal-comparator` and `@pnpm/config.registry-auth-key`.
Use these instead of `@pnpm/util.lex-comparator` and
`@pnpm/config.nerf-dart`.

- Fixed the order in which pnpm matches a lockfile's recorded tarball
URL against known registry URLs. Two registry URLs of equal length were
previously ordered arbitrarily, so which one a tarball URL matched could
differ between runs.

- Dependency resolution is faster: package metadata is now filtered once
per packument instead of once per dependency edge when
`minimumReleaseAge` is active, and parsed semver versions and ranges are
reused instead of re-parsed on every comparison.

- Security: `pnpm rebuild` now refuses a lockfile whose `packages` key
carries a path traversal in the package name (e.g.
`../../../escaped@1.0.0`), instead of running that package's lifecycle
scripts and linking its bins in a directory outside the virtual store.
Such a name is rejected with `ERR_PNPM_INVALID_DEPENDENCY_NAME`.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.19.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.19.0):
pnpm 11.19

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.18.0...v11.19.0)

#### Minor Changes

- `pnpm login` no longer requires an interactive terminal when the
registry supports web-based login: without a TTY it prints the
authentication URL (skipping the QR code and the "Press ENTER to open
the URL in your browser" prompt) and polls the registry until the
browser approval completes. Only the classic username/password login
still fails with `ERR_PNPM_LOGIN_NON_INTERACTIVE` in a non-interactive
terminal.

- The `save-prefix` setting now accepts `=`: newly added dependencies
are saved with an explicit `=` operator (`=1.2.3`) instead of the
setting being silently treated as the default `^`.

#### Patch Changes

- `allowBuilds` entries can now approve git-hosted packages that pnpm
downloads as a tarball, such as `github:` dependencies (which are
fetched from `codeload.github.com` rather than cloned), by their
repository URL without the resolved commit hash. This matches the
hashless `git+` matching already supported for cloned git dependencies.
For example:

  ```yaml
  allowBuilds:
    "foo@git+https://github.com/org/foo.git": true
  ```

This approves the package whether pnpm clones it or downloads a tarball,
so the entry no longer has to be updated every time the pinned commit
changes. GitLab and Bitbucket tarball downloads are matched the same
way. Approving or denying a specific resolved commit by its full tarball
dep path continues to work.

- `pnpm outdated --include-github-actions` no longer blocks on an
interactive git credential prompt when a workflow uses a private action
repo.

- Prevented `minimumReleaseAge` from replacing `latest` with a
SemVer-greater version than the registry tag target
[#&#8203;13034](https://redirect.github.com/pnpm/pnpm/issues/13034).

- Fixed empty `bundledDependencies` and `bundleDependencies` arrays
causing nondeterministic lockfile changes. See
[#&#8203;13123](https://redirect.github.com/pnpm/pnpm/issues/13123).

- The install summary no longer prints `(X is available)` when the
registry's `dist-tags.latest` is still held back by the active
`minimumReleaseAge` policy. The hint only ever names the actual latest
tag, so an immature latest suppresses the hint instead of advertising
the version pnpm just refused to install
[#&#8203;11698](https://redirect.github.com/pnpm/pnpm/issues/11698).

- `pnpm update` keeps the explicit `=` operator of an exact version pin:
a dependency saved as `=3.5.1` now updates to `=3.5.2` instead of the
bare `3.5.2`. See
[#&#8203;13168](https://redirect.github.com/pnpm/pnpm/issues/13168).

- Preserve a workspace dependency's `link:` entry when a run does not
target it — e.g. `pnpm update <other-pkg>` (with or without
`--recursive`), or a plain install after a root/catalog dependency
change — with `injectWorkspacePackages`, instead of spuriously rewriting
it to a peer-suffixed `file:` protocol. See
[#&#8203;10433](https://redirect.github.com/pnpm/pnpm/issues/10433).

- Workspace dependencies declared with a relative path (e.g. `"foo":
"workspace:../foo"`) are no longer silently dropped from the workspace
projects graph, so `--filter` selection and the topological order of
recursive commands take them into account.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.18.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.18.0):
pnpm 11.18

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.17.0...v11.18.0)

#### Minor Changes

- Fixed an installed optional dependency being left without one of its
own required dependencies. When a package reached through
`optionalDependencies` is installable on the current system but one of
its regular `dependencies` is not, a lockfile-based install skipped that
dependency and installed the parent anyway, so importing the parent
failed with `MODULE_NOT_FOUND`. The dependency is now installed, and an
install-check warning reports the incompatibility. A dependency is still
only skipped when every path to it is optional, or when the package that
pulls it in was itself skipped
[#&#8203;13286](https://redirect.github.com/pnpm/pnpm/issues/13286).

- `pnpm setup` now appends `PNPM_HOME` and the global bin directory to
the GitHub Actions environment files (`GITHUB_ENV` and `GITHUB_PATH`),
so later steps in the same job can run `pnpm add --global` and other
global commands
[#&#8203;9191](https://redirect.github.com/pnpm/pnpm/issues/9191).

- Added support for `publishConfig.name`, which publishes a package
under a different name than the one its manifest carries in the
workspace. It is for a project whose published name is already taken by
a sibling project, which otherwise has to be renamed by a build step
just before publishing. Only the published artifact is renamed —
dependents, `pnpm-lock.yaml`, and release tooling keep addressing the
project by its manifest name — and the new name reaches the packed
manifest, the tarball filename, and everything that addresses the
package at the registry: the already-published check of `pnpm publish
-r`, its registry selection, and the release-planning probes of `pnpm
change status` and `pnpm version -r`
[#&#8203;13345](https://redirect.github.com/pnpm/pnpm/issues/13345).

- `pnpm self-update` no longer takes any instruction from the project it
is run in:

- pnpm is fetched through the same trusted registry and auth
configuration used when switching pnpm versions, so a project `.npmrc`
or `pnpm-workspace.yaml` can no longer redirect the download or attach
credentials to it, and the project's default `.pnpmfile.(c|m)js` is no
longer loaded. Pnpmfiles from trusted sources (the `pnpmfile` setting,
the global pnpmfile, config dependencies) still apply.
- The `minimumReleaseAge` settings in `pnpm-workspace.yaml` no longer
affect `self-update`. They still govern the project's own dependencies;
for `self-update` the cooldown now comes from the built-in default, your
global config, a `PNPM_CONFIG_*` environment variable, or a command-line
flag. This fixes `self-update` failing inside a workspace that raises
the cutoff while succeeding everywhere else, and stops a repository from
either waiving the cooldown or keeping you on an outdated pnpm by
raising it.
- The same applies to the `trustPolicy` settings and to `ci`: a project
can no longer weaken the trust check that guards the pnpm download, nor
re-enable the confirmation prompt that a CI run suppresses.

When `self-update` refuses a version that is younger than the cutoff, an
interactive run now offers to update anyway; non-interactive runs still
fail. CI never prompts, even on a runner that attaches a TTY.

#### Patch Changes

- Fixed `pnpm licenses list` to report every version when the same
package is installed under multiple aliases
[pnpm/pnpm#13438](https://redirect.github.com/pnpm/pnpm/issues/13438).

- Sort `pnpm dedupe --check` snapshot changes for stable output across
pnpm implementations.

- Strip Unicode formatting characters from registry- and
manifest-derived terminal output.

- Speed up installs after compatible catalog or direct dependency range
changes by retaining the locked version without resolving the dependency
graph again.

- Speed up installs after safe override changes by reusing unambiguous
compatible dependency resolutions, pruning obsolete dependencies,
applying independent replacements and removals together, and handling
parent-scoped `"-"` overrides without full lockfile resolution.

- Installing a local `file:` directory dependency with the global
virtual store enabled no longer fails with `TypeError: Cannot read
properties of undefined (reading 'split')`
[#&#8203;13335](https://redirect.github.com/pnpm/pnpm/issues/13335).

Local directory dependencies — `file:` directories and injected
workspace packages — now get a global-virtual-store slot of their own
per project. They used to share one slot across every project that
depended on a directory of the same name, so a project could end up
linked to another project's copy of the dependency.

- The `Workspace` column of `pnpm update --interactive` now falls back
to the project's path when its `name` is only whitespace, as it already
did for a missing or empty one — all three render an equally blank label
otherwise.

- Checking GitHub Actions dependencies for updates is now opt-in for
every command. Neither `pnpm outdated` nor `pnpm update` reads the
workflow files unless `--include-github-actions` is passed or
`update.githubActions` is set to `true` in `pnpm-workspace.yaml`.
Reading them runs `git ls-remote` against every referenced repository,
which fails in environments where GitHub is not reachable the way pnpm
assumes (a GitHub Enterprise Server, a custom certificate authority, or
an offline network)
[#&#8203;13254](https://redirect.github.com/pnpm/pnpm/issues/13254).

  `pnpm outdated` accepts the `--include-github-actions` option too.

- `pnpm update --interactive` now measures its table in terminal columns
rather than in characters. A package name, workspace name, or version
containing wide characters (CJK, most emoji) no longer knocks its row's
columns out of line with the rest of the group, and a wide character in
a version no longer aborts the command with `Subject parameter value
width cannot be greater than the container width`
[#&#8203;13357](https://redirect.github.com/pnpm/pnpm/issues/13357).

- The `Workspace` column of `pnpm update --interactive` is more
informative in two cases. A dependency outdated at the same version in
several workspace projects is offered as one choice, since selecting it
updates every project — that choice now names all of them instead of
only the first. And a workspace project without a `name` is now labelled
with its path rather than left blank, so several unnamed projects can be
told apart.

- An auto-installed *optional* peer is no longer hoisted at a version
the workspace root's own dependency on that package excludes.
`resolvePeersFromWorkspaceRoot` already made the workspace root's
specifier decide which version a missing *required* peer is installed
at; the optional-peer picker ignored it and always took the highest
version present anywhere in the graph. In a workspace whose root pins
`postcss: 8.5.10`, an importer that depends on `webpack` and declares no
`postcss` of its own got `postcss@8.5.22` hoisted for
`terser-webpack-plugin`'s optional `postcss` peer, leaving two
`postcss@8.5.x` instances in the graph
[#&#8203;13320](https://redirect.github.com/pnpm/pnpm/issues/13320).

- `overrides` now also govern peers that pnpm auto-installs. Previously
an override only rewrote dependencies declared in a manifest, so a peer
nobody declares — installed because `autoInstallPeers` is on — resolved
against its declared peer range and could bring in a second copy of the
very package the override pinned. For example, with `overrides: { react:
npm:react@19.2.0 }` and a lone `lucide-react` dependency, pnpm installed
`react@18.3.1`; it now installs the pinned `react@19.2.0`
[#&#8203;13320](https://redirect.github.com/pnpm/pnpm/issues/13320).

- Under `resolvePeersFromWorkspaceRoot`, a workspace root dependency
declared with `link:` or `file:` (or the path form of `workspace:`, such
as `workspace:../pkg`) now satisfies another project's missing peer
dependency at the linked package's own version, instead of being hoisted
as a path. Those specifiers are relative to the project that declares
them, so the same specifier reached a different directory — or none —
from the project the peer was hoisted into, leaving a broken link. The
root now has the same authority over the peer as it has when it declares
the package with a version range
[#&#8203;13373](https://redirect.github.com/pnpm/pnpm/issues/13373).

- Installs through a pnpr server now apply the project's whole
verification policy. `minimumReleaseAgeExclude`,
`minimumReleaseAgeIgnoreMissingTime`, `trustPolicy`,
`trustPolicyExclude`, `trustPolicyIgnoreAfter`, and `trustLockfile` were
ignored, so excluded packages were still held back and a lockfile
containing them could be rejected.

`trustPolicy: no-downgrade` no longer fails with
`TRUST_POLICY_INCOMPATIBLE_WITH_PNPR` when a pnpr server is configured.

`--frozen-lockfile` and `--no-prefer-frozen-lockfile` are now honored on
the pnpr path, instead of resolving and rewriting the lockfile anyway.
Since `frozenLockfile` defaults to `true` on CI, a CI install through a
pnpr server now fails on an out-of-date lockfile rather than updating
it.

- Workspace installs through a pnpr server no longer crash with `Cannot
read properties of undefined (reading 'filter')` after linking, when
`minimumReleaseAge` is active
[#&#8203;13275](https://redirect.github.com/pnpm/pnpm/issues/13275).

- Fixed `pnpm dedupe` updating valid catalog resolutions when another
matching version exists in the lockfile.

- `pnpm -r run "/pattern/" --no-bail` no longer exits zero when one of a
project's matched scripts fails and a later one passes. The run summary
carries a single status per project, and the passing script overwrote
the recorded failure.

- Restored the store block a first install prints, naming how packages
were materialized and where the stores live
[#&#8203;13315](https://redirect.github.com/pnpm/pnpm/issues/13315):

  ```text
Packages are hard linked from the content-addressable store to the
virtual store.
    Content-addressable store is at: ~/.local/share/pnpm/store/v11
    Virtual store is at:             node_modules/.pnpm
  ```

- The root project's `pnpm:devPreinstall` script now runs before
resolution and linking, as it does in pnpm 11. It is skipped under
`--ignore-scripts`, `--lockfile-only` and `--dry-run`, by `pnpm fetch`
and `pnpm rebuild`, and by a repeat install that is already up to date.
Workspaces that use the hook to prepare state the install depends on —
such as [next.js](https://redirect.github.com/vercel/next.js), which
generates a placeholder `next` bin with it — were left with dependents
linked against files that were never created
[#&#8203;13313](https://redirect.github.com/pnpm/pnpm/issues/13313).

- Prevented `pnpm dedupe --check` from removing an incompatible
`node_modules` directory.

- `pnpm update --workspace` no longer links dependencies the user never
named:

- Running it with `updateConfig.ignoreDependencies` configured no longer
fails with `ERR_PNPM_WORKSPACE_PACKAGE_NOT_FOUND` for a dependency that
is only published to the registry. Such dependencies keep their
specifiers, as they already did when no dependencies were ignored.
- Passing package selectors that match no direct dependency no longer
falls back to linking every workspace dependency.

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

</details>

<details>
<summary>typescript-eslint/typescript-eslint
(typescript-eslint)</summary>

###
[`v8.67.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8670-2026-08-10)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.66.0...v8.67.0)

##### 🚀 Features

- **typescript-eslint:** export basic globs for using tseslint
([#&#8203;12105](https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12105))

##### ❤️ Thank You

- Claude Sonnet 5
- Evyatar Daud
[@&#8203;StyleShit](https://redirect.github.com/StyleShit)
- Josh Goldberg
- Josh Goldberg ✨
- Kirk Waiblinger
[@&#8203;kirkwaiblinger](https://redirect.github.com/kirkwaiblinger)

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.67.0)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

###
[`v8.66.0`](https://redirect.github.com/typescript-eslint/typescript-eslint/blob/HEAD/packages/typescript-eslint/CHANGELOG.md#8660-2026-08-03)

[Compare
Source](https://redirect.github.com/typescript-eslint/typescript-eslint/compare/v8.65.0...v8.66.0)

This was a version bump only for typescript-eslint to align it with
other projects, there were no code changes.

See [GitHub
Releases](https://redirect.github.com/typescript-eslint/typescript-eslint/releases/tag/v8.66.0)
for more information.

You can read about our [versioning
strategy](https://typescript-eslint.io/users/versioning) and
[releases](https://typescript-eslint.io/users/releases) on our website.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4yOS41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
🤖 I have created a release *beep* *boop*
---


## [0.2.8](https://github.com/Goloom-App/goloom/compare/v0.2.7...v0.2.8)
(2026-08-16)


### Bug Fixes

* **deps:** update frontend non-major dependencies
([#74](https://github.com/Goloom-App/goloom/issues/74))
([a36afb0](a36afb0e20))
* **deps:** update module github.com/mmcdole/gofeed to v1.4.1
([#84](https://github.com/Goloom-App/goloom/issues/84))
([26eab21](26eab21965))
* **deps:** update module github.com/modelcontextprotocol/go-sdk to
v1.7.0 ([#77](https://github.com/Goloom-App/goloom/issues/77))
([4c051d5](4c051d5e86))
* **deps:** update module modernc.org/sqlite to v1.55.0
([#76](https://github.com/Goloom-App/goloom/issues/76))
([ca715f8](ca715f85e9))
* **recurring:** constrain horizon regenerate
([#73](https://github.com/Goloom-App/goloom/issues/73))
([6e2dfef](6e2dfef261))
* **recurring:** make "skip next" drop the round the user actually sees
([#83](https://github.com/Goloom-App/goloom/issues/83))
([a554c52](a554c523c5))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [@astrojs/starlight](https://starlight.astro.build)
([source](https://redirect.github.com/withastro/starlight/tree/HEAD/packages/starlight))
| [`^0.41.0` →
`^0.42.0`](https://renovatebot.com/diffs/npm/@astrojs%2fstarlight/0.41.7/0.42.2)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/@astrojs%2fstarlight/0.42.2?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@astrojs%2fstarlight/0.41.7/0.42.2?slim=true)
|

---

### Release Notes

<details>
<summary>withastro/starlight (@&#8203;astrojs/starlight)</summary>

###
[`v0.42.2`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#0422)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.42.1...@astrojs/starlight@0.42.2)

##### Patch Changes

-
[#&#8203;4201](https://redirect.github.com/withastro/starlight/pull/4201)
[`fafd989`](fafd989453)
Thanks
[@&#8203;linux-universe](https://redirect.github.com/linux-universe)! -
Add 1 new icon: `fluxer`

###
[`v0.42.1`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#0421)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.42.0...@astrojs/starlight@0.42.1)

##### Patch Changes

-
[#&#8203;4198](https://redirect.github.com/withastro/starlight/pull/4198)
[`96a44d4`](96a44d4f29)
Thanks [@&#8203;mayank99](https://redirect.github.com/mayank99)! -
Removes the `popover` attribute from the sidebar pane on desktop
viewports. This ensures the desktop sidebar doesn't stay in a "hidden"
popover visibility state.

###
[`v0.42.0`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#0420)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.41.11...@astrojs/starlight@0.42.0)

##### Minor Changes

-
[#&#8203;3572](https://redirect.github.com/withastro/starlight/pull/3572)
[`292fb17`](292fb179cb)
Thanks [@&#8203;HiDeoo](https://redirect.github.com/HiDeoo)! -
Distributes package as JavaScript files with dedicated type declaration
files instead of TypeScript source files.

-
[#&#8203;4121](https://redirect.github.com/withastro/starlight/pull/4121)
[`2623ae6`](2623ae60af)
Thanks [@&#8203;delucis](https://redirect.github.com/delucis)! -
Simplifies markup for Starlight’s mobile menu toggle

**⚠️ Potentially breaking change:** If you use a theme plugin, custom
styles, or component overrides targeting the `MobileMenuToggle` button
or `PageFrame` components, you may need to adjust these for the new
markup. The button is no longer wrapped in a `<starlight-menu-button>`
custom element and no longer uses the `aria-expanded` attribute.
Instead, you can use the `.sl-menu-button` class name to target the
button and the `:popover-open` pseudo-class to style the menu open state
specifically.

In the following example, custom styles for the menu button are updated
for the new approach:

  ```diff
  - starlight-menu-button button {
  + .sl-menu-button {
    color: var(--sl-color-text);
  }

  - starlight-menu-button[aria-expanded='true'] button {
  + .sl-menu-button:has(~ :popover-open) {
    color: var(--sl-color-text-accent-high);
  }
  ```

See
[`MobileMenuToggle.astro`](https://redirect.github.com/withastro/starlight/blob/main/packages/starlight/components/MobileMenuToggle.astro)
and
[`PageFrame.astro`](https://redirect.github.com/withastro/starlight/blob/main/packages/starlight/components/PageFrame.astro)
on GitHub for the full source code of the updated components.

-
[#&#8203;3572](https://redirect.github.com/withastro/starlight/pull/3572)
[`292fb17`](292fb179cb)
Thanks [@&#8203;HiDeoo](https://redirect.github.com/HiDeoo)! - Removes
the `tagline` configuration option, which was never used.

If your configuration included a `tagline` option, you can safely remove
it without any replacement.

-
[#&#8203;4134](https://redirect.github.com/withastro/starlight/pull/4134)
[`6135f01`](6135f015b5)
Thanks [@&#8203;HiDeoo](https://redirect.github.com/HiDeoo)! - Updates
internal `@astrojs/mdx`, `@astrojs/markdown-satteri`, and `satteri`
dependencies.

⚠️ **BREAKING CHANGE:** The following minimum versions are now required:

  - `astro` v7.2.10 or later
  - `@astrojs/markdown-satteri` 0.4.0 or later (if you use it)
  - `@astrojs/markdown-remark` 7.3.0 or later (if you use it)

  Please update Starlight and Astro together:

  ```sh
  npx @astrojs/upgrade
  ```

-
[#&#8203;4121](https://redirect.github.com/withastro/starlight/pull/4121)
[`2623ae6`](2623ae60af)
Thanks [@&#8203;delucis](https://redirect.github.com/delucis)! -
Refactors Starlight’s mobile menu toggle to work when JavaScript fails
or is disabled

⚠️ **BREAKING CHANGE:** This release drops official support for
Chromium-based browsers prior to version 116 (released August 2023),
Safari-based browsers prior to version 17.0 (released September 2023),
and Firefox prior to version 125 (released April 2024). You can find a
list of currently supported browsers and their versions using this
[browserslist
query](https://browsersl.ist/#q=%3E+0.5%25%2C+not+dead%2C+Chrome+%3E%3D+116%2C+Edge+%3E%3D+116%2C+Firefox+%3E%3D+125%2C+Safari+%3E%3D+17.0%2C+iOS+%3E%3D+17.0%2C+not+op_mini+all).

This change also removes the `data-mobile-menu-expanded` attribute,
which was previously added to `<body>` while the mobile menu is open. If
you have custom code that was depending on this attribute, you will need
to update it to use a new selector to check if the mobile menu is open.

In the following example, a custom background colour for the site header
while the menu is open is updated for the new approach:

  ```diff
  - [data-mobile-menu-expanded] header {
  + body:has(sl-sidebar-pane:popover-open) header {
    background-color: var(--sl-color-bg);
  }
  ```

###
[`v0.41.11`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#04111)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.41.10...@astrojs/starlight@0.41.11)

##### Patch Changes

-
[#&#8203;4167](https://redirect.github.com/withastro/starlight/pull/4167)
[`32a5e29`](32a5e29127)
Thanks [@&#8203;HiDeoo](https://redirect.github.com/HiDeoo)! - Fixes a
layout issue and anchor links appearing for hidden headings, e.g.
footnote headings, when `markdown.headingLinks` is enabled or the
`<AnchorHeading>` component is used.

-
[#&#8203;4148](https://redirect.github.com/withastro/starlight/pull/4148)
[`cdfafd8`](cdfafd8eed)
Thanks [@&#8203;ematipico](https://redirect.github.com/ematipico)! -
Optimizes sidebar data generation logic to speed up sites with large
sidebars

###
[`v0.41.10`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#04110)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.41.9...@astrojs/starlight@0.41.10)

##### Patch Changes

-
[#&#8203;4160](https://redirect.github.com/withastro/starlight/pull/4160)
[`88442c3`](88442c3336)
Thanks
[@&#8203;ArmandPhilippot](https://redirect.github.com/ArmandPhilippot)!
- Adds the missing translations for Expressive Code in the following
locales: `ar`, `hi`, `it`, `ja`, `ko`, `pt`, `zh-CN`, and `zh-TW`.

-
[#&#8203;4156](https://redirect.github.com/withastro/starlight/pull/4156)
[`57af92d`](57af92d91f)
Thanks [@&#8203;pyxelr](https://redirect.github.com/pyxelr)! - Adds 1
new icon: `hypothesis`

-
[#&#8203;4159](https://redirect.github.com/withastro/starlight/pull/4159)
[`a0e0ba2`](a0e0ba263c)
Thanks
[@&#8203;trueberryless](https://redirect.github.com/trueberryless)! -
Adds 1 new icon: `npmx`

###
[`v0.41.9`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#0419)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.41.8...@astrojs/starlight@0.41.9)

##### Patch Changes

-
[#&#8203;4145](https://redirect.github.com/withastro/starlight/pull/4145)
[`1c90d69`](1c90d69b42)
Thanks [@&#8203;pyxelr](https://redirect.github.com/pyxelr)! - Adds 1
new icon: `goodreads`

###
[`v0.41.8`](https://redirect.github.com/withastro/starlight/blob/HEAD/packages/starlight/CHANGELOG.md#0418)

[Compare
Source](https://redirect.github.com/withastro/starlight/compare/@astrojs/starlight@0.41.7...@astrojs/starlight@0.41.8)

##### Patch Changes

-
[#&#8203;4142](https://redirect.github.com/withastro/starlight/pull/4142)
[`cacbc9f`](cacbc9ff45)
Thanks [@&#8203;alebelcor](https://redirect.github.com/alebelcor)! -
Adds 1 new icon: `whatsApp`

-
[#&#8203;4133](https://redirect.github.com/withastro/starlight/pull/4133)
[`3944311`](3944311bed)
Thanks [@&#8203;delucis](https://redirect.github.com/delucis)! -
Internal refactor: numbered `id` attributes in the `<Tabs>` component
are now page-specific instead of using a global counter

-
[#&#8203;4138](https://redirect.github.com/withastro/starlight/pull/4138)
[`cd4b665`](cd4b6655f3)
Thanks [@&#8203;delucis](https://redirect.github.com/delucis)! - Fixes
localisation of code block UI elements when using the Sätteri Markdown
processor

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC42MS4zIiwidXBkYXRlZEluVmVyIjoiNDQuMTAzLjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change | Pending |
|---|---|---|---|---|
| [golang](https://hub.docker.com/_/golang)
([source](https://redirect.github.com/docker-library/golang)) | stage |
minor | `1.26.5-alpine3.24` → `1.27.0-alpine3.24` | `1.27.1-alpine3.24`
|

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMy4yIiwidXBkYXRlZEluVmVyIjoiNDQuMTAzLjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
> ℹ️ **Note**
> 
> This PR body was truncated due to platform limits.

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://redirect.github.com/pnpm/pnpm/tree/main/pnpm)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm/npm/pnpm))
| [`11.21.0` →
`11.27.0`](https://renovatebot.com/diffs/npm/pnpm/11.21.0/11.27.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.27.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.21.0/11.27.0?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.27.0`](https://redirect.github.com/pnpm/pnpm/compare/v11.26.0...v11.27.0)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.26.0...v11.27.0)

###
[`v11.26.0`](https://redirect.github.com/pnpm/pnpm/compare/v11.25.0...v11.26.0)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.25.0...v11.26.0)

###
[`v11.25.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.25.0):
pnpm 11.25

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.24.0...v11.25.0)

#### Minor Changes

- Added an opt-in proof of concept that lets installs reuse a
dependency's build output across machines, by publishing and restoring
signed, organization-scoped artifacts through pnpr instead of running
the lifecycle scripts locally.

Configure it with the new `remoteSideEffectsCache` setting. A workspace
names the eligible `organization` and `packages`; everything describing
the act of signing — `publish`, `keyId`, `builderId`, `trustedKeys`,
`privateKey` and the provenance fields — is refused in
`pnpm-workspace.yaml` and read from the global config file or the
environment instead.

- Added macOS and Windows x64 and arm64 support to remote shared build
artifacts
[pnpm/pnpm#13771](https://redirect.github.com/pnpm/pnpm/issues/13771).

- Added the `audit.ignorePrune` setting. When set to `true`, `pnpm audit
--fix` removes ignored GHSA entries that no longer appear in the audit
report.

- Generalized the experimental shared-artifact protocol so candidates
and signed payloads identify a discriminated subject. Dependency side
effects use package and source-integrity subjects, while workspace tasks
use project and task subjects.

This changes shared-artifact request bodies and signed payloads. A pnpr
server and its clients have to be on matching versions.

- `pnpm init` now pins the latest pnpm version, instead of the version
of pnpm that ran the command. A project scaffolded by an outdated pnpm
therefore no longer inherits that staleness through its own
`devEngines.packageManager` / `packageManager` pin
[#&#8203;7490](https://redirect.github.com/pnpm/pnpm/issues/7490).

The version is read from the `latest` tag on the package-manager
registries. When that lookup cannot answer — no network, an unreachable
or slow registry, `offline`, or a `latest` that the `minimumReleaseAge`
/ `trustPolicy` settings reject — `pnpm init` pins the running version
as before, and never fails or hangs on the lookup. A `latest` that is
older than the running pnpm is never pinned either.

- A `scope` set in a project's `pnpm-workspace.yaml` is now ignored,
with a warning naming where to set it instead. `pnpm login` records the
scope as a `@scope:registry` route in the machine-global `auth.ini`,
which outranks `~/.npmrc` in every project — so a repository-committed
file could redirect a scope such as `@acme` for all of a user's other
projects after one routine login. Use `--scope`, the `PNPM_CONFIG_SCOPE`
environment variable, or the global config file instead
[#&#8203;13557](https://redirect.github.com/pnpm/pnpm/issues/13557).

- Verified remote build artifacts are persisted in the shared store with
their signed origin metadata. Later installs reverify the artifact
against current trust, policy, platform, and source before reuse, while
invalid remote variants are quarantined per channel
([pnpm/pnpm#13771](https://redirect.github.com/pnpm/pnpm/issues/13771)).

- Persist completed recursive tasks so `--resume-from` skips exactly the
work that passed during a matching interrupted or failed `pnpm -r run` /
`pnpm -r exec` invocation. When no compatible state exists, pnpm retains
its graph-based resume behavior.

- Allowed `pnpm update --patches` to refresh registry revisions through
a configured pnpr server while retaining locked package versions.

- Added explicit registry revision selection with `<version>+rN` and
`pnpm update --patches` for refreshing revision artifacts without
changing package versions. Registry-backed lockfile policy checks
recognize historical revisions, and pnpr now preserves safe revision
histories from upstream registries.

- Workspace install, rebuild, pack, publish, stage, and lifecycle work
now starts as soon as its dependencies finish instead of waiting for an
unrelated topological group.

- `pnpm stage approve` now approves several staged packages at once. Run
it without a stage id to pick from the staged versions interactively, or
pass a list of stage ids. The whole batch is approved with a single
one-time password, and pnpm asks for a new one only once the registry
stops accepting it. Inside a workspace, the selected packages are
approved in dependency order, and a package whose workspace dependency
could not be approved is skipped instead of being published against a
dependency that never reached the registry.

- Added per-task concurrency limits to workspace task orchestration. Set
`tasks.<name>.concurrency` in `pnpm-workspace.yaml` to limit how many
instances of that task may run across workspace projects at once:

  ```yaml
  tasks:
    build:
      concurrency: 2
  ```

- Added support for registry replacement tarballs using standard
integrity values, explicit revision fields, registry routing from the
`registries` setting, non-redirecting integrity-addressed URLs,
canonical safe-integer revision numbers, and pnpr proxying for immutable
upstream revision artifacts.

- `sideEffectsCache` now declares the whole of how a package's build
output is reused — whether one is restored, whether one is saved, and
the remote tier that shares it between machines:

  ```yaml
  sideEffectsCache:
    read: true
    write: true
    remote:
      org: acme
      packages: ['native-addon']
  ```

`sideEffectsCache: true`, `sideEffectsCacheReadonly`,
`remoteSideEffectsCache`, and its `organization` field all keep working.
Where a field is set under both spellings the one above wins; where it
is set under only one, it is kept.

Two behaviors change, both bringing this CLI in line with what the Rust
one already did: `sideEffectsCacheReadonly: true` now blocks writing to
the cache, and setting it alongside `sideEffectsCache: false` gives a
read-only view rather than switching the cache off entirely. A cache can
also be declared write-only now, to populate one the run does not read.

- Workspace task orchestration
([pnpm/rfcs#23](https://redirect.github.com/pnpm/rfcs/pull/23)). `pnpm
-r run` and `pnpm -r exec` now schedule per task instead of in
topological chunks: a task starts as soon as the tasks it depends on
have finished, so a project no longer waits for unrelated projects that
happen to share its chunk.

A new `tasks` section in `pnpm-workspace.yaml` declares what a task
depends on, using the `^` convention:

  ```yaml
  tasks:
    build:
      dependsOn: ['^build']
    test:
      dependsOn: ['build']
    lint: {}
  ```

`^name` means the named task in each of the project's workspace
dependencies; a bare `name` means the task in the same project; an entry
with no `dependsOn` declares an empty dependency list. A task with no
entry behaves as `dependsOn: ['^<its own name>']`, which is exactly what
the previous chunked ordering implied — an unconfigured workspace gets
the scheduler improvement and nothing else changes meaning. A project
without the script is reported skipped and passes its edges through to
its own dependencies, so a scriptless package does not sever a chain.

  Also part of this change:

- A dependency cycle among the tasks of a run is now an error naming the
participating tasks (`ERR_PNPM_TASK_CYCLE`) instead of silently running
in an arbitrary order. Setting `ignoreWorkspaceCycles: true` downgrades
the error to a warning: the cycle's tasks run in an arbitrary order
relative to each other.
- `--resume-from` now skips exactly the transitive dependencies of the
anchor package; work unrelated to the anchor still runs.
- Under `--no-bail`, tasks whose dependencies failed are reported as
skipped, not failed, and do not add to the exit code.
- With `--bail` (the default), the first failure still ends the run at
once and nothing new is dispatched — including scripts already queued
behind the concurrency limit.
- `pnpm -r run --dry-run <script>` prints the task graph that would
execute without running anything (including skipping the
`verifyDepsBeforeRun` check); `--json` emits the tasks and their
resolved dependency edges.
- Output is inherited rather than piped only when at most one script can
ever be in flight (`--workspace-concurrency=1`, or the graph forces the
scripts to run one after another).

#### Patch Changes

- An `_auth` entry in the global config file no longer decides which
registry packages come from when something else says. A `registry` or
`registries` declared in `pnpm-workspace.yaml` or the global config now
wins over the route inferred from a stored credential, which still
applies where nothing else declares one. The `pnpm_config__auth`
environment variable is unchanged: it stays the way to point a CI runner
at a mandated proxy, and still overrides what a repository declares.

- Prevent installs through a symlinked `node_modules` directory from
rewriting the target checkout
[pnpm/pnpm#14286](https://redirect.github.com/pnpm/pnpm/issues/14286).

- Treat empty scripts selected by a regular expression as missing before
running dependent tasks.

- The options type of the `fetch` command now declares `allowBuilds`, a
setting its handler already forwarded to the installer. Type-level only
— what `pnpm fetch` does is unchanged.

- Filter hidden scripts matched by a regular expression during recursive
runs when a visible script also matches.

- Fixed automatically switched pnpm versions forcing all descendant pnpm
processes to use the same version
[pnpm/pnpm#14309](https://redirect.github.com/pnpm/pnpm/issues/14309).

- Fixed `ERR_PNPM_UNUSED_PATCH` validation during incremental installs
[pnpm/pnpm#13692](https://redirect.github.com/pnpm/pnpm/issues/13692).

- Fixed `pnpm deploy --prod` failing when an excluded dev dependency was
also declared as an optional peer dependency
[pnpm/pnpm#14302](https://redirect.github.com/pnpm/pnpm/issues/14302).

- `pnpm update -g` no longer downgrades a global package. `--latest`
resolves the `latest` dist-tag, which can point at an older release than
the one installed — after `pnpm add -g <pkg>@next`, for instance
[#&#8203;14270](https://redirect.github.com/pnpm/pnpm/issues/14270).

`pnpm update -g` also no longer changes the pnpm version. pnpm's own
global install belongs to `pnpm self-update`
[#&#8203;14270](https://redirect.github.com/pnpm/pnpm/issues/14270).

- Copying a built package to its other hoisted locations no longer
replaces the destination directory. With `nodeLinker: hoisted`, that
replacement deleted the dependencies nested inside the destination's
`node_modules`, and made concurrent copies of the same build chunk fail
with `ERR_PNPM_ENOENT: no such file or directory, rename
'.../node_modules/_tmp_...'`
[#&#8203;12880](https://redirect.github.com/pnpm/pnpm/issues/12880).

- `pnpm update` no longer replaces the specifier a project declares for
a dependency that is also listed in `overrides`. A `catalog:` reference
stays a `catalog:` reference, and a declared range stays as written,
instead of being rewritten to the version the override resolved to
[#&#8203;12115](https://redirect.github.com/pnpm/pnpm/issues/12115).

- `pnpm update` no longer moves the range a project declares for a
dependency that `overrides` also lists, even when the override repeats
that range verbatim. Previously the updated `package.json` disagreed
with the lockfile, so the next `pnpm install --frozen-lockfile` failed
with a specifier mismatch
[#&#8203;14224](https://redirect.github.com/pnpm/pnpm/issues/14224).

- Make `pnpm add --lockfile-only` skip dependency linking
[pnpm/pnpm#14286](https://redirect.github.com/pnpm/pnpm/issues/14286).

- `--production` is accepted again as an alias of `--prod` on `install`,
`fetch`, `prune`, `update`, `list`, `why`, and `sbom`, and the install
that `verifyDepsBeforeRun` reproduces is now spelled with `--prod`.
`pnpm run` no longer aborts with "unexpected argument '--production'
found" after a production-only install
[#&#8203;14147](https://redirect.github.com/pnpm/pnpm/issues/14147).

- The progress output no longer overwrites the lines above it once it
grows taller than the terminal window
[#&#8203;14270](https://redirect.github.com/pnpm/pnpm/issues/14270).

- Restoring a dependency's build from the remote side-effects cache no
longer downloads files the store already holds.

- Forward `patchedDependencies` hashes and `packageExtensions` to pnpr
so server-side resolution preserves patches and package extensions in
the lockfile and installed packages.

- Published the workspace task graph and scheduler as
`@pnpm/workspace.task-scheduler` so other workspace commands can use the
same dependency-aware scheduling as recursive run and exec.

- The environment variables for the remote side-effects cache are named
for the setting they configure: `PNPM_SIDE_EFFECTS_CACHE_REMOTE_KEY_ID`,
`..._BUILDER_ID`, `..._IMAGE_DIGEST`, `..._ARCHITECTURE_BASELINE`,
`..._PRIVATE_KEY`, `..._BUILD_ENV`, `..._TRUSTED_KEYS` and
`..._PUBLISH`. The `PNPM_REMOTE_SIDE_EFFECTS_CACHE_*` names keep
working, and the new one wins when both are set.

- A `devEngines.packageManager` range pin on pnpm is now recorded in
`pnpm-lock.yaml`'s `packageManagerDependencies` when the running pnpm
already satisfies it, using the running version and keeping the range as
the recorded specifier. Previously only an exact pin — or a range
resolved on the way through a version switch — reached the lockfile, so
a range pin written by hand (or by any tool other than `pnpm add` /
`pnpm self-update`) left the project without the shared resolution the
pin exists to provide.

- Fixed recursive `run` cleanup on Windows when a lifecycle script fails
while another script's process tree is still running.

- The update notification now suggests `pnpm self-update` when
`PNPM_HOME` manages the pnpm in use, and the [standalone install
script](https://pnpm.io/installation) otherwise — under Corepack, or
when another package manager installed pnpm. `pnpm self-update` under
Corepack names the standalone install script too.

- Enforce `allowBuilds` when a prepared git dependency is reused from
the shared store, and use the lockfile's canonical git resolution ID in
approval suggestions.

- Topologically sorting workspace projects now runs in linear time,
fixing installs and lockfile updates that stalled for seconds on
workspaces with thousands of projects forming deep dependency chains
[#&#8203;14149](https://redirect.github.com/pnpm/pnpm/issues/14149),
[#&#8203;14151](https://redirect.github.com/pnpm/pnpm/issues/14151).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://notion.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/notion.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/notion_light.svg" />
<img src="https://pnpm.io/img/users/notion.svg" width="80" alt="Notion"
/>
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://latitude.so/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/latitude.svg" width="160"
alt="Latitude"></a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.24.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.24.0):
pnpm 11.24

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.23.0...v11.24.0)

##### Minor Changes

- Added global build approvals
[pnpm/pnpm#14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

##### Patch Changes

- Fixed pnpm v11 incorrectly reporting `confirmModulesPurge` as
unrecognized when set in `pnpm-workspace.yaml`. The Rust CLI now
identifies the unsupported option as a pnpm v11 setting instead of
suggesting an unrelated setting.

- `pnpm install --frozen-lockfile` no longer fails with
`ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE` when the pinned pnpm
version recorded in `pnpm-lock.yaml` has to be re-resolved before it can
be installed. It runs the pnpm version the lockfile pins and leaves the
lockfile unchanged
[#&#8203;14124](https://redirect.github.com/pnpm/pnpm/issues/14124).

- Under `nodeLinker: hoisted`, peer-resolution variants of an injected
directory dependency (a `file:` snapshot) are materialized as separate
copies again instead of collapsing onto the first-seen variant. Each
copy keeps its own peer-resolved dependency set, so a project pinning
one peer version no longer resolves another project's variant — Bit root
components with conflicting peers across injected copies rely on this.

- Fixed `pnpm install --merge-git-branch-lockfiles --frozen-lockfile`
failing with `ERR_PNPM_OUTDATED_LOCKFILE` when a branch lockfile
predates the removal of a dependency, or its move to another dependency
group
[#&#8203;13966](https://redirect.github.com/pnpm/pnpm/issues/13966). A
dependency that no project declares anymore is no longer reinstated by
the merge, and the packages it was the only path to are dropped with it.

- Batch workspace publishing accepts a shared scope-specific credential,
rejects mismatched credentials for a registry before publishing, and
runs the `publish` and `postpublish` scripts after each completed
registry group
[pnpm/pnpm#14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

- The Rust CLI now honors five settings it recognized but ignored:
`updateNotifier`, `legacyDirFiltering`, `initAuthorName` /
`initAuthorEmail` / `initAuthorUrl`, `initLicense`, and `initVersion`.
`pnpm install` and `pnpm add` check once a day for a newer pnpm and
print how to get it (turn it off with `updateNotifier: false`); a
`{<dir>}` filter selector can go back to matching the subtree below the
directory with `legacyDirFiltering: true`; and `pnpm init` writes the
configured author, license, and version into the `package.json` it
scaffolds. `PNPM_CONFIG_INIT_VERSION` is now read as well.

`maxsockets`, npm's spelling of `maxSockets`, is no longer ignored: both
spellings are read from `pnpm-workspace.yaml`, the global config file,
the environment, and the command line, in that increasing order of
precedence — a value passed on the command line now wins even when the
two sides spelled the setting differently.

A `lastUpdateCheck` timestamp dated in the future — after a clock
change, a restored snapshot, or a hand-edited state file — no longer
silences the update check until that time comes around.

`legacyDirFiltering` no longer reaches the workspace-root selectors pnpm
generates for itself: the `!{<workspace-root>}` exclusion a recursive
`run` / `exec` / `add` / `test` appends, and the `{<workspace-root>}`
inclusion `--workspace-root` appends. Read as subtree matches they named
every project below the root, so a recursive command under the setting
selected nothing at all, and `--workspace-root` pulled in every project
below the root instead of the root alone
[#&#8203;14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

- `pnpm install --frozen-lockfile` no longer fails when `pnpm-lock.yaml`
records the pinned pnpm version alongside an engine package the running
pnpm does not install it from. An entry pinning another version is still
refused, and a plain install rewrites the block
[#&#8203;14124](https://redirect.github.com/pnpm/pnpm/issues/14124).

###
[`v11.23.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.23.0):
pnpm 11.23

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.22.0...v11.23.0)

#### Minor Changes

- `pnpm config get` and `pnpm config list` now show the settings pnpm
acts on under their documented names:

- `registries` shows the registries pnpm resolves from, merged across
every source (`.npmrc`, `pnpm-workspace.yaml`, the global config, CLI
flags), in the shape the setting is written in: keyed by registry URL,
with the default registry declared as the bare `@` scope. Built-in
routes are included — the `@jsr` scope and the `npmjs` and `gh` prefixes
— unless pointed elsewhere. Previously `pnpm config get registries`
printed `undefined`.
- `update` and `audit` show the effective sections, whichever spelling
set them. The deprecated internal spellings (`updateConfig`,
`auditConfig`, `auditLevel`) are no longer listed.
- `catalogs` shows the complete resolved catalog set — the singular
`catalog` block is its `default` entry — whichever spelling declared it.
- The `registry` and `@scope:registry` entries show the merged routes
rather than raw `.npmrc` values, so they always agree with the
`registries` view.

- Settings that no supported pnpm version recognizes get their own
warning. A key in the global config file that this version of pnpm does
not read is no longer reported with advice to move it to a project-level
`pnpm-workspace.yaml` (where it would be ignored too); the warning now
says the setting is not recognized by this version of pnpm, names the
pnpm version that does read it when there is one (for example,
`globalShims` is a pnpm v12 setting), and suggests the closest real
setting name when the key looks like a typo. Unrecognized and
non-camelCase keys in a project's `pnpm-workspace.yaml`, previously
ignored silently, are now reported the same way. `pnpm config get <key>`
and `pnpm get <key>` no longer print config-load warnings, so a script
capturing the value gets the value alone.

- The `importPackage` pnpmfile hook is deprecated. pnpm now prints a
warning when a pnpmfile defines it, and the hook will be removed in the
next major version. It also opts the installation out of the parallel
package importer, making installation slower. If you rely on this hook,
comment on
[#&#8203;14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

- `node_modules/.modules.yaml` no longer records the registries an
install resolved from, and the recorded copy is dropped from the file on
the first install that rewrites it.

It dated from the lockfile format that spelled a dependency's path
relative to its registry, where reading an installed tree meant knowing
the registries it was installed with. Dependency paths have not carried
a registry for several major versions, and the recorded copy outlived
its use: `pnpm list`, `pnpm why`, and single-project installs preferred
it over the project's own configuration, so a project whose registry had
changed since its last install was still read through the old one.

They now use the configured registries, like every other command already
did.

- When `enableGlobalVirtualStore` is on, every process pnpm spawns for
the project (`pnpm run`, `pnpm exec`, lifecycle scripts) now receives a
`NODE_PATH` pointing at the project's hoisted `node_modules`, plus a
`NODE_OPTIONS` `--import` flag that registers a resolve hook restoring
`NODE_PATH` lookups for ESM imports. Dependencies that import undeclared
("phantom") packages keep resolving under the global virtual store — for
both CommonJS and ESM — without installing the
`@pnpm/plugin-esm-node-path` config dependency
[pnpm/pnpm#9618](https://redirect.github.com/pnpm/pnpm/issues/9618).
Tools run by `pnpm dlx` resolve such dependencies too: the JS CLI passes
them the same environment, while the Rust CLI's dlx cache is
self-contained, so its layout already exposes them.

- A registry can now declare that its abbreviated metadata carries the
`time` field, so `resolutionMode: time-based` reads the full metadata
document only from the registries that need it:

  ```yaml
  resolutionMode: time-based
  registries:
    https://npm.internal.example/:
      supportsTimeField: true
  ```

`registry.npmjs.org` omits `time` from abbreviated metadata, so a
time-based resolution has to fall back to the much larger full document.
That fallback used to be all-or-nothing: `registrySupportsTimeField`
answered for every registry at once, so a project resolving from both
the public registry and a Verdaccio instance either paid for full
metadata everywhere or claimed a `time` field npmjs does not serve. The
answer is now per registry, and `registrySupportsTimeField` remains the
answer for every registry that does not declare one.

The declaration is also sent to a pnpr server, which applies it to the
resolution it runs on the client's behalf.

- A pnpr resolve request now carries the client's registries the way the
`registries` setting declares them — keyed by URL, with the scopes
routed to each, the bare-specifier prefix each answers to, and each
one's `serverType` — in place of the prefix map it used to send.

The server routes them through the same inversion the config reader
runs, so a pnpr-served install resolves a scoped dependency from the
registry that scope is routed to, which it previously could not: only
the default registry and the prefix-addressed ones reached the server. A
declared `serverType` reaches it too, so the tarball URLs pnpr omits
from the lockfile match the ones the client reconstructs.

Built-in scope routes the project has not pointed elsewhere are not
declared, so a pnpr server's allowlist is not asked about `npm.jsr.io`
on requests that resolve no JSR package.

A registry a request only declares is no longer refused up front for
being off the server's allowlist — a client describes its whole
configuration, including scopes a given resolve never reaches, so a
stray `@scope:registry` in a developer's `~/.npmrc` no longer fails
every install against a pnpr server that does not serve it. The boundary
moves to the fetch itself: an origin the resolve does reach is refused
before the request leaves the server, with the same message.

This changes the resolve and verify-lockfile request bodies. A pnpr
server and its clients have to be on matching versions; the protocol is
still experimental and unversioned.

- The `registries` setting now declares a registry once, keyed by its
URL, with everything about that registry in the entry: how it lays out
tarball URLs, the scopes routed to it, and the bare-specifier prefix it
answers to.

  ```yaml
  registries:
    https://artifactory.example.com/artifactory/api/npm/npm-virtual/:
      serverType: artifactory
      scopes: ['@acme', '@acme-internal']
      prefix: work
  ```

- **`serverType`** tells pnpm how the registry lays out its tarball
URLs, which decides whether a URL can be omitted from `pnpm-lock.yaml`:
- **undeclared** (the default) — strict. Only the exact canonical URL is
treated as reconstructible.
- **`npm`** — the registry behaves like `registry.npmjs.org`, which also
serves a scoped package from its percent-encoded path. Declare this for
a faithful mirror or caching proxy of the public registry so its tarball
URLs can be omitted too.
- **`artifactory`** — JFrog Artifactory repeats the scope in a scoped
package's tarball filename (`@acme/widget/-/@acme/widget-1.0.0.tgz`)
where the npm registry strips it (`@acme/widget/-/widget-1.0.0.tgz`).
Declaring it lets pnpm rebuild that URL, so it is omitted from
`pnpm-lock.yaml` instead of being written out for every scoped package
[pnpm/get-npm-tarball-url#16](https://redirect.github.com/pnpm/get-npm-tarball-url/issues/16).
- **`scopes`** lists the `@`-prefixed scopes that resolve from this
registry. A bare `'@'` is the scope-less default registry, the one the
`registry` setting names.
- **`prefix`** is the alias a dependency addresses this registry by, as
in `"foo": "work:^1.0.0"`.

The layout is never inferred from the registry URL, so nothing changes
unless you declare it; `registry.npmjs.org` continues to behave as `npm`
without being declared. Because the lockfile depends on `serverType`, it
is read from `pnpm-workspace.yaml` only — a `serverType` in the global
`config.yaml` is ignored, so one developer's machine cannot shape a
lockfile their collaborators read back with a different layout.
Credentials are rejected in this setting, in a key as well as in a
field, and still belong in `.npmrc`. An entry that routes nothing to
itself and matches no configured registry is reported as a warning
rather than silently ignored.

##### Migrating

The older `registries` shape, a map of `<scope>: <url>` strings, still
works and needs no change:

```yaml
registries:
  '@acme': https://npm.acme.example/
```

`namedRegistries` is deprecated in favor of the `prefix` field, and is
still read for prefixes `registries` does not declare.

`toLockfileResolution` and `isCanonicalRegistryTarballUrl` now take
their registry and layout as an options object rather than positional
arguments, so `@pnpm/lockfile.utils` and `@pnpm/resolving.tarball-url`
get a major bump.

- An install that had to re-hash store files to verify them now reports
it. If that cost more than a second, it says how long — `The integrity
of N files was checked in 2.5s.` — and if it was quick but covered more
than a thousand files, it names the cause instead: their timestamps
changed since the store recorded them, which a backup tool, an antivirus
scan or a copied store can do.

- Added `virtualStoreType`, which names where the virtual store lives —
one store per machine, or one per project:

  ```yaml
  virtualStoreType: global   # or: project
  ```

It is the canonical spelling of `enableGlobalVirtualStore`, which keeps
working. When a project sets both, `virtualStoreType` wins. It can also
be set through `PNPM_CONFIG_VIRTUAL_STORE_TYPE` and read back with `pnpm
config get virtualStoreType`. The default is unchanged — `project`, so
the shared store stays opt-in.

The setting is independent of `nodeLinker`. `isolated` and `pnp` both
work with either store type, and `hoisted` writes no virtual store at
all, so it is unaffected.

#### Patch Changes

- `pnpm add --allow-build` now adds to the `allowBuilds` entries already
in `pnpm-workspace.yaml` instead of replacing them
[#&#8203;13872](https://redirect.github.com/pnpm/pnpm/issues/13872).

- Kept pending build approvals available after removing an unrelated
dependency.

- `pnpm approve-builds` now removes `onlyBuiltDependencies`,
`onlyBuiltDependenciesFile`, `neverBuiltDependencies`, and
`ignoredBuiltDependencies` from `pnpm-workspace.yaml` when it writes
`allowBuilds`. Those settings were replaced by `allowBuilds` in pnpm 11
and silently ignored since, so a workspace migrated from pnpm 10 kept
them around looking active.

- `pnpm audit` no longer reports a patched version that was never
published or is deprecated. The inferred patched range (e.g. `>=4.17.24`
from `<=4.17.23`) is now checked against the registry packument, and the
report is corrected to the lowest non-deprecated published version that
satisfies it (e.g. `>=4.18.1` when `4.17.24` does not exist and `4.18.0`
is deprecated). When no published version satisfies the range, the
report shows `Patched versions: None`. This also prevents `pnpm audit
--fix` from adding overrides or `minimumReleaseAgeExclude` entries for
patches that do not exist
[#&#8203;13824](https://redirect.github.com/pnpm/pnpm/issues/13824).

`pnpm audit --fix` and `pnpm audit --fix update` no longer add a
`minimumReleaseAgeExclude` entry when the registry packument shows that
the minimum patched version was never published. Previously such entries
were written for versions that do not exist, which would have let a
later publish of that version bypass the `minimumReleaseAge` gate
[#&#8203;11563](https://redirect.github.com/pnpm/pnpm/issues/11563).

The `--json` output of `pnpm audit` now returns `patched_versions: null`
for advisories whose inferred patch is not available (never published,
skipped, yanked, or deprecated), making it easier for tooling to
distinguish "no fix available" from "fix available at version X".

- Fixed `pnpm patch-commit` in project and edit paths containing
non-ASCII characters.

- The package and bump pickers of `pnpm change` now size their page from
the terminal height instead of always showing 7 rows. They fall back to
7 rows when the terminal height is unknown
[`pnpm/pnpm#13815`](https://redirect.github.com/pnpm/pnpm/issues/13815).

- Canceling a `pnpm change` prompt with Ctrl-c no longer prints a stack
trace. It reports `Change canceled` and exits with a success status,
like the other interactive commands
[#&#8203;13814](https://redirect.github.com/pnpm/pnpm/issues/13814).

- Re-fetch full registry metadata when `minimumReleaseAge` is enabled
and an abbreviated packument's `time` map omits timestamps for some
versions. This prevents mature versions from being filtered out and
resolution from falling back to the lowest matching version
[pnpm/pnpm#13741](https://redirect.github.com/pnpm/pnpm/issues/13741).

- A config dependency carrying an inline integrity (the
`<version>+<integrity>` form, or the object form without a `tarball`)
now takes its tarball URL from the registry's packument instead of
deriving it from the registry URL, so migrating one costs an extra
metadata request. On a registry that serves tarballs from a path pnpm
cannot derive, GitLab's group endpoint for one, installing such a config
dependency failed with a 404 while the same package installed fine as a
regular dependency
[#&#8203;13765](https://redirect.github.com/pnpm/pnpm/issues/13765).

- Fixed `PNPM_CONFIG_NODE_VERSION` being ignored when setting the
Node.js version used for compatibility checks.

- A custom fetcher can no longer replace the archive integrity that
`pnpm-lock.yaml` pins: the locked value is restored after a `canFetch`
or `fetch` hook rewrites the resolution, and delegating a locked archive
to a directory or git source now fails instead of installing unverified
content.

The Rust CLI now also loads the pnpmfiles named by the `pnpmfile`
setting (a single path or an ordered list), and hands custom fetchers
native `localTarball` and `remoteTarball` callbacks — including on a
fresh install that has to compute a missing tarball integrity, which is
then reused by later offline installs. File maps a fetcher returns are
accepted only when they match what those native callbacks extracted.

- Fixed an issue where running `pnpm dedupe --check` in projects with
`nodeLinker: hoisted` would cause dependencies to be moved out of
`node_modules` into `node_modules/.ignored`.

- `pnpm deploy --prod` and `pnpm deploy --no-optional` no longer list
the excluded dependency groups in the deployed `package.json` and
`pnpm-lock.yaml`. The deployed lockfile referenced packages that the
deploy left out of its graph, so installing in the deploy directory
afterwards created dangling symlinks
[#&#8203;13623](https://redirect.github.com/pnpm/pnpm/issues/13623).

- Don't treat files like `license16.json` as a package license when
deciding if the workspace LICENSE file should be included in the packed
package.

- `pnpm exec --recursive --no-reporter-hide-prefix` no longer prints a
blank prefixed line after each chunk of a command's output, and no
longer splits a line in two when it straddles a chunk boundary.

- Fixed `404` errors when installing from a registry that serves scoped
packages only from a percent-encoded path, such as GitHub Enterprise
Server. Outside `registry.npmjs.org`, a tarball URL that encodes the
scope separator as `%2f` or `%2F` is no longer mistaken for one that
pnpm can rebuild from the package name, version, and registry, so it is
kept in `pnpm-lock.yaml` and requested verbatim on the next install
[#&#8203;13534](https://redirect.github.com/pnpm/pnpm/issues/13534).

- Fixed `trustPolicyExclude` and `minimumReleaseAgeExclude` being
ignored when set to a single string instead of a list. The value was
read one character at a time, so the exclusion never matched the package
it named — and a `*` anywhere in it matched every package, silently
switching the policy off.

- `pnpm init` now pins the exact pnpm version instead of a `^` range,
and records it in the `packageManager` field alongside
`devEngines.packageManager`. Corepack reads only `packageManager` and
accepts nothing but an exact version, so it rejected the generated
`package.json` with "expected a semver version"
[pnpm/pnpm#13969](https://redirect.github.com/pnpm/pnpm/issues/13969). A
package created inside an existing workspace is still left unpinned — it
follows the pin at the workspace root — and `--no-init-package-manager`
still scaffolds a manifest without any pin. In pnpm 12, `pnpm init` also
honors `initType` and its `--init-type` flag, so the manifest it writes
is the same one pnpm 11 writes.

- Fixed an issue where package overrides were written into the metadata
cache, causing removed overrides to keep applying on subsequent installs
[pnpm/pnpm#13918](https://redirect.github.com/pnpm/pnpm/issues/13918).

- On Windows, upgrading pnpm no longer leaves a stale `pnpm.ps1` behind.
PowerShell resolves `pnpm.ps1` ahead of `pnpm.cmd`, so a shim written by
an older installation kept running the previous version. Linking the
pnpm CLI's bins now deletes it
[#&#8203;13919](https://redirect.github.com/pnpm/pnpm/issues/13919).

- Fixed an inconsistency where `minimumReleaseAgeExclude` (and
`trustPolicyExclude`) wildcard/bare-name rules behaved differently in
the evaluator and normalizer. A bare rule now consistently evaluates as
matching every version, preventing unexpected behavior and silent
widening of version policy exemptions when pnpm rewrites the workspace
manifest
[pnpm/pnpm#13725](https://redirect.github.com/pnpm/pnpm/issues/13725).

- A frozen install no longer rewrites the `packageManagerDependencies`
block of `pnpm-lock.yaml`. When the pnpm version pinned by
`devEngines.packageManager` (or by `packageManager`) is missing from the
lockfile or no longer matches it, `--frozen-lockfile` now fails with
`ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE` instead of resolving
the version and saving it, so a manifest whose pin was bumped without
regenerating the lockfile can no longer pass CI
[#&#8203;14009](https://redirect.github.com/pnpm/pnpm/issues/14009).

- A git dependency installed over HTTPS from a hosted repository now
keeps its branch, tag, or version range in the specifier recorded in
`package.json`. It was written back without one, so the next `pnpm
update` moved the dependency to the repository's default branch
[#&#8203;13999](https://redirect.github.com/pnpm/pnpm/issues/13999).

- Fixed `pnpm update --global --latest` failing with a 404 error when a
globally installed package was not added from the registry by name.
Packages installed from a local path (`link:`/`file:`), a git
repository, a tarball URL, an `npm:` alias, or a named registry now keep
their spec during a global update instead of being looked up by name in
the default registry. See
[#&#8203;12854](https://redirect.github.com/pnpm/pnpm/issues/12854).

- Fix recursive `pnpm update <name>@<version>` so an exact pinned update
stays scoped to the requested version line: copies of the same package
on another major line — or, for a `0.x` request, another minor line —
keep their locked resolution instead of being re-resolved along with the
target.

- Under `nodeLinker: hoisted`, a dependency declared against a
peer-resolution variant of a package version is no longer dropped from
the installed layout. All variants of a version share one hoisted copy,
and edges pointing at any of them now resolve to it, so the depending
project keeps the package in its `.package-map.json` and the depending
package keeps it in its `node_modules/.bin`.

- Fixed `pnpm install --merge-git-branch-lockfiles` deleting the
per-branch lockfiles when the `lockfile` setting is `false`. Such an
install never reads them, so it has nothing to merge them into and now
leaves them alone.

- Fixed `pnpm install` sometimes not exiting after printing `Done in Xs`
[#&#8203;12297](https://redirect.github.com/pnpm/pnpm/issues/12297).

- Fixed pnpm failing to read `.modules.yaml` files containing long
dependency paths
[#&#8203;13875](https://redirect.github.com/pnpm/pnpm/issues/13875). The
manifest is now parsed as JSON (the format pnpm writes it in), falling
back to the YAML parser only for manifests written by old pnpm versions.

- With `preferSymlinkedExecutables`, `NODE_PATH` again points at the
virtual store of the workspace root when pnpm is run from inside a
workspace package, so scripts can resolve dependencies that live only in
the hoisted store
[#&#8203;13912](https://redirect.github.com/pnpm/pnpm/issues/13912).

- Reduced registry metadata requests during dependency resolution by
reusing cached metadata when lockfile preferences prove that no uncached
version can win
[pnpm/pnpm#13976](https://redirect.github.com/pnpm/pnpm/issues/13976).

- `pnpm pkg get` and `pnpm pkg set` now accept hyphens inside a
dot-notation property path, so `pnpm pkg get
dependencies.some-package-name` reads the key instead of failing with
`ERR_PNPM_UNEXPECTED_TOKEN_IN_PROPERTY_PATH`. The bracketed and quoted
forms already worked and are unchanged.

- A resolve request now carries the client's `resolutionMode`, so an
install delegated to a pnpr server picks versions the way the client
would. `time-based` and `lowest-direct` reached the server as nothing at
all, leaving it on its `highest` default: the returned lockfile pinned
the highest satisfying version of every dependency, and the setting
appeared to be ignored.

This adds a field to the resolve request body. A server older than its
client ignores it and keeps resolving `highest`; the protocol is still
experimental and unversioned.

- Fixed `pnpm` installs using pnpr to honor the client's
`autoInstallPeers`, `dedupePeers`, and `excludeLinksFromLockfile`
settings
[pnpm/pnpm#13389](https://redirect.github.com/pnpm/pnpm/issues/13389).

- `pnpm remove` now prunes undecided entries (`"set this to true or
false"`) from `allowBuilds` in `pnpm-workspace.yaml` when
`sharedWorkspaceLockfile: true` and the corresponding packages are
removed
[pnpm/pnpm#13892](https://redirect.github.com/pnpm/pnpm/issues/13892).

- Fixed workspace discovery for `pnpm-workspace.yaml` files without a
`packages` field so commands only consider the workspace root instead of
recursively scanning nested projects
[#&#8203;14047](https://redirect.github.com/pnpm/pnpm/issues/14047).

- A runtime installed through `devEngines.runtime` now matches the host
when `supportedArchitectures` lists several platforms. Listing `os:
[darwin, linux]` and `cpu: [x64, arm64]` used to install the runtime
built for the first entry of each list, so a machine running Linux on
arm64 got a macOS x64 Node.js that could not execute
[#&#8203;13898](https://redirect.github.com/pnpm/pnpm/issues/13898).

- `pnpm sbom` now fails with `ERR_PNPM_SBOM_MISSING_IMPORTERS` when
`pnpm-lock.yaml` has no entry for a selected project, instead of writing
an SBOM that under-reports that project's dependencies. Previously this
crashed with `Cannot read properties of undefined (reading
'devDependencies')`.

- `pnpm self-update` now rewrites a simple
`devEngines.packageManager.version` range (`^`/`~`) to the newly
installed version, keeping the operator — matching how `pnpm update` and
`pnpm runtime set` rewrite ranges. Complex ranges such as `>=8.0.0` that
the new version satisfies are still left unchanged
[#&#8203;13935](https://redirect.github.com/pnpm/pnpm/issues/13935).

- `pnpm self-update <tag>` no longer downgrades when the dist-tag points
at the pnpm version already running and that version is younger than
`minimumReleaseAge`. The maturity cutoff moved the tag back to the
previous mature release, so `pnpm self-update next-12` on v12.0.0-rc.4
switched to v12.0.0-rc.3.

- `pnpm set-script` now updates `package.json` instead of failing with
`ERR_PNPM_NOT_IMPLEMENTED`
[`pnpm/pnpm#13956`](https://redirect.github.com/pnpm/pnpm/issues/13956).

- `pnpm update` now preserves the existing range operator when updating
a prerelease dependency. See
[#&#8203;7002](https://redirect.github.com/pnpm/pnpm/issues/7002).

- Installs are faster in workspaces that declare inter-workspace
dependencies with plain ranges (`"*"`, `"^1.2.3"`) rather than the
`workspace:` protocol. With `preferWorkspacePackages` enabled, linking
such a dependency no longer makes a registry request that cannot change
the outcome — and workspace packages that were never published no longer
cost a 404 on every install.

- Added `fetchWarnTimeoutMs` and `fetchMinSpeedKiBps` to the Rust pnpm
CLI and its N-API bindings. Slow registry metadata requests and tarball
downloads now emit pnpm-compatible warnings without exposing URL
credentials, query parameters, fragments, or control characters
[pnpm/pnpm#12042](https://redirect.github.com/pnpm/pnpm/issues/12042).

- An override change is now absorbed by the fast lockfile update even
when another, unchanged override uses the `catalog:` protocol.
Previously any `catalog:`-valued override forced a full re-resolution
whenever the override list changed, which could move unrelated packages
in the lockfile (for example after `pnpm audit --fix` added an
override).

- Packed workspace package manifests now preserve dependency order,
making repeated `pnpm pack` output deterministic
[#&#8203;10167](https://redirect.github.com/pnpm/pnpm/issues/10167).

- `pnpm update <name>@<version>` now fails with
`ERR_PNPM_UPDATE_VERSION_ON_INDIRECT_DEP` when the package is not a
direct dependency of any selected project, instead of quietly updating
it to whatever a fresh install would resolve. There is nowhere to record
the version in that case, so the request cannot be honored, and the
error points at the `overrides` entry that does pin a transitive
dependency. Ranges and tags are unaffected, and a package that any
selected project declares directly still takes its version as before.

- `trustPolicy: no-downgrade` no longer aborts the install with
`ERR_PNPM_MISSING_TIME` on registries that serve no per-version `time`
field when `minimumReleaseAgeIgnoreMissingTime` is set. The trust check
reads the same publish dates the `minimumReleaseAge` check does, so it
now honors the same opt-in and skips the affected package with a warning
[#&#8203;12446](https://redirect.github.com/pnpm/pnpm/issues/12446).

`minimumReleaseAgeIgnoreMissingTime` no longer lets a lockfile entry the
registry does not list pass the `minimumReleaseAge` check during
lockfile verification. The opt-in covers a registry that cannot date its
releases; a packument that does date every version it lists is saying it
never published this one, which stays a hard failure.

The missing-`time` warning now names the check it is reporting on, so a
package whose `minimumReleaseAge` and `trustPolicy` checks are both
skipped warns about both instead of only the first.

- `pnpm update <pkg>@<version>` now updates only the selected packages
and leaves unrelated dependencies unchanged. A selector that renames the
package it installs — `pnpm update <alias>@npm:<pkg>@<version>` or the
`jsr:` equivalent — now targets the package the alias installs rather
than the alias.

- Fixed `verifyDepsBeforeRun` being ignored when set to `install`,
`warn`, `error`, or `prompt` through the
`PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN` environment variable or the
`--config.verify-deps-before-run` flag
[#&#8203;13816](https://redirect.github.com/pnpm/pnpm/issues/13816).
Only the boolean values were accepted before, so a string value was
silently dropped.

- `pnpm version <bump>` with `--dry-run` no longer edits `package.json`
files. It now only reports the bumps it would make, and skips the
working tree check, the version lifecycle scripts, the commit, and the
tag
[`pnpm/pnpm#13953`](https://redirect.github.com/pnpm/pnpm/issues/13953).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </

> ❗ **Important**
> 
> ✂ PR body was truncated to here.


</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMi42IiwidXBkYXRlZEluVmVyIjoiNDQuOTMuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
> ℹ️ **Note**
> 
> This PR body was truncated due to platform limits.

This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pnpm](https://redirect.github.com/pnpm/pnpm/tree/main/pnpm)
([source](https://redirect.github.com/pnpm/pnpm/tree/HEAD/pnpm/npm/pnpm))
| [`11.21.0` →
`11.27.0`](https://renovatebot.com/diffs/npm/pnpm/11.21.0/11.27.0) |
![age](https://developer.mend.io/api/mc/badges/age/npm/pnpm/11.27.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/pnpm/11.21.0/11.27.0?slim=true)
|
|
[typescript-eslint](https://typescript-eslint.io/packages/typescript-eslint)
([source](https://redirect.github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint))
| [`8.67.0` →
`8.70.0`](https://renovatebot.com/diffs/npm/typescript-eslint/8.67.0/8.70.0)
|
![age](https://developer.mend.io/api/mc/badges/age/npm/typescript-eslint/8.70.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/typescript-eslint/8.67.0/8.70.0?slim=true)
|

---

### Release Notes

<details>
<summary>pnpm/pnpm (pnpm)</summary>

###
[`v11.27.0`](https://redirect.github.com/pnpm/pnpm/compare/v11.26.0...v11.27.0)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.26.0...v11.27.0)

###
[`v11.26.0`](https://redirect.github.com/pnpm/pnpm/compare/v11.25.0...v11.26.0)

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.25.0...v11.26.0)

###
[`v11.25.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.25.0):
pnpm 11.25

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.24.0...v11.25.0)

#### Minor Changes

- Added an opt-in proof of concept that lets installs reuse a
dependency's build output across machines, by publishing and restoring
signed, organization-scoped artifacts through pnpr instead of running
the lifecycle scripts locally.

Configure it with the new `remoteSideEffectsCache` setting. A workspace
names the eligible `organization` and `packages`; everything describing
the act of signing — `publish`, `keyId`, `builderId`, `trustedKeys`,
`privateKey` and the provenance fields — is refused in
`pnpm-workspace.yaml` and read from the global config file or the
environment instead.

- Added macOS and Windows x64 and arm64 support to remote shared build
artifacts
[pnpm/pnpm#13771](https://redirect.github.com/pnpm/pnpm/issues/13771).

- Added the `audit.ignorePrune` setting. When set to `true`, `pnpm audit
--fix` removes ignored GHSA entries that no longer appear in the audit
report.

- Generalized the experimental shared-artifact protocol so candidates
and signed payloads identify a discriminated subject. Dependency side
effects use package and source-integrity subjects, while workspace tasks
use project and task subjects.

This changes shared-artifact request bodies and signed payloads. A pnpr
server and its clients have to be on matching versions.

- `pnpm init` now pins the latest pnpm version, instead of the version
of pnpm that ran the command. A project scaffolded by an outdated pnpm
therefore no longer inherits that staleness through its own
`devEngines.packageManager` / `packageManager` pin
[#&#8203;7490](https://redirect.github.com/pnpm/pnpm/issues/7490).

The version is read from the `latest` tag on the package-manager
registries. When that lookup cannot answer — no network, an unreachable
or slow registry, `offline`, or a `latest` that the `minimumReleaseAge`
/ `trustPolicy` settings reject — `pnpm init` pins the running version
as before, and never fails or hangs on the lookup. A `latest` that is
older than the running pnpm is never pinned either.

- A `scope` set in a project's `pnpm-workspace.yaml` is now ignored,
with a warning naming where to set it instead. `pnpm login` records the
scope as a `@scope:registry` route in the machine-global `auth.ini`,
which outranks `~/.npmrc` in every project — so a repository-committed
file could redirect a scope such as `@acme` for all of a user's other
projects after one routine login. Use `--scope`, the `PNPM_CONFIG_SCOPE`
environment variable, or the global config file instead
[#&#8203;13557](https://redirect.github.com/pnpm/pnpm/issues/13557).

- Verified remote build artifacts are persisted in the shared store with
their signed origin metadata. Later installs reverify the artifact
against current trust, policy, platform, and source before reuse, while
invalid remote variants are quarantined per channel
([pnpm/pnpm#13771](https://redirect.github.com/pnpm/pnpm/issues/13771)).

- Persist completed recursive tasks so `--resume-from` skips exactly the
work that passed during a matching interrupted or failed `pnpm -r run` /
`pnpm -r exec` invocation. When no compatible state exists, pnpm retains
its graph-based resume behavior.

- Allowed `pnpm update --patches` to refresh registry revisions through
a configured pnpr server while retaining locked package versions.

- Added explicit registry revision selection with `<version>+rN` and
`pnpm update --patches` for refreshing revision artifacts without
changing package versions. Registry-backed lockfile policy checks
recognize historical revisions, and pnpr now preserves safe revision
histories from upstream registries.

- Workspace install, rebuild, pack, publish, stage, and lifecycle work
now starts as soon as its dependencies finish instead of waiting for an
unrelated topological group.

- `pnpm stage approve` now approves several staged packages at once. Run
it without a stage id to pick from the staged versions interactively, or
pass a list of stage ids. The whole batch is approved with a single
one-time password, and pnpm asks for a new one only once the registry
stops accepting it. Inside a workspace, the selected packages are
approved in dependency order, and a package whose workspace dependency
could not be approved is skipped instead of being published against a
dependency that never reached the registry.

- Added per-task concurrency limits to workspace task orchestration. Set
`tasks.<name>.concurrency` in `pnpm-workspace.yaml` to limit how many
instances of that task may run across workspace projects at once:

  ```yaml
  tasks:
    build:
      concurrency: 2
  ```

- Added support for registry replacement tarballs using standard
integrity values, explicit revision fields, registry routing from the
`registries` setting, non-redirecting integrity-addressed URLs,
canonical safe-integer revision numbers, and pnpr proxying for immutable
upstream revision artifacts.

- `sideEffectsCache` now declares the whole of how a package's build
output is reused — whether one is restored, whether one is saved, and
the remote tier that shares it between machines:

  ```yaml
  sideEffectsCache:
    read: true
    write: true
    remote:
      org: acme
      packages: ['native-addon']
  ```

`sideEffectsCache: true`, `sideEffectsCacheReadonly`,
`remoteSideEffectsCache`, and its `organization` field all keep working.
Where a field is set under both spellings the one above wins; where it
is set under only one, it is kept.

Two behaviors change, both bringing this CLI in line with what the Rust
one already did: `sideEffectsCacheReadonly: true` now blocks writing to
the cache, and setting it alongside `sideEffectsCache: false` gives a
read-only view rather than switching the cache off entirely. A cache can
also be declared write-only now, to populate one the run does not read.

- Workspace task orchestration
([pnpm/rfcs#23](https://redirect.github.com/pnpm/rfcs/pull/23)). `pnpm
-r run` and `pnpm -r exec` now schedule per task instead of in
topological chunks: a task starts as soon as the tasks it depends on
have finished, so a project no longer waits for unrelated projects that
happen to share its chunk.

A new `tasks` section in `pnpm-workspace.yaml` declares what a task
depends on, using the `^` convention:

  ```yaml
  tasks:
    build:
      dependsOn: ['^build']
    test:
      dependsOn: ['build']
    lint: {}
  ```

`^name` means the named task in each of the project's workspace
dependencies; a bare `name` means the task in the same project; an entry
with no `dependsOn` declares an empty dependency list. A task with no
entry behaves as `dependsOn: ['^<its own name>']`, which is exactly what
the previous chunked ordering implied — an unconfigured workspace gets
the scheduler improvement and nothing else changes meaning. A project
without the script is reported skipped and passes its edges through to
its own dependencies, so a scriptless package does not sever a chain.

  Also part of this change:

- A dependency cycle among the tasks of a run is now an error naming the
participating tasks (`ERR_PNPM_TASK_CYCLE`) instead of silently running
in an arbitrary order. Setting `ignoreWorkspaceCycles: true` downgrades
the error to a warning: the cycle's tasks run in an arbitrary order
relative to each other.
- `--resume-from` now skips exactly the transitive dependencies of the
anchor package; work unrelated to the anchor still runs.
- Under `--no-bail`, tasks whose dependencies failed are reported as
skipped, not failed, and do not add to the exit code.
- With `--bail` (the default), the first failure still ends the run at
once and nothing new is dispatched — including scripts already queued
behind the concurrency limit.
- `pnpm -r run --dry-run <script>` prints the task graph that would
execute without running anything (including skipping the
`verifyDepsBeforeRun` check); `--json` emits the tasks and their
resolved dependency edges.
- Output is inherited rather than piped only when at most one script can
ever be in flight (`--workspace-concurrency=1`, or the graph forces the
scripts to run one after another).

#### Patch Changes

- An `_auth` entry in the global config file no longer decides which
registry packages come from when something else says. A `registry` or
`registries` declared in `pnpm-workspace.yaml` or the global config now
wins over the route inferred from a stored credential, which still
applies where nothing else declares one. The `pnpm_config__auth`
environment variable is unchanged: it stays the way to point a CI runner
at a mandated proxy, and still overrides what a repository declares.

- Prevent installs through a symlinked `node_modules` directory from
rewriting the target checkout
[pnpm/pnpm#14286](https://redirect.github.com/pnpm/pnpm/issues/14286).

- Treat empty scripts selected by a regular expression as missing before
running dependent tasks.

- The options type of the `fetch` command now declares `allowBuilds`, a
setting its handler already forwarded to the installer. Type-level only
— what `pnpm fetch` does is unchanged.

- Filter hidden scripts matched by a regular expression during recursive
runs when a visible script also matches.

- Fixed automatically switched pnpm versions forcing all descendant pnpm
processes to use the same version
[pnpm/pnpm#14309](https://redirect.github.com/pnpm/pnpm/issues/14309).

- Fixed `ERR_PNPM_UNUSED_PATCH` validation during incremental installs
[pnpm/pnpm#13692](https://redirect.github.com/pnpm/pnpm/issues/13692).

- Fixed `pnpm deploy --prod` failing when an excluded dev dependency was
also declared as an optional peer dependency
[pnpm/pnpm#14302](https://redirect.github.com/pnpm/pnpm/issues/14302).

- `pnpm update -g` no longer downgrades a global package. `--latest`
resolves the `latest` dist-tag, which can point at an older release than
the one installed — after `pnpm add -g <pkg>@next`, for instance
[#&#8203;14270](https://redirect.github.com/pnpm/pnpm/issues/14270).

`pnpm update -g` also no longer changes the pnpm version. pnpm's own
global install belongs to `pnpm self-update`
[#&#8203;14270](https://redirect.github.com/pnpm/pnpm/issues/14270).

- Copying a built package to its other hoisted locations no longer
replaces the destination directory. With `nodeLinker: hoisted`, that
replacement deleted the dependencies nested inside the destination's
`node_modules`, and made concurrent copies of the same build chunk fail
with `ERR_PNPM_ENOENT: no such file or directory, rename
'.../node_modules/_tmp_...'`
[#&#8203;12880](https://redirect.github.com/pnpm/pnpm/issues/12880).

- `pnpm update` no longer replaces the specifier a project declares for
a dependency that is also listed in `overrides`. A `catalog:` reference
stays a `catalog:` reference, and a declared range stays as written,
instead of being rewritten to the version the override resolved to
[#&#8203;12115](https://redirect.github.com/pnpm/pnpm/issues/12115).

- `pnpm update` no longer moves the range a project declares for a
dependency that `overrides` also lists, even when the override repeats
that range verbatim. Previously the updated `package.json` disagreed
with the lockfile, so the next `pnpm install --frozen-lockfile` failed
with a specifier mismatch
[#&#8203;14224](https://redirect.github.com/pnpm/pnpm/issues/14224).

- Make `pnpm add --lockfile-only` skip dependency linking
[pnpm/pnpm#14286](https://redirect.github.com/pnpm/pnpm/issues/14286).

- `--production` is accepted again as an alias of `--prod` on `install`,
`fetch`, `prune`, `update`, `list`, `why`, and `sbom`, and the install
that `verifyDepsBeforeRun` reproduces is now spelled with `--prod`.
`pnpm run` no longer aborts with "unexpected argument '--production'
found" after a production-only install
[#&#8203;14147](https://redirect.github.com/pnpm/pnpm/issues/14147).

- The progress output no longer overwrites the lines above it once it
grows taller than the terminal window
[#&#8203;14270](https://redirect.github.com/pnpm/pnpm/issues/14270).

- Restoring a dependency's build from the remote side-effects cache no
longer downloads files the store already holds.

- Forward `patchedDependencies` hashes and `packageExtensions` to pnpr
so server-side resolution preserves patches and package extensions in
the lockfile and installed packages.

- Published the workspace task graph and scheduler as
`@pnpm/workspace.task-scheduler` so other workspace commands can use the
same dependency-aware scheduling as recursive run and exec.

- The environment variables for the remote side-effects cache are named
for the setting they configure: `PNPM_SIDE_EFFECTS_CACHE_REMOTE_KEY_ID`,
`..._BUILDER_ID`, `..._IMAGE_DIGEST`, `..._ARCHITECTURE_BASELINE`,
`..._PRIVATE_KEY`, `..._BUILD_ENV`, `..._TRUSTED_KEYS` and
`..._PUBLISH`. The `PNPM_REMOTE_SIDE_EFFECTS_CACHE_*` names keep
working, and the new one wins when both are set.

- A `devEngines.packageManager` range pin on pnpm is now recorded in
`pnpm-lock.yaml`'s `packageManagerDependencies` when the running pnpm
already satisfies it, using the running version and keeping the range as
the recorded specifier. Previously only an exact pin — or a range
resolved on the way through a version switch — reached the lockfile, so
a range pin written by hand (or by any tool other than `pnpm add` /
`pnpm self-update`) left the project without the shared resolution the
pin exists to provide.

- Fixed recursive `run` cleanup on Windows when a lifecycle script fails
while another script's process tree is still running.

- The update notification now suggests `pnpm self-update` when
`PNPM_HOME` manages the pnpm in use, and the [standalone install
script](https://pnpm.io/installation) otherwise — under Corepack, or
when another package manager installed pnpm. `pnpm self-update` under
Corepack names the standalone install script too.

- Enforce `allowBuilds` when a prepared git dependency is reused from
the shared store, and use the lockfile's canonical git resolution ID in
approval suggestions.

- Topologically sorting workspace projects now runs in linear time,
fixing installs and lockfile updates that stalled for seconds on
workspaces with thousands of projects forming deep dependency chains
[#&#8203;14149](https://redirect.github.com/pnpm/pnpm/issues/14149),
[#&#8203;14151](https://redirect.github.com/pnpm/pnpm/issues/14151).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://notion.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/notion.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/notion_light.svg" />
<img src="https://pnpm.io/img/users/notion.svg" width="80" alt="Notion"
/>
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://coderabbit.ai/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/coderabbit.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/coderabbit_light.svg" />
<img src="https://pnpm.io/img/users/coderabbit.svg" width="220"
alt="CodeRabbit" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a
href="https://stackblitz.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/stackblitz.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/stackblitz_light.svg" />
<img src="https://pnpm.io/img/users/stackblitz.svg" width="190"
alt="Stackblitz" />
          </picture>
        </a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://workleap.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/workleap.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/workleap_light.svg" />
<img src="https://pnpm.io/img/users/workleap.svg" width="190"
alt="Workleap" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://nx.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/nx.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/nx_light.svg" />
<img src="https://pnpm.io/img/users/nx.svg" width="50" alt="Nx" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://latitude.so/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/latitude.svg" width="160"
alt="Latitude"></a>
      </td>
    </tr>
  </tbody>
</table>

<!-- sponsors end -->

###
[`v11.24.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.24.0):
pnpm 11.24

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.23.0...v11.24.0)

##### Minor Changes

- Added global build approvals
[pnpm/pnpm#14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

##### Patch Changes

- Fixed pnpm v11 incorrectly reporting `confirmModulesPurge` as
unrecognized when set in `pnpm-workspace.yaml`. The Rust CLI now
identifies the unsupported option as a pnpm v11 setting instead of
suggesting an unrelated setting.

- `pnpm install --frozen-lockfile` no longer fails with
`ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE` when the pinned pnpm
version recorded in `pnpm-lock.yaml` has to be re-resolved before it can
be installed. It runs the pnpm version the lockfile pins and leaves the
lockfile unchanged
[#&#8203;14124](https://redirect.github.com/pnpm/pnpm/issues/14124).

- Under `nodeLinker: hoisted`, peer-resolution variants of an injected
directory dependency (a `file:` snapshot) are materialized as separate
copies again instead of collapsing onto the first-seen variant. Each
copy keeps its own peer-resolved dependency set, so a project pinning
one peer version no longer resolves another project's variant — Bit root
components with conflicting peers across injected copies rely on this.

- Fixed `pnpm install --merge-git-branch-lockfiles --frozen-lockfile`
failing with `ERR_PNPM_OUTDATED_LOCKFILE` when a branch lockfile
predates the removal of a dependency, or its move to another dependency
group
[#&#8203;13966](https://redirect.github.com/pnpm/pnpm/issues/13966). A
dependency that no project declares anymore is no longer reinstated by
the merge, and the packages it was the only path to are dropped with it.

- Batch workspace publishing accepts a shared scope-specific credential,
rejects mismatched credentials for a registry before publishing, and
runs the `publish` and `postpublish` scripts after each completed
registry group
[pnpm/pnpm#14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

- The Rust CLI now honors five settings it recognized but ignored:
`updateNotifier`, `legacyDirFiltering`, `initAuthorName` /
`initAuthorEmail` / `initAuthorUrl`, `initLicense`, and `initVersion`.
`pnpm install` and `pnpm add` check once a day for a newer pnpm and
print how to get it (turn it off with `updateNotifier: false`); a
`{<dir>}` filter selector can go back to matching the subtree below the
directory with `legacyDirFiltering: true`; and `pnpm init` writes the
configured author, license, and version into the `package.json` it
scaffolds. `PNPM_CONFIG_INIT_VERSION` is now read as well.

`maxsockets`, npm's spelling of `maxSockets`, is no longer ignored: both
spellings are read from `pnpm-workspace.yaml`, the global config file,
the environment, and the command line, in that increasing order of
precedence — a value passed on the command line now wins even when the
two sides spelled the setting differently.

A `lastUpdateCheck` timestamp dated in the future — after a clock
change, a restored snapshot, or a hand-edited state file — no longer
silences the update check until that time comes around.

`legacyDirFiltering` no longer reaches the workspace-root selectors pnpm
generates for itself: the `!{<workspace-root>}` exclusion a recursive
`run` / `exec` / `add` / `test` appends, and the `{<workspace-root>}`
inclusion `--workspace-root` appends. Read as subtree matches they named
every project below the root, so a recursive command under the setting
selected nothing at all, and `--workspace-root` pulled in every project
below the root instead of the root alone
[#&#8203;14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

- `pnpm install --frozen-lockfile` no longer fails when `pnpm-lock.yaml`
records the pinned pnpm version alongside an engine package the running
pnpm does not install it from. An entry pinning another version is still
refused, and a plain install rewrites the block
[#&#8203;14124](https://redirect.github.com/pnpm/pnpm/issues/14124).

###
[`v11.23.0`](https://redirect.github.com/pnpm/pnpm/releases/tag/v11.23.0):
pnpm 11.23

[Compare
Source](https://redirect.github.com/pnpm/pnpm/compare/v11.22.0...v11.23.0)

#### Minor Changes

- `pnpm config get` and `pnpm config list` now show the settings pnpm
acts on under their documented names:

- `registries` shows the registries pnpm resolves from, merged across
every source (`.npmrc`, `pnpm-workspace.yaml`, the global config, CLI
flags), in the shape the setting is written in: keyed by registry URL,
with the default registry declared as the bare `@` scope. Built-in
routes are included — the `@jsr` scope and the `npmjs` and `gh` prefixes
— unless pointed elsewhere. Previously `pnpm config get registries`
printed `undefined`.
- `update` and `audit` show the effective sections, whichever spelling
set them. The deprecated internal spellings (`updateConfig`,
`auditConfig`, `auditLevel`) are no longer listed.
- `catalogs` shows the complete resolved catalog set — the singular
`catalog` block is its `default` entry — whichever spelling declared it.
- The `registry` and `@scope:registry` entries show the merged routes
rather than raw `.npmrc` values, so they always agree with the
`registries` view.

- Settings that no supported pnpm version recognizes get their own
warning. A key in the global config file that this version of pnpm does
not read is no longer reported with advice to move it to a project-level
`pnpm-workspace.yaml` (where it would be ignored too); the warning now
says the setting is not recognized by this version of pnpm, names the
pnpm version that does read it when there is one (for example,
`globalShims` is a pnpm v12 setting), and suggests the closest real
setting name when the key looks like a typo. Unrecognized and
non-camelCase keys in a project's `pnpm-workspace.yaml`, previously
ignored silently, are now reported the same way. `pnpm config get <key>`
and `pnpm get <key>` no longer print config-load warnings, so a script
capturing the value gets the value alone.

- The `importPackage` pnpmfile hook is deprecated. pnpm now prints a
warning when a pnpmfile defines it, and the hook will be removed in the
next major version. It also opts the installation out of the parallel
package importer, making installation slower. If you rely on this hook,
comment on
[#&#8203;14101](https://redirect.github.com/pnpm/pnpm/issues/14101).

- `node_modules/.modules.yaml` no longer records the registries an
install resolved from, and the recorded copy is dropped from the file on
the first install that rewrites it.

It dated from the lockfile format that spelled a dependency's path
relative to its registry, where reading an installed tree meant knowing
the registries it was installed with. Dependency paths have not carried
a registry for several major versions, and the recorded copy outlived
its use: `pnpm list`, `pnpm why`, and single-project installs preferred
it over the project's own configuration, so a project whose registry had
changed since its last install was still read through the old one.

They now use the configured registries, like every other command already
did.

- When `enableGlobalVirtualStore` is on, every process pnpm spawns for
the project (`pnpm run`, `pnpm exec`, lifecycle scripts) now receives a
`NODE_PATH` pointing at the project's hoisted `node_modules`, plus a
`NODE_OPTIONS` `--import` flag that registers a resolve hook restoring
`NODE_PATH` lookups for ESM imports. Dependencies that import undeclared
("phantom") packages keep resolving under the global virtual store — for
both CommonJS and ESM — without installing the
`@pnpm/plugin-esm-node-path` config dependency
[pnpm/pnpm#9618](https://redirect.github.com/pnpm/pnpm/issues/9618).
Tools run by `pnpm dlx` resolve such dependencies too: the JS CLI passes
them the same environment, while the Rust CLI's dlx cache is
self-contained, so its layout already exposes them.

- A registry can now declare that its abbreviated metadata carries the
`time` field, so `resolutionMode: time-based` reads the full metadata
document only from the registries that need it:

  ```yaml
  resolutionMode: time-based
  registries:
    https://npm.internal.example/:
      supportsTimeField: true
  ```

`registry.npmjs.org` omits `time` from abbreviated metadata, so a
time-based resolution has to fall back to the much larger full document.
That fallback used to be all-or-nothing: `registrySupportsTimeField`
answered for every registry at once, so a project resolving from both
the public registry and a Verdaccio instance either paid for full
metadata everywhere or claimed a `time` field npmjs does not serve. The
answer is now per registry, and `registrySupportsTimeField` remains the
answer for every registry that does not declare one.

The declaration is also sent to a pnpr server, which applies it to the
resolution it runs on the client's behalf.

- A pnpr resolve request now carries the client's registries the way the
`registries` setting declares them — keyed by URL, with the scopes
routed to each, the bare-specifier prefix each answers to, and each
one's `serverType` — in place of the prefix map it used to send.

The server routes them through the same inversion the config reader
runs, so a pnpr-served install resolves a scoped dependency from the
registry that scope is routed to, which it previously could not: only
the default registry and the prefix-addressed ones reached the server. A
declared `serverType` reaches it too, so the tarball URLs pnpr omits
from the lockfile match the ones the client reconstructs.

Built-in scope routes the project has not pointed elsewhere are not
declared, so a pnpr server's allowlist is not asked about `npm.jsr.io`
on requests that resolve no JSR package.

A registry a request only declares is no longer refused up front for
being off the server's allowlist — a client describes its whole
configuration, including scopes a given resolve never reaches, so a
stray `@scope:registry` in a developer's `~/.npmrc` no longer fails
every install against a pnpr server that does not serve it. The boundary
moves to the fetch itself: an origin the resolve does reach is refused
before the request leaves the server, with the same message.

This changes the resolve and verify-lockfile request bodies. A pnpr
server and its clients have to be on matching versions; the protocol is
still experimental and unversioned.

- The `registries` setting now declares a registry once, keyed by its
URL, with everything about that registry in the entry: how it lays out
tarball URLs, the scopes routed to it, and the bare-specifier prefix it
answers to.

  ```yaml
  registries:
    https://artifactory.example.com/artifactory/api/npm/npm-virtual/:
      serverType: artifactory
      scopes: ['@acme', '@acme-internal']
      prefix: work
  ```

- **`serverType`** tells pnpm how the registry lays out its tarball
URLs, which decides whether a URL can be omitted from `pnpm-lock.yaml`:
- **undeclared** (the default) — strict. Only the exact canonical URL is
treated as reconstructible.
- **`npm`** — the registry behaves like `registry.npmjs.org`, which also
serves a scoped package from its percent-encoded path. Declare this for
a faithful mirror or caching proxy of the public registry so its tarball
URLs can be omitted too.
- **`artifactory`** — JFrog Artifactory repeats the scope in a scoped
package's tarball filename (`@acme/widget/-/@acme/widget-1.0.0.tgz`)
where the npm registry strips it (`@acme/widget/-/widget-1.0.0.tgz`).
Declaring it lets pnpm rebuild that URL, so it is omitted from
`pnpm-lock.yaml` instead of being written out for every scoped package
[pnpm/get-npm-tarball-url#16](https://redirect.github.com/pnpm/get-npm-tarball-url/issues/16).
- **`scopes`** lists the `@`-prefixed scopes that resolve from this
registry. A bare `'@'` is the scope-less default registry, the one the
`registry` setting names.
- **`prefix`** is the alias a dependency addresses this registry by, as
in `"foo": "work:^1.0.0"`.

The layout is never inferred from the registry URL, so nothing changes
unless you declare it; `registry.npmjs.org` continues to behave as `npm`
without being declared. Because the lockfile depends on `serverType`, it
is read from `pnpm-workspace.yaml` only — a `serverType` in the global
`config.yaml` is ignored, so one developer's machine cannot shape a
lockfile their collaborators read back with a different layout.
Credentials are rejected in this setting, in a key as well as in a
field, and still belong in `.npmrc`. An entry that routes nothing to
itself and matches no configured registry is reported as a warning
rather than silently ignored.

##### Migrating

The older `registries` shape, a map of `<scope>: <url>` strings, still
works and needs no change:

```yaml
registries:
  '@acme': https://npm.acme.example/
```

`namedRegistries` is deprecated in favor of the `prefix` field, and is
still read for prefixes `registries` does not declare.

`toLockfileResolution` and `isCanonicalRegistryTarballUrl` now take
their registry and layout as an options object rather than positional
arguments, so `@pnpm/lockfile.utils` and `@pnpm/resolving.tarball-url`
get a major bump.

- An install that had to re-hash store files to verify them now reports
it. If that cost more than a second, it says how long — `The integrity
of N files was checked in 2.5s.` — and if it was quick but covered more
than a thousand files, it names the cause instead: their timestamps
changed since the store recorded them, which a backup tool, an antivirus
scan or a copied store can do.

- Added `virtualStoreType`, which names where the virtual store lives —
one store per machine, or one per project:

  ```yaml
  virtualStoreType: global   # or: project
  ```

It is the canonical spelling of `enableGlobalVirtualStore`, which keeps
working. When a project sets both, `virtualStoreType` wins. It can also
be set through `PNPM_CONFIG_VIRTUAL_STORE_TYPE` and read back with `pnpm
config get virtualStoreType`. The default is unchanged — `project`, so
the shared store stays opt-in.

The setting is independent of `nodeLinker`. `isolated` and `pnp` both
work with either store type, and `hoisted` writes no virtual store at
all, so it is unaffected.

#### Patch Changes

- `pnpm add --allow-build` now adds to the `allowBuilds` entries already
in `pnpm-workspace.yaml` instead of replacing them
[#&#8203;13872](https://redirect.github.com/pnpm/pnpm/issues/13872).

- Kept pending build approvals available after removing an unrelated
dependency.

- `pnpm approve-builds` now removes `onlyBuiltDependencies`,
`onlyBuiltDependenciesFile`, `neverBuiltDependencies`, and
`ignoredBuiltDependencies` from `pnpm-workspace.yaml` when it writes
`allowBuilds`. Those settings were replaced by `allowBuilds` in pnpm 11
and silently ignored since, so a workspace migrated from pnpm 10 kept
them around looking active.

- `pnpm audit` no longer reports a patched version that was never
published or is deprecated. The inferred patched range (e.g. `>=4.17.24`
from `<=4.17.23`) is now checked against the registry packument, and the
report is corrected to the lowest non-deprecated published version that
satisfies it (e.g. `>=4.18.1` when `4.17.24` does not exist and `4.18.0`
is deprecated). When no published version satisfies the range, the
report shows `Patched versions: None`. This also prevents `pnpm audit
--fix` from adding overrides or `minimumReleaseAgeExclude` entries for
patches that do not exist
[#&#8203;13824](https://redirect.github.com/pnpm/pnpm/issues/13824).

`pnpm audit --fix` and `pnpm audit --fix update` no longer add a
`minimumReleaseAgeExclude` entry when the registry packument shows that
the minimum patched version was never published. Previously such entries
were written for versions that do not exist, which would have let a
later publish of that version bypass the `minimumReleaseAge` gate
[#&#8203;11563](https://redirect.github.com/pnpm/pnpm/issues/11563).

The `--json` output of `pnpm audit` now returns `patched_versions: null`
for advisories whose inferred patch is not available (never published,
skipped, yanked, or deprecated), making it easier for tooling to
distinguish "no fix available" from "fix available at version X".

- Fixed `pnpm patch-commit` in project and edit paths containing
non-ASCII characters.

- The package and bump pickers of `pnpm change` now size their page from
the terminal height instead of always showing 7 rows. They fall back to
7 rows when the terminal height is unknown
[`pnpm/pnpm#13815`](https://redirect.github.com/pnpm/pnpm/issues/13815).

- Canceling a `pnpm change` prompt with Ctrl-c no longer prints a stack
trace. It reports `Change canceled` and exits with a success status,
like the other interactive commands
[#&#8203;13814](https://redirect.github.com/pnpm/pnpm/issues/13814).

- Re-fetch full registry metadata when `minimumReleaseAge` is enabled
and an abbreviated packument's `time` map omits timestamps for some
versions. This prevents mature versions from being filtered out and
resolution from falling back to the lowest matching version
[pnpm/pnpm#13741](https://redirect.github.com/pnpm/pnpm/issues/13741).

- A config dependency carrying an inline integrity (the
`<version>+<integrity>` form, or the object form without a `tarball`)
now takes its tarball URL from the registry's packument instead of
deriving it from the registry URL, so migrating one costs an extra
metadata request. On a registry that serves tarballs from a path pnpm
cannot derive, GitLab's group endpoint for one, installing such a config
dependency failed with a 404 while the same package installed fine as a
regular dependency
[#&#8203;13765](https://redirect.github.com/pnpm/pnpm/issues/13765).

- Fixed `PNPM_CONFIG_NODE_VERSION` being ignored when setting the
Node.js version used for compatibility checks.

- A custom fetcher can no longer replace the archive integrity that
`pnpm-lock.yaml` pins: the locked value is restored after a `canFetch`
or `fetch` hook rewrites the resolution, and delegating a locked archive
to a directory or git source now fails instead of installing unverified
content.

The Rust CLI now also loads the pnpmfiles named by the `pnpmfile`
setting (a single path or an ordered list), and hands custom fetchers
native `localTarball` and `remoteTarball` callbacks — including on a
fresh install that has to compute a missing tarball integrity, which is
then reused by later offline installs. File maps a fetcher returns are
accepted only when they match what those native callbacks extracted.

- Fixed an issue where running `pnpm dedupe --check` in projects with
`nodeLinker: hoisted` would cause dependencies to be moved out of
`node_modules` into `node_modules/.ignored`.

- `pnpm deploy --prod` and `pnpm deploy --no-optional` no longer list
the excluded dependency groups in the deployed `package.json` and
`pnpm-lock.yaml`. The deployed lockfile referenced packages that the
deploy left out of its graph, so installing in the deploy directory
afterwards created dangling symlinks
[#&#8203;13623](https://redirect.github.com/pnpm/pnpm/issues/13623).

- Don't treat files like `license16.json` as a package license when
deciding if the workspace LICENSE file should be included in the packed
package.

- `pnpm exec --recursive --no-reporter-hide-prefix` no longer prints a
blank prefixed line after each chunk of a command's output, and no
longer splits a line in two when it straddles a chunk boundary.

- Fixed `404` errors when installing from a registry that serves scoped
packages only from a percent-encoded path, such as GitHub Enterprise
Server. Outside `registry.npmjs.org`, a tarball URL that encodes the
scope separator as `%2f` or `%2F` is no longer mistaken for one that
pnpm can rebuild from the package name, version, and registry, so it is
kept in `pnpm-lock.yaml` and requested verbatim on the next install
[#&#8203;13534](https://redirect.github.com/pnpm/pnpm/issues/13534).

- Fixed `trustPolicyExclude` and `minimumReleaseAgeExclude` being
ignored when set to a single string instead of a list. The value was
read one character at a time, so the exclusion never matched the package
it named — and a `*` anywhere in it matched every package, silently
switching the policy off.

- `pnpm init` now pins the exact pnpm version instead of a `^` range,
and records it in the `packageManager` field alongside
`devEngines.packageManager`. Corepack reads only `packageManager` and
accepts nothing but an exact version, so it rejected the generated
`package.json` with "expected a semver version"
[pnpm/pnpm#13969](https://redirect.github.com/pnpm/pnpm/issues/13969). A
package created inside an existing workspace is still left unpinned — it
follows the pin at the workspace root — and `--no-init-package-manager`
still scaffolds a manifest without any pin. In pnpm 12, `pnpm init` also
honors `initType` and its `--init-type` flag, so the manifest it writes
is the same one pnpm 11 writes.

- Fixed an issue where package overrides were written into the metadata
cache, causing removed overrides to keep applying on subsequent installs
[pnpm/pnpm#13918](https://redirect.github.com/pnpm/pnpm/issues/13918).

- On Windows, upgrading pnpm no longer leaves a stale `pnpm.ps1` behind.
PowerShell resolves `pnpm.ps1` ahead of `pnpm.cmd`, so a shim written by
an older installation kept running the previous version. Linking the
pnpm CLI's bins now deletes it
[#&#8203;13919](https://redirect.github.com/pnpm/pnpm/issues/13919).

- Fixed an inconsistency where `minimumReleaseAgeExclude` (and
`trustPolicyExclude`) wildcard/bare-name rules behaved differently in
the evaluator and normalizer. A bare rule now consistently evaluates as
matching every version, preventing unexpected behavior and silent
widening of version policy exemptions when pnpm rewrites the workspace
manifest
[pnpm/pnpm#13725](https://redirect.github.com/pnpm/pnpm/issues/13725).

- A frozen install no longer rewrites the `packageManagerDependencies`
block of `pnpm-lock.yaml`. When the pnpm version pinned by
`devEngines.packageManager` (or by `packageManager`) is missing from the
lockfile or no longer matches it, `--frozen-lockfile` now fails with
`ERR_PNPM_FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE` instead of resolving
the version and saving it, so a manifest whose pin was bumped without
regenerating the lockfile can no longer pass CI
[#&#8203;14009](https://redirect.github.com/pnpm/pnpm/issues/14009).

- A git dependency installed over HTTPS from a hosted repository now
keeps its branch, tag, or version range in the specifier recorded in
`package.json`. It was written back without one, so the next `pnpm
update` moved the dependency to the repository's default branch
[#&#8203;13999](https://redirect.github.com/pnpm/pnpm/issues/13999).

- Fixed `pnpm update --global --latest` failing with a 404 error when a
globally installed package was not added from the registry by name.
Packages installed from a local path (`link:`/`file:`), a git
repository, a tarball URL, an `npm:` alias, or a named registry now keep
their spec during a global update instead of being looked up by name in
the default registry. See
[#&#8203;12854](https://redirect.github.com/pnpm/pnpm/issues/12854).

- Fix recursive `pnpm update <name>@<version>` so an exact pinned update
stays scoped to the requested version line: copies of the same package
on another major line — or, for a `0.x` request, another minor line —
keep their locked resolution instead of being re-resolved along with the
target.

- Under `nodeLinker: hoisted`, a dependency declared against a
peer-resolution variant of a package version is no longer dropped from
the installed layout. All variants of a version share one hoisted copy,
and edges pointing at any of them now resolve to it, so the depending
project keeps the package in its `.package-map.json` and the depending
package keeps it in its `node_modules/.bin`.

- Fixed `pnpm install --merge-git-branch-lockfiles` deleting the
per-branch lockfiles when the `lockfile` setting is `false`. Such an
install never reads them, so it has nothing to merge them into and now
leaves them alone.

- Fixed `pnpm install` sometimes not exiting after printing `Done in Xs`
[#&#8203;12297](https://redirect.github.com/pnpm/pnpm/issues/12297).

- Fixed pnpm failing to read `.modules.yaml` files containing long
dependency paths
[#&#8203;13875](https://redirect.github.com/pnpm/pnpm/issues/13875). The
manifest is now parsed as JSON (the format pnpm writes it in), falling
back to the YAML parser only for manifests written by old pnpm versions.

- With `preferSymlinkedExecutables`, `NODE_PATH` again points at the
virtual store of the workspace root when pnpm is run from inside a
workspace package, so scripts can resolve dependencies that live only in
the hoisted store
[#&#8203;13912](https://redirect.github.com/pnpm/pnpm/issues/13912).

- Reduced registry metadata requests during dependency resolution by
reusing cached metadata when lockfile preferences prove that no uncached
version can win
[pnpm/pnpm#13976](https://redirect.github.com/pnpm/pnpm/issues/13976).

- `pnpm pkg get` and `pnpm pkg set` now accept hyphens inside a
dot-notation property path, so `pnpm pkg get
dependencies.some-package-name` reads the key instead of failing with
`ERR_PNPM_UNEXPECTED_TOKEN_IN_PROPERTY_PATH`. The bracketed and quoted
forms already worked and are unchanged.

- A resolve request now carries the client's `resolutionMode`, so an
install delegated to a pnpr server picks versions the way the client
would. `time-based` and `lowest-direct` reached the server as nothing at
all, leaving it on its `highest` default: the returned lockfile pinned
the highest satisfying version of every dependency, and the setting
appeared to be ignored.

This adds a field to the resolve request body. A server older than its
client ignores it and keeps resolving `highest`; the protocol is still
experimental and unversioned.

- Fixed `pnpm` installs using pnpr to honor the client's
`autoInstallPeers`, `dedupePeers`, and `excludeLinksFromLockfile`
settings
[pnpm/pnpm#13389](https://redirect.github.com/pnpm/pnpm/issues/13389).

- `pnpm remove` now prunes undecided entries (`"set this to true or
false"`) from `allowBuilds` in `pnpm-workspace.yaml` when
`sharedWorkspaceLockfile: true` and the corresponding packages are
removed
[pnpm/pnpm#13892](https://redirect.github.com/pnpm/pnpm/issues/13892).

- Fixed workspace discovery for `pnpm-workspace.yaml` files without a
`packages` field so commands only consider the workspace root instead of
recursively scanning nested projects
[#&#8203;14047](https://redirect.github.com/pnpm/pnpm/issues/14047).

- A runtime installed through `devEngines.runtime` now matches the host
when `supportedArchitectures` lists several platforms. Listing `os:
[darwin, linux]` and `cpu: [x64, arm64]` used to install the runtime
built for the first entry of each list, so a machine running Linux on
arm64 got a macOS x64 Node.js that could not execute
[#&#8203;13898](https://redirect.github.com/pnpm/pnpm/issues/13898).

- `pnpm sbom` now fails with `ERR_PNPM_SBOM_MISSING_IMPORTERS` when
`pnpm-lock.yaml` has no entry for a selected project, instead of writing
an SBOM that under-reports that project's dependencies. Previously this
crashed with `Cannot read properties of undefined (reading
'devDependencies')`.

- `pnpm self-update` now rewrites a simple
`devEngines.packageManager.version` range (`^`/`~`) to the newly
installed version, keeping the operator — matching how `pnpm update` and
`pnpm runtime set` rewrite ranges. Complex ranges such as `>=8.0.0` that
the new version satisfies are still left unchanged
[#&#8203;13935](https://redirect.github.com/pnpm/pnpm/issues/13935).

- `pnpm self-update <tag>` no longer downgrades when the dist-tag points
at the pnpm version already running and that version is younger than
`minimumReleaseAge`. The maturity cutoff moved the tag back to the
previous mature release, so `pnpm self-update next-12` on v12.0.0-rc.4
switched to v12.0.0-rc.3.

- `pnpm set-script` now updates `package.json` instead of failing with
`ERR_PNPM_NOT_IMPLEMENTED`
[`pnpm/pnpm#13956`](https://redirect.github.com/pnpm/pnpm/issues/13956).

- `pnpm update` now preserves the existing range operator when updating
a prerelease dependency. See
[#&#8203;7002](https://redirect.github.com/pnpm/pnpm/issues/7002).

- Installs are faster in workspaces that declare inter-workspace
dependencies with plain ranges (`"*"`, `"^1.2.3"`) rather than the
`workspace:` protocol. With `preferWorkspacePackages` enabled, linking
such a dependency no longer makes a registry request that cannot change
the outcome — and workspace packages that were never published no longer
cost a 404 on every install.

- Added `fetchWarnTimeoutMs` and `fetchMinSpeedKiBps` to the Rust pnpm
CLI and its N-API bindings. Slow registry metadata requests and tarball
downloads now emit pnpm-compatible warnings without exposing URL
credentials, query parameters, fragments, or control characters
[pnpm/pnpm#12042](https://redirect.github.com/pnpm/pnpm/issues/12042).

- An override change is now absorbed by the fast lockfile update even
when another, unchanged override uses the `catalog:` protocol.
Previously any `catalog:`-valued override forced a full re-resolution
whenever the override list changed, which could move unrelated packages
in the lockfile (for example after `pnpm audit --fix` added an
override).

- Packed workspace package manifests now preserve dependency order,
making repeated `pnpm pack` output deterministic
[#&#8203;10167](https://redirect.github.com/pnpm/pnpm/issues/10167).

- `pnpm update <name>@<version>` now fails with
`ERR_PNPM_UPDATE_VERSION_ON_INDIRECT_DEP` when the package is not a
direct dependency of any selected project, instead of quietly updating
it to whatever a fresh install would resolve. There is nowhere to record
the version in that case, so the request cannot be honored, and the
error points at the `overrides` entry that does pin a transitive
dependency. Ranges and tags are unaffected, and a package that any
selected project declares directly still takes its version as before.

- `trustPolicy: no-downgrade` no longer aborts the install with
`ERR_PNPM_MISSING_TIME` on registries that serve no per-version `time`
field when `minimumReleaseAgeIgnoreMissingTime` is set. The trust check
reads the same publish dates the `minimumReleaseAge` check does, so it
now honors the same opt-in and skips the affected package with a warning
[#&#8203;12446](https://redirect.github.com/pnpm/pnpm/issues/12446).

`minimumReleaseAgeIgnoreMissingTime` no longer lets a lockfile entry the
registry does not list pass the `minimumReleaseAge` check during
lockfile verification. The opt-in covers a registry that cannot date its
releases; a packument that does date every version it lists is saying it
never published this one, which stays a hard failure.

The missing-`time` warning now names the check it is reporting on, so a
package whose `minimumReleaseAge` and `trustPolicy` checks are both
skipped warns about both instead of only the first.

- `pnpm update <pkg>@<version>` now updates only the selected packages
and leaves unrelated dependencies unchanged. A selector that renames the
package it installs — `pnpm update <alias>@npm:<pkg>@<version>` or the
`jsr:` equivalent — now targets the package the alias installs rather
than the alias.

- Fixed `verifyDepsBeforeRun` being ignored when set to `install`,
`warn`, `error`, or `prompt` through the
`PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN` environment variable or the
`--config.verify-deps-before-run` flag
[#&#8203;13816](https://redirect.github.com/pnpm/pnpm/issues/13816).
Only the boolean values were accepted before, so a string value was
silently dropped.

- `pnpm version <bump>` with `--dry-run` no longer edits `package.json`
files. It now only reports the bumps it would make, and skips the
working tree check, the version lifecycle scripts, the commit, and the
tag
[`pnpm/pnpm#13953`](https://redirect.github.com/pnpm/pnpm/issues/13953).

<!-- sponsors -->

#### Platinum Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://bit.cloud/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/bit.svg" width="80" alt="Bit"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://openai.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/openai_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/openai_light.svg" />
<img src="https://pnpm.io/img/users/openai_dark.svg" width="160"
alt="OpenAI" />
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>

#### Gold Sponsors

<table>
  <tbody>
    <tr>
      <td align="center" valign="middle">
<a href="https://sanity.io/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/sanity.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/sanity_light.svg" />
<img src="https://pnpm.io/img/users/sanity.svg" width="120" alt="Sanity"
/>
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://discord.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/discord.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/discord_light.svg" />
<img src="https://pnpm.io/img/users/discord.svg" width="220"
alt="Discord" />
          </picture>
        </a>
      </td>
      <td align="center" valign="middle">
<a href="https://vite.dev/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer"><img
src="https://pnpm.io/img/users/vitejs.svg" width="42" alt="Vite"></a>
      </td>
    </tr>
    <tr>
      <td align="center" valign="middle">
<a href="https://serpapi.com/?utm_source=pnpm&utm_medium=release_notes"
target="_blank" rel="noopener noreferrer">
          <picture>
<source media="(prefers-color-scheme: light)"
srcset="https://pnpm.io/img/users/serpapi_dark.svg" />
<source media="(prefers-color-scheme: dark)"
srcset="https://pnpm.io/img/users/serpapi_light.svg" />
<img src="https://pnpm.io/img/users/serpapi_dark.svg" width="160"
alt="SerpApi" />
          <

> ❗ **Important**
> 
> ✂ PR body was truncated to here.


</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/Goloom-App/goloom).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMi42IiwidXBkYXRlZEluVmVyIjoiNDQuOTMuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
fix(review-queue): atomic stale-safe review transition
Some checks failed
CI/CD Workflow / Test Backend (Go) (pull_request) Successful in 3m11s
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 14s
Website CI / Build website (pull_request) Failing after 40s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m45s
CI/CD Workflow / Test Postgres Store (pull_request) Failing after 1m34s
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Failing after 1m1s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 7m43s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
789cd026b9
Queue completions now use an explicit review_complete signal with a
status-guarded UPDATE (draft→pending) in both stores; a stale action on
a post that already left the draft state conflicts with 409
(review_conflict, X-Error-Code) instead of overwriting newer
composer-scheduled state.

review_complete must map to exactly one explicit action — publish_now:
true, or draft:false with an explicitly supplied scheduled_at — and
always requires write:schedule. Missing/incomplete/contradictory
patches are rejected with 400 before Prepare, so no implicit past
timestamp publishes without the publish-now marker.

Past-time rejection is now a Prepare option (RejectPastScheduledAt) so
drafts and publish_now stay exempt while schedule paths fail on the
past; agent-tools schedule/modify adopt it. OpenAPI, auth/scope DOX,
and frontend queue payloads updated accordingly.
Some checks failed
CI/CD Workflow / Test Backend (Go) (pull_request) Successful in 3m11s
CI/CD Workflow / Detect changed paths (pull_request) Successful in 10s
CI/CD Workflow / Security (Secrets: gitleaks) (pull_request) Successful in 14s
Website CI / Build website (pull_request) Failing after 40s
CI/CD Workflow / Test Frontend (Node.js) (pull_request) Successful in 1m45s
CI/CD Workflow / Test Postgres Store (pull_request) Failing after 1m34s
CI/CD Workflow / Security (Go: govulncheck + gosec) (pull_request) Failing after 1m1s
CI/CD Workflow / E2E (Playwright + Go) (pull_request) Failing after 7m43s
CI/CD Workflow / Build and Publish Docker Image (pull_request) Has been skipped
CI/CD Workflow / Trigger Dockhand Deployment (pull_request) Has been skipped
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'kreativmonkey/fix-issue-95:kreativmonkey/fix-issue-95'
git switch 'kreativmonkey/fix-issue-95'

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 'main'
git merge --no-ff 'kreativmonkey/fix-issue-95'
git switch 'kreativmonkey/fix-issue-95'
git rebase 'main'
git switch 'main'
git merge --ff-only 'kreativmonkey/fix-issue-95'
git switch 'kreativmonkey/fix-issue-95'
git rebase 'main'
git switch 'main'
git merge --no-ff 'kreativmonkey/fix-issue-95'
git switch 'main'
git merge --squash 'kreativmonkey/fix-issue-95'
git switch 'main'
git merge --ff-only 'kreativmonkey/fix-issue-95'
git switch 'main'
git merge 'kreativmonkey/fix-issue-95'
git push origin 'main'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kreativmonkey/goloom!131
No description provided.