Skip to content

chore(format): align oxfmt with sanity-io/ui (^0.71.0, config), pre-commit hook on lefthook - #2047

Merged
stipsan merged 12 commits into
mainfrom
cody/align-oxfmt-with-ui-e2dd
Sep 29, 2026
Merged

stipsan merged 12 commits into
mainfrom
cody/align-oxfmt-with-ui-e2dd

Conversation

@stipsan

@stipsan stipsan commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Brings oxfmt in line with sanity-io/ui's main: the same version, the same config, and the same scripts and CI wiring. The pre-commit hook moves from husky and lint-staged to lefthook, set up like sanity-io/sanity's. Supersedes #1919.

Commits

  1. chore(deps): update oxfmt to ^0.71.0: the catalog goes from ^0.63.0 to ui's ^0.71.0, with ui's oxfmt resolution: oxfmt 0.71.0 and tinypool 2.2.0, the same versions and integrity hashes as ui's lockfile. There's a patch changeset for @sanity/plugin-kit, whose optional oxfmt peer uses the catalog.
  2. chore(format): align the oxfmt config with sanity-io/ui: root oxfmt.config.ts now ignores storybook-static/** and CHANGELOG.md, like ui's .oxfmtrc.json. .vscode/settings.json points oxc.fmt.configPath at oxfmt.config.ts instead of the .oxfmtrc.json that Migrate plugin-kit and the monorepo from prettier/eslint to oxfmt/oxlint #1565 deleted. AGENTS.md records the parity with ui and the exceptions.
  3. chore: drop the husky and lint-staged pre-commit hook, like sanity-io/ui: superseded by commit 6, which brings the hook back on lefthook.
  4. chore(format): drop the oxfmt preset's .changeset/*.md override, like sanity-io/ui: the @sanity/plugin-kit/oxfmt preset loses its Prettier-era singleQuote: false override for .changeset/*.md, as ui's .oxfmtrc.json did when ui switched Changesets to oxfmt formatting (chore: use changesets format oxfmt ui#2957). It gets a patch changeset for @sanity/plugin-kit, since the preset is published. This part moved here from feat(themer): move @sanity/themer from sanity-io/ui, with a Storybook and ui's Changesets setup #2046 because it's formatter config. AGENTS.md now explains how changesets get quoted.
  5. chore(format): run pnpm format: requotes this PR's own changeset from commit 1. Everything else already passed under oxfmt 0.71.
  6. chore: run oxfmt on staged files with lefthook, like sanity-io/sanity: see below.

Pre-commit hook: husky and lint-staged → lefthook

This mirrors how sanity-io/sanity replaced husky and lint-staged (sanity-io/sanity#12755, then sanity-io/sanity#12767 and sanity-io/sanity#12953):

  • lefthook ^2.1.14 as a root devDependency, sanity's range. It resolves to 2.1.14, as in sanity's lockfile.
  • allowBuilds: lefthook: true in pnpm-workspace.yaml, as in sanity. Lefthook's own install script runs lefthook install during pnpm install, and it skips when CI is set, which covers GitHub Actions and Vercel. There's no root postinstall script: sanity dropped its lefthook install --reset-hooks-path postinstall in #12767 for this package build.
  • lefthook.yml with sanity's layout: a parallel pre-commit with two jobs that run oxfmt on staged files with stage_fixed: true. The jobs are format-scripts (*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}) and format-other (*.{md,yml,yaml,css,json,jsonc}).
  • Direct binary calls: the jobs call node_modules/.bin/oxfmt instead of sanity's pnpm oxfmt. Running pnpm in a hook triggers pnpm 12's implicit install, which flips the lockfile's peer toggle (see AGENTS.md). sanity switched to pnpm oxfmt in #12953 because lefthook doesn't put node_modules/.bin on PATH; the path solves that too.
  • Lockfile: pnpm-lock.yaml gains only lefthook 2.1.14 and its platform packages (100 lines). A plain install would also have bumped the Studio's next overrides from 6.17.0-next.108 to 6.17.0-next.112, so I resolved it through a local registry proxy that served the locked versions as next, as AGENTS.md describes. The lockfile has no localhost or tarball: entries.
  • Docs: AGENTS.md documents the hook, LEFTHOOK=0, the one-time reset for clones that ran husky, and pnpm --config.verify-deps-before-run=false <script> for local runs. README's note that formatting also runs in a pre-commit hook is back.

Merges with main

main is merged in, not rebased, so nothing was force-pushed. After each merge, pnpm-lock.yaml is main's lockfile regenerated with pnpm 12.6.0, invoked directly so packageManagerDependencies stays, minus the peer toggle that AGENTS.md describes.

pnpm-lock.yaml differs from main only by this PR's own changes:

  • oxfmt and its bindings go from 0.63.0 to 0.71.0, and tinypool from 2.1.0 to 2.2.0.
  • husky, lint-staged and their four exclusive dependencies are removed.
  • lefthook 2.1.14 and its platform packages are added.

No other version moves, and the Studio stays on 6.17.0-next.108.

How it compares with ui

  • Options: identical, overrides included (printWidth, semi, singleQuote, bracketSpacing, quoteProps, sortImports, sortPackageJson). They come from the @sanity/plugin-kit/oxfmt preset.
  • Ignore patterns: dist/**, storybook-static/**, pnpm-lock.yaml and CHANGELOG.md in both. Two differences remain:
    • turbo/**/*.hbs is plugins-only (the turbo generator templates).
    • ui's **/sanity.types.ts is left out. In ui it was for apps/docs/sanity.types.ts and has matched nothing since the docs app went static. Here, pnpm typegen formats dev/test-studio/sanity.types.ts on purpose: the test studio runs typegen with formatGeneratedCode: false and then pnpm format. Ignoring the file would make the next TypeGen PR unformat it.
  • Config file: plugins keeps oxfmt.config.ts re-exporting the published preset instead of ui's .oxfmtrc.json. Migrate plugin-kit and the monorepo from prettier/eslint to oxfmt/oxlint #1565 made that switch so the preset is exactly what the monorepo formats with, and plugin-kit's verify-package expects plugins to use it. oxfmt, the Oxc extension and Changesets' formatter detection all read oxfmt.config.ts. See the open question.
  • Scripts and CI: the format script is identical to ui's (oxfmt . --no-error-on-unmatched-pattern). Neither repo checks formatting on PRs, and both run the same shared format-if-needed.yml on main, so no workflow changes are needed. oxfmt . also formats .github/workflows/*.yml, which that workflow can't push, and 0.71 changes none of them. ui has no pre-commit hook; this repo keeps one, on lefthook.
  • VS Code: ui points oxc.fmt.configPath at its config file, but plugins pointed it at a file that doesn't exist. I drove oxfmt --lsp directly: with the old setting, the editor silently formats with oxfmt's defaults (double quotes, semicolons, bracket spacing, unsorted imports), and with oxfmt.config.ts it matches pnpm format.

Changesets

  • Changesets formats what it writes with oxfmt. .changeset/config.json sets "format": "oxfmt" (from feat(themer): move @sanity/themer from sanity-io/ui, with a Storybook and ui's Changesets setup #2046). I called @changesets/write (what changeset add uses) directly. With the override it writes "@sanity/plugin-kit": patch; without it, '@sanity/plugin-kit': patch, the same as pnpm format.
  • changeset version is unaffected. It only hands CHANGELOG.md files to the formatter. This PR ignores those, and oxfmt skips them and exits 0 thanks to --no-error-on-unmatched-pattern.
  • changeset status parses the single-quoted frontmatter. It lists this PR's two changesets for @sanity/plugin-kit 10.0.11.

What to expect after merging

Related PRs

What Cody needs to do

  • Add the 🤖 bot label: the agent's label tool couldn't edit PRs in this repository.
  • Triage Socket's alert. It flags lefthook@2.1.14's install script (node postinstall.js) as a low-priority warning. That script is what installs the hook: allowBuilds: lefthook: true enables it, as in sanity-io/sanity, and it skips when CI is set. Mark it as acceptable risk if you agree. Socket's required checks pass either way.
  • After merging, tell contributors to run git config --unset core.hooksPath && pnpm install once, so lefthook replaces husky's hook.
  • Merge the Renovate follow-up format PRs as they come, as in ui.
  • No Vercel, secrets or ruleset changes, and no new secrets or env vars.

Open question

.oxfmtrc.json: should plugins switch to ui's JSON config file, too? That would mean no longer re-exporting the plugin-kit preset, and it would reverse #1565. I kept oxfmt.config.ts, since the formatting result is already the same as ui's.

Verification

  • The hook, tested on throwaway commits, with pnpm-lock.yaml untouched each time:
    • Staged TS and JSON files get formatted and re-staged.
    • A tracked .vscode/settings.json (its folder is gitignored) is re-staged without the [FAILED] that lint-staged printed.
    • A staged CHANGELOG.md, which oxfmt ignores, passes as-is.
    • In a partially staged file, only the staged hunk is formatted and the unstaged hunk is kept.
    • The commit that adds the hook ran it on its own files in 0.4 seconds.
  • Clones that ran husky: with core.hooksPath=.husky/_, lefthook install exits 1 with instructions and installs nothing, as described above.
  • Local checks at the head commit, with pnpm 12.6.0 on Node 24.21 and CI=true (lefthook's install script skips):
    • pnpm install --frozen-lockfile, which leaves pnpm-lock.yaml untouched
    • oxfmt --check (2,018 files)
    • oxlint and knip
    • the full turbo build (54 tasks)
    • vitest run (235 files, 1,509 tests)
    • pnpm test:browser (4 files, 7 stories)
  • CI is fully green at the head commit (123af257): build, lint, knip, all four test shards, coverage, storybook-test, both e2e browsers, Bugbot, and both Vercel checks, whose installs run lefthook's install script. The branch is up to date with main.
Open in Web Open in Cursor 

Same version as sanity-io/ui. The lockfile only moves oxfmt, its
platform bindings and its tinypool dependency, to the same versions ui's
lockfile resolves. Supersedes #1919.
Ignore storybook-static/** and CHANGELOG.md like ui's .oxfmtrc.json.
ui's **/sanity.types.ts stays out: it no longer matches anything in ui,
while plugins formats dev/test-studio/sanity.types.ts on purpose.

Point the Oxc VS Code extension at oxfmt.config.ts: .oxfmtrc.json was
deleted in #1565, and with a missing oxc.fmt.configPath the oxfmt
language server formats with oxfmt's defaults (double quotes,
semicolons, unsorted imports) instead of the repo's settings.
The hook only ran oxfmt on staged files. sanity-io/ui has no pre-commit
hook: formatting comes from `pnpm format` and the Auto format workflow
on main, which this repo already runs. Existing clones need no cleanup:
husky's leftover .husky/_ runner exits 0 once .husky/pre-commit is gone.
@changeset-bot

changeset-bot Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 123af25

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sanity/plugin-kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
plugins-studio Ready Ready Preview Sep 29, 2026 8:43am UTC
1 Skipped Deployment
Project Deployment Actions Updated
plugins-e2e-test-studio Ignored Ignored Sep 29, 2026 8:43am UTC

Request Review

@socket-security

socket-security Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​oxfmt@​0.63.0 ⏵ 0.71.094 +810088 +196 +1100
Addednpm/​lefthook@​2.1.149210010094100

View full report

@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

✅ E2E Tests

🟢 43 passed • 🟡 1 flaky • view full report • view run

Studio: https://plugins-e2e-test-studio-l9v661854.sanity.dev

Datasets: pr-2047-chromium-36544401748, pr-2047-firefox-36544401748

@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 35.3% 6421 / 18187
🔵 Statements 35.22% 6842 / 19426
🔵 Functions 31.45% 1716 / 5455
🔵 Branches 26.69% 3419 / 12810
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/@sanity/plugin-kit/src/oxfmt.ts 100% 100% 100% 100%
Generated in workflow #10217 for commit 123af25 by the Vitest Coverage Report Action

cursor Bot pushed a commit that referenced this pull request Sep 29, 2026
…he oxfmt alignment PR

Dropping the `.changeset/*.md` `singleQuote: false` override from the
`@sanity/plugin-kit/oxfmt` preset is formatter config, which the oxfmt
alignment (#2047) owns, not the Changesets setup (config, versions,
scripts and release flow). Restore the preset as it is on main, drop its
`@sanity/plugin-kit` patch changeset, and format the remaining changesets
with the preset's double quotes again.
… sanity-io/ui

sanity-io/ui removed the same Prettier-era singleQuote: false override
when it switched Changesets to oxfmt formatting (sanity-io/ui#2957).
Changesets already formats the changesets it writes with oxfmt here:
its default format: "auto" detects oxfmt.config.ts, and #2046 makes
that explicit with "format": "oxfmt". Without the override, both
write single quotes, the same as pnpm format.
Requotes this PR's pending changeset now that the preset no longer keeps
.changeset/*.md files on double quotes. Rerun after rebasing onto any
branch that adds double-quoted changesets.
Resolves the pnpm-lock.yaml conflict with the lock file maintenance in
#2039 by taking main's lockfile and running pnpm install. Versions only
move for this branch's own changes (oxfmt 0.71.0 with tinypool 2.2.0,
husky and lint-staged removed). pnpm also recomputes the peer suffixes
of snapshots that have oxfmt as an optional peer (sanity@next,
@sanity/cli); clean main plus this branch's package.json and catalog
changes yields the same lockfile.
stipsan added a commit that referenced this pull request Sep 29, 2026
…2048)

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
Puts this repo on the same pnpm version and settings as
[sanity-io/ui](https://github.com/sanity-io/ui) `main`: `packageManager`
`pnpm@12.6.0`, ui's pnpm settings in `pnpm-workspace.yaml`, ui's CI
setup action (`pnpm/setup@v3`) but with its store cache off, and a
lockfile regenerated with pnpm 12.6.0. The `Dedupe lockfile` workflow
stays, with the one change pnpm 12 needs.

## Builds on #2044, supersedes #2043, #2044 and #1131

- **#2044** (pnpm 12.6.0 + `autoDedupe` + Vercel CLI bump) is the base.
Its commits are cherry-picked with `-x`. #2044's interim
`installCommand` workaround in `dev/e2e-studio/vercel.json`, which it
later removed, is left out, so this PR doesn't touch any Vercel config.
#2044 left CI on `pnpm/action-setup` + `actions/setup-node`; this PR
switches to ui's action.
- **#2043** (Renovate's plain `packageManager` bump) fails `E2E /
deploy-preview`, because `vercel@57` can't parse pnpm 12's lockfile (see
below).
- **#1131** (an early `pnpm/setup@v1` attempt) is covered by the CI
change here.
- **#2018** (lockfile regenerated from scratch) is not superseded: it
re-resolves every dependency, which is out of this PR's scope.

## Changes

| | Before | After |
| --- | --- | --- |
| `packageManager` | `pnpm@11.21.0` | `pnpm@12.6.0` (as in ui) |
| `pnpm-workspace.yaml` | | `autoDedupe: true` and
`strictPeerDependencies: false` (as in ui) |
| `.github/actions/setup` | `pnpm/action-setup@v6` +
`actions/setup-node@v7` + `pnpm install` | ui's action (`pnpm/setup@v3`,
`runtime: node@lts`) with `cache: false`, where ui has `cache: true` |
| `.github/workflows/pnpm-if-needed.yml` (`Dedupe lockfile`) | runs
`pnpm dedupe` once | kept; runs `pnpm dedupe` twice |
| `vercel` (root devDependency) | `^57.0.0` | `^60.1.3` |

- **Lockfile:** main's lockfile after #2039, plus this PR's changes as
pnpm 12.6.0 re-applied them. Those changes are the
`packageManagerDependencies` block, the `vercel@60.1.3` tree with the
optional-peer suffixes it brings, and `autoDedupe`'s dedupes: the same
`zod` and `gaxios` ones as the pending #2052, plus the peer toggle
described below. No other versions change, and `sanity@6.17.0-next.108`
stays put. #2039's refresh had already removed the three duplicates the
first revision collapsed.
- **Vercel CLI:** pnpm 12 writes the lockfile as two YAML documents.
`vercel@57`'s bundled `@vercel/build-utils` reads only the first, falls
back to npm, and fails on `workspace:*`, which is #2043's failure.
`58.9.5` is the first CLI that parses it, and every release from
`58.7.0` on ships without npm provenance (still published from GitHub
Actions OIDC). So `trustPolicy: no-downgrade` needs the exact versions
pnpm reports as `ERR_PNPM_TRUST_DOWNGRADE` in `trustPolicyExclude`:
`vercel@60.1.3` and 31 `@vercel/*` packages.
- **CI setup:** `pnpm/setup` reads `packageManager`, installs Node LTS,
runs `pnpm install`, and caches pnpm's lockfile-verification verdict
across jobs, which saves the ~28s supply-chain check. `ailf-eval.yml`
passes `runtime: node@lts` instead of `node-version: lts/*`.
`release.yml` keeps `pnpm/action-setup` + `actions/setup-node`, as in
ui.
- **Store cache off, unlike ui** (commit `bddef7a4`). With `cache:
true`, `pnpm/setup` uploads a new ~645 MiB store entry after every job,
even for an unchanged lockfile, because its keys include the run id.
That was 12 entries (7.7 GB) per push here, evicting the Playwright
browser caches the e2e jobs reuse. With it off, test shards spend 16–19s
in setup and nothing afterwards, against 19–23s plus 9–12s of upload
with it on. ui keeps `cache: true` and has the same issue. Revert
`bddef7a4` to match ui.
- **`Dedupe lockfile` workflow kept, adapted for pnpm 12** (commit
`a7e1057f`). On the current lockfile, pnpm 12.6.0's `pnpm dedupe` isn't
idempotent. Each run toggles `@vitejs/devtools` and
`oxc-transform-react` in the peer suffixes of
`plugins/@sanity/debug-preview-url-secret-plugin`'s `sanity` and
`@sanity/tsdown-config` entries, without changing any version. Run once,
as before, the workflow would open a toggle-only PR after every lockfile
change on `main`, and each automerged dedupe PR would trigger the next.
A second run undoes the toggle and keeps real dedupes. An earlier commit
in this branch deleted the workflow; `82810b5e` reverts that.
- **Docs:** AGENTS.md, CONTRIBUTING.md and README.md now require pnpm
v12. AGENTS.md and `e2e/README.md` explain the two-document lockfile and
the Vercel CLI floor; per Copilot's review of #2044, the trust-policy
wording only lists versions that pnpm reports as downgrades. AGENTS.md
also says not to commit lockfile diffs that only flip the peer toggle.

No changeset: no published package's manifest or runtime code changes,
as with the pnpm 11 bump in #1579.

## Merge with main

`main` gained one commit after this branch started: Renovate's lock file
maintenance (#2039, `cb68d65e`). It conflicted only in `pnpm-lock.yaml`.
`main` is merged in rather than rebased, so nothing was force-pushed.
The resolution takes main's lockfile and lets pnpm 12.6.0 re-apply this
PR's changes; `pnpm-workspace.yaml` needed no further changes. #2039's
25 source files merged cleanly.

## What Cody needs to do

- **Add the "🤖 bot" label.** The agent's label tool can't edit PRs in
this repo.
- **Close #2044 and #1131** when this lands. Renovate autocloses #2043.
The pending dedupe PR #2052 is redundant, since its four lines are
already in this lockfile. It merges cleanly with this PR in either
order.
- **Vercel:** nothing to set up. No project, env var or `vercel.json`
changes; only the root `vercel` CLI devDependency moves.
- **Secrets and ruleset:** no new secrets, and the required checks
(`lint`, `build`, `test`, Socket) keep their names.

## Open questions

1. **Vercel CLI trust exclusions.** This is #2044's call, which
overrides the reason #1890 was closed: 32 exact versions without
provenance in `trustPolicyExclude`. Every future `vercel` bump has to
add its own versions, so Renovate's `vercel` PRs will fail their
artifact update until someone does. The alternative is e2e previews that
can't build on pnpm 12.
2. **`strictPeerDependencies: false`** matches ui but is already pnpm's
default; ui carried it over from an old `.npmrc`. Keep it for parity, or
drop it?
3. **Store cache in ui.** ui has the same per-job uploads. Turn its
store cache off too?

## Known pnpm 12.6.0 issue

The peer toggle also shows up locally. A fresh `pnpm install`, or the
implicit install pnpm runs before scripts when `node_modules` looks
stale, flips those two suffixes in `pnpm-lock.yaml`. Frozen installs,
which CI uses, never do. The lockfile before #2039 didn't toggle; main's
refreshed resolutions exposed it, and it happens with `autoDedupe` off
too.

## Not in this PR

- vitest 5, oxfmt (#2047), oxlint (#2049) and the tsdown setup are
sibling PRs. Whichever lands later merges `main` and regenerates the
lockfile.
- ui's `packageExtensions` entry for `@testing-library/jest-dom` belongs
to its vitest 5 setup.
- ui's root `engines.node: ">=22.13"` and macOS test job are Node and
test-matrix changes, not pnpm. Plugins' tooling needs Node ≥ 22.18
anyway (AGENTS.md).
- Plugins-specific pnpm settings that ui doesn't have (`trustPolicy`,
`dedupePeers`, `dedupeDirectDeps`, `publicHoistPattern`) stay.

## Verification

- **Lockfile:** regenerated on `main` at `cb68d65e` by pnpm 12.6.0 run
directly on Node 24.21.0. A cold `pnpm install --frozen-lockfile` passes
the supply-chain check (2,615 entries), and without the Vercel
exclusions it fails with `ERR_PNPM_TRUST_DOWNGRADE`.
- **Dedupe workflow:** from the committed lockfile, from its toggled
state, and from the committed lockfile with #2052's duplicates put back,
two `CI=true pnpm dedupe --config.ignore-scripts=true` runs give,
respectively, no change, no change, and exactly #2052's dedupes. A
single run gives the toggle every time.
- **Local checks on the merged tree:** `pnpm lint`, `pnpm knip`, `pnpm
build` (52/52 tasks) and `pnpm test run` (224 files, 1,391 tests) pass.
- **CI:** everything passes on `bddef7a4`, including `deploy-preview`
(Vercel CLI 60.1.3 detects the lockfile and installs with pnpm 12.6.0)
and e2e on Chromium and Firefox. CI on `a7e1057f`, which only touches
the dedupe workflow and AGENTS.md, is running.
- **zizmor:** `zizmor .github` reports the same findings as on `main` at
every severity.

<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-0c45b56b-fd33-55f7-b22c-89bde73748e4?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-0c45b56b-fd33-55f7-b22c-89bde73748e4&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Brings in pnpm 12.6.0 from #2048.

package.json keeps both sides: main's packageManager pnpm@12.6.0 and
vercel ^60.1.3, without this branch's removed lint-staged block.

pnpm-lock.yaml is main's lockfile regenerated with pnpm 12.6.0.
Versions only move for this branch's own changes (oxfmt 0.71.0 with
tinypool 2.2.0; husky, lint-staged and their exclusive dependencies
removed). pnpm also re-derives the peer contexts of snapshots that have
oxfmt as an optional peer, which adds sanity@6.17.0-next.108 and
@sanity/cli@8.13.0 variants. Clean main plus this branch's package.json
and catalog changes yields the identical lockfile. pnpm format changes
nothing.
The merge's regenerated lockfile carried the peer toggle that AGENTS.md
describes: a non-frozen install flips @vitejs/devtools and
oxc-transform-react in the peer suffixes of
@sanity/debug-preview-url-secret-plugin's sanity and
@sanity/tsdown-config entries, adding sanity and @sanity/cli snapshot
variants, without changing any version. This restores main's side of
the toggle, so pnpm-lock.yaml differs from main only by this branch's
own changes: oxfmt 0.71.0 with tinypool 2.2.0, and husky, lint-staged
and their exclusive dependencies removed.
stipsan added a commit that referenced this pull request Sep 29, 2026
… and ui's Changesets setup (#2046)

<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
Moves `@sanity/themer` from sanity-io/ui (`packages/themer`) to
`plugins/@sanity/themer`, adds a React Storybook in `dev/storybook`
modeled on sanity-io/ui's `apps/storybook`, and puts the whole repo on
sanity-io/ui's Changesets setup.

## What's in this PR

1. **Changesets setup identical to sanity-io/ui (repo-wide).**
`.changeset/config.json` gains `"format": "oxfmt"` and
`"bumpVersionsWithWorkspaceProtocolOnly": true` (only the changelog
`repo` differs from ui's). `@changesets/cli` ^3.0.3 and
`@changesets/changelog-github` ^1.0.1 are root devDependencies, and
there's a `changeset` script. `release.yml` drops the npm@11 pin, since
`@changesets/cli` 3.0.3 handles npm 12's `pnpm info --json` output
(changesets/changesets#2274). The Renovate changesets workflow is ui's.
2. **Catalog aligned with sanity-io/ui for what themer needs:**
`@sanity/ui` ^4.2.7, `@sanity/icons` ^5.2.2, `motion` ^13.4.4,
`@sanity/vanilla-extract-vite-plugin` ^0.2.20. These are the ranges
`@sanity/themer@0.8.0` was published with. As AGENTS.md asks for uniform
shared-dependency updates, one combined patch changeset covers the 43
published plugins whose `dependencies` ranges change with the
`@sanity/ui`, `@sanity/icons` and `motion` bumps;
`@sanity/vanilla-extract-vite-plugin` is a devDependency everywhere, so
it doesn't reach a published range.
3. **The move.** Source copied from sanity-io/ui `main` (`b28d66c`),
which is exactly the published 0.8.0. The version and CHANGELOG carry
over, so the next release is 0.8.1. `package.json` follows the monorepo
template (plugins repository links, `build`/`prepack` scripts) with the
published exports, `sideEffects`, and dependency ranges.
`@sanity/themer-legacy` (moving to sanity-io/themer) is the published
^0.2.1. `xstate`, `@xstate/react`, and `scroll-into-view-if-needed` move
to the catalog, since other plugins now share them;
`sanity-plugin-dashboard-widget-vercel` gets its own patch changeset for
its `xstate` range (^5.32.5 → ^5.33.2). The test studio switches from
`^0.8.0` on npm to `workspace:*`; `themerTool()` was already wired in
its Home workspace.
4. **Storybook in `dev/storybook`**, next to the test studios, set up
like sanity-io/ui's `apps/storybook`: Storybook 10.6 with the a11y,
docs, links, themes and vitest addons, the React Compiler through
`@vitejs/plugin-react`, and the vanilla-extract plugin for workspace
plugins' `.css.ts` source. The preview imports `@sanity/ui/styles.css`,
since the published dist doesn't. The global decorator renders every
story in the theme `buildTheme` from `@sanity/themer` builds from a
preset picked in the toolbar, next to the light/dark toggle. It adds
`pnpm dev:storybook`, `pnpm storybook:build`, `pnpm test:browser`, ui's
`apps/storybook/vercel.json` unchanged (as `dev/storybook/vercel.json`),
a `storybook-test` CI job like ui's, and eslint-plugin-storybook's CSF
rules through oxlint's JS plugins, as in ui. Unlike ui's job,
`storybook-test` also installs Playwright's system deps when it restores
the browser cache, as this repo's e2e workflow does (Bugbot flagged that
the cache doesn't hold them). Like the other `dev/*` apps, it's skipped
by `pretest` and the CI build job.

## Layout

No existing folder is renamed or moved, and there's no new top-level
folder. `@sanity/themer` goes into the existing `plugins/@sanity/`
folder next to the other `@sanity/*` plugins, not ui's
`packages/themer`. The Storybook goes into the existing `dev/` folder as
`dev/storybook`, next to `dev/test-studio` and `dev/e2e-studio`, so the
`dev/*` workspace glob and the `./dev/*` build filters already cover it.
The root only gains workspace-level config.

## How faithful the move is

- **Build output vs. the npm tarball of 0.8.0:** JavaScript is identical
apart from chunk hashes, and `bundle.css` is byte-identical. The `.d.ts`
files have the same API; tsdown 0.22 writes `declare …; export {…}`
where 0.23 wrote `export declare …`.
- **Source changes:** `type` modifiers on type-only imports (plugins'
`strictest` tsconfig has `verbatimModuleSyntax`), one inline
`oxlint-disable-next-line react/exhaustive-effect-dependencies` with its
reason (the rule is on here and off in ui; the `[palette]` dependency is
deliberate), and the README license link. The tsconfig is `strictest`
without `noUncheckedIndexedAccess`, which ui never enabled
(`sanity-plugin-graph-view` and `plugin-kit` do the same).
- **No React Compiler typings stub:** ui's
`typings/babel-plugin-react-compiler.d.ts` isn't carried over. Here the
real `babel-plugin-react-compiler` types resolve (it's a linked optional
peer of `@sanity/tsdown-config`), so `defineConfig()` picks the
single-config overload, and a wrong `reactCompiler` value is still
flagged (checked with a bad `target`, a misspelled `transform`, a number
`target` and an unknown key).
- **Tests:** themer's Vitest config sets `testTimeout: 30_000`. PR CI
here runs every project with coverage, and the whole-theme `buildTheme`
tests took 8s there against the 5s default (ui runs them without
coverage).
- **Versions:** every themer runtime dependency and the whole Storybook
stack resolve to the same versions as in ui's lockfile.

## What Cody needs to do

- **npm trusted publishing:** publishing runs from
`.github/workflows/release.yml`, which this repo already had; it now
uses ui's version/publish flow. The trusted publisher for
`@sanity/themer` must be repository `sanity-io/plugins`, workflow
`release.yml`, no environment.
- **Vercel:** the Storybook carries ui's `apps/storybook/vercel.json`
unchanged, as `dev/storybook/vercel.json` (`pnpm build` into
`storybook-static`). To deploy it like ui's `sanity-ui-storybook`,
create a project with root directory `dev/storybook`; the file supplies
the build command and output directory. No other Vercel config is
touched: `dev/e2e-studio/vercel.json` and the `plugins-studio` and
`plugins-e2e-test-studio` projects stay as they are, and both previews
built fine on this PR.
- **Secrets and env vars:** none new. The touched workflows use names
this repo already has: `ECOSPARK_APP_ID`, `ECOSPARK_APP_PRIVATE_KEY`,
`vars.ECOSPARK_CLIENT_ID`, `TURBO_TOKEN` and `vars.TURBO_TEAM`.
`storybook-test` uses none.
- **Ruleset:** no swap needed. The `main` ruleset requires `lint`,
`build`, `test` and the two Socket Security checks, and those job names
are unchanged. Optionally, to match ui (which requires `build`, `knip`,
`Test node@lts / ubuntu-latest`, `storybook-test` and its two Vercel
checks), add `storybook-test` and `knip`, and the Storybook's Vercel
check once that project exists.
- **CODEOWNERS:** untouched, per the transfer convention. Add an owner
for `plugins/@sanity/themer` if you want one.

## Open questions

1. **Patch, not major.** The transfer skill defaults to a major, but
themer is 0.x, nothing breaks, the next release should continue from the
published version, and themer's own deprecation notice reserves 1.0 for
removing `@sanity/themer/legacy`. So the changeset is a patch (0.8.1).
The color move made the same call.
2. **Stories.** sanity-io/ui had no themer stories. I ported the ui
stories that exercise what themer builds (theme
Debug/Build/Canvas/Color, and the color palette story on
`buildPalette`'s output) and added stories for the tool's theme
thumbnails and navbar color wheel. Those two aren't public API, so their
stories import them from `plugins/@sanity/themer/src` by relative path.
Keep them, or public API only?
3. **`sanity` peer range.** I kept 0.8.0's optional `^3 || ^4 || ^5 ||
^6` instead of the monorepo's `catalog:peer` (`^5 || ^6.0.0-0`), which
would drop Studio v3/v4. As with 0.8.0 from npm, it doesn't match the
`sanity@next` prereleases here, so the test studio shows a peer warning.
4. **`bumpVersionsWithWorkspaceProtocolOnly`.** With ui's setting,
Changesets no longer rewrites `@sanity/sfcc`'s intentionally wide
`sanity-plugin-internationalized-array` peer (`^4.0.0 || ^5.0.0`), the
only internal dependency that doesn't use `workspace:`. That seems
right, but it's a behavior change.

## Remaining alignment with sanity-io/ui (not in this PR)

This PR stays scoped to the themer move. Matching ui's tooling happens
in five separate PRs, one per tool, each owned by another worker. All
five exist:

- **pnpm** 11.21.0 → 12.6.0 with ui's pnpm setup, including the
`pnpm/setup@v3` CI setup action: #2048 (merged; this branch is merged
with it)
- **oxfmt** ^0.63 → ^0.71 with ui's config: #2047. Dropping the
`@sanity/plugin-kit/oxfmt` preset's Prettier-era `.changeset/*.md`
`singleQuote: false` override, which ui did when it enabled Changesets'
`format: "oxfmt"`, belongs there too; #2047 doesn't include it yet.
- **vitest** ^4.1 → ^5.0, with `@vitest/coverage-v8`: #2050. If it
merges first, the rebase of this PR raises the Storybook's
`@vitest/browser-playwright` to `^5.0.2` and re-resolves
`@storybook/addon-vitest` in the lockfile, since otherwise two stale
vitest 4 packages stay behind. #2050's worker checked that the Storybook
tests pass on vitest 5 with those two changes (`@storybook/addon-vitest`
10.6 officially peers on vitest 3/4; ui runs it on 5 with loose peers).
- **oxlint** ^1.83 → ^1.86 and **oxlint-tsgolint** ^7.0.2001 → ^7.0.2003
with ui's config: #2049. It turns `react/exhaustive-effect-dependencies`
off, as ui does, so if it merges first, the rebase of this PR drops its
one suppression for that rule in `ImagePaletteSection.tsx`, which would
otherwise be an unused-directive error.
- **tsdown** ^0.22 → ^0.23 with **@sanity/tsdown-config** ^0.27 → ^0.28,
which requires tsdown 0.23: #2051

All five also touch files this PR changes (`pnpm-workspace.yaml`,
`pnpm-lock.yaml` and `AGENTS.md`; `package.json` and `README.md` for
#2047 and #2048; `oxlint.config.ts` for #2049;
`.github/workflows/ci.yml` and `.gitignore` for #2050), so whichever PR
merges later rebases and regenerates the lockfile.

Smaller differences left to Renovate or later PRs: `oxc-transform-react`
^0.147 → ^0.151 (#1988), `@types/node` ^24.13 → ^24.19, `jsdom` ^29 →
^30, `knip` ^6.33 → ^6.38, ui's macOS test run, and ui's root
`engines.node: ">=22.13"`.

## Verification

- `pnpm format`, `pnpm knip`, `pnpm lint`, `pnpm build` (54 tasks,
including both studios and the Storybook), `pnpm test run` (235 files,
1,509 tests) and `pnpm test:browser` (7 stories) all pass locally,
starting from `pnpm install --frozen-lockfile`.
- A `changeset version` dry run in a scratch worktree, with ui's config
and `GITHUB_TOKEN`, bumps themer 0.8.0 → 0.8.1 and
dashboard-widget-vercel 4.0.28 → 4.0.29 (before the combined changeset;
`changeset status` now plans 46 patch releases: the 43 plugins, themer,
and `sanity-plugin-studio-smartling` and `sanity-plugin-transifex`,
which follow `sanity-translations-tab` as internal dependents), credits
@stipsan through the `author:` line, and writes CHANGELOGs that pass
`oxfmt --check`.
- `zizmor .github --min-severity high` reports no findings.

## Transfer verification

- [x] `package.json` dependencies, peerDependencies and exports verified
against the published 0.8.0
- [x] `LICENSE` not added: ui's credits only Sanity.io; the README links
this repo's LICENSE
- [x] Test studio uses the workspace package (`themerTool()` was already
wired)
- [x] `pnpm format`, `pnpm knip`, `pnpm lint`, `pnpm build`, `pnpm test
run` pass
- [x] Changeset added (patch; see open question 1)
- [ ] Trusted publishing for `@sanity/themer` configured with
`sanity-io/plugins` and `release.yml`

## Maintainer follow-up

- [ ] Remove `packages/themer` from sanity-io/ui (with its entries in
ui's root `build`/`test` scripts and `pkg-pr-new.yml`) once this lands,
on your go-ahead
- [ ] Point ui's docs and AGENTS.md mentions of `@sanity/themer` to
`plugins/@sanity/themer`
- [ ] Transfer open themer issues from sanity-io/ui and label them
`themer`

## Screenshots

The theme cards of every preset, in the dark scheme:

[Storybook: themer tool theme thumbnails for every
preset](https://cursor.com/agents/bc-7516e1ad-c642-5cd2-97f4-35288fbda30a/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fstorybook_themer_theme_thumbnails_presets.png)

The palette `buildPalette` generates for the Verdant preset, light
scheme (its backgrounds replace black and white, its accent the blue
scale, its text color the gray scale):

[Storybook: generated Verdant palette with contrast
badges](https://cursor.com/agents/bc-7516e1ad-c642-5cd2-97f4-35288fbda30a/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fstorybook_themer_palette_verdant_light.png)

The Debug theme story in the Pink Synth preset, both schemes:

[Storybook: Debug theme story in the Pink Synth
preset](https://cursor.com/agents/bc-7516e1ad-c642-5cd2-97f4-35288fbda30a/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fstorybook_themer_debug_pink_synth.png)


<sub>To show artifacts inline, <a
href="https://cursor.com/dashboard/cloud-agents#team-pull-requests">enable</a>
in settings.</sub>
<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-7516e1ad-c642-5cd2-97f4-35288fbda30a?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-7516e1ad-c642-5cd2-97f4-35288fbda30a&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Brings in the themer move from #2046. Only pnpm-lock.yaml conflicted.

pnpm-lock.yaml is main's lockfile regenerated with pnpm 12.6.0, minus
the peer toggle AGENTS.md describes (debug-preview-url-secret-plugin's
sanity and @sanity/tsdown-config suffixes). It differs from main only by
this branch's own changes: oxfmt 0.71.0 with tinypool 2.2.0, and husky,
lint-staged and their exclusive dependencies removed.
sanity@6.17.0-next.108 doesn't move.
Requotes the three changesets from #2046
(dashboard-widget-vercel-xstate, shared-deps-sanity-ui-icons-motion and
themer-plugins-monorepo) now that the oxfmt preset no longer keeps
.changeset/*.md files on double quotes. Quote-only changes; the themer
package and dev/storybook already pass.
Brings in the Version Packages release (#2053), which consumed the three
changesets from #2046 that this branch had just requoted. The
modify/delete conflicts resolve to main's deletions. #2053 didn't
change pnpm-lock.yaml, so this branch's lockfile (main's, regenerated
with pnpm 12.6.0, minus the peer toggle) still applies. pnpm format
changes nothing.
Brings back a pre-commit hook, set up the way sanity-io/sanity replaced
husky and lint-staged: lefthook ^2.1.14 as a root devDependency, its
install script allowed in pnpm-workspace.yaml (it installs the hook and
skips when CI is set), and a lefthook.yml whose parallel jobs run oxfmt
on staged scripts and on other files with stage_fixed. sanity's oxlint
command is left to the oxlint alignment. The jobs call
node_modules/.bin/oxfmt instead of sanity's pnpm oxfmt, because running
pnpm in a hook triggers pnpm 12's implicit install, which flips the
lockfile's peer toggle.

pnpm-lock.yaml only gains lefthook 2.1.14 and its platform packages. It
was resolved through a local registry proxy that served the locked
6.17.0-next.108 as the next dist-tag, as AGENTS.md describes, so the
Studio overrides stay put.
@cursor cursor Bot changed the title chore(format): align oxfmt with sanity-io/ui (^0.71.0, config, no pre-commit hook) chore(format): align oxfmt with sanity-io/ui (^0.71.0, config), pre-commit hook on lefthook Sep 29, 2026
@socket-security

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
Low priority
Install-time scripts: npm lefthook during postinstall

Install script: postinstall

Source: node postinstall.js

From: package.json → npm/lefthook@2.1.14

ℹ Read more on: This package | This alert | What is an install script?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not be running non-essential scripts during install and there are often solutions to problems people solve with install scripts that can be run at publish time instead.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/lefthook@2.1.14. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn

View full report

@stipsan
stipsan marked this pull request as ready for review September 29, 2026 09:12
@stipsan
stipsan requested a review from a team as a code owner September 29, 2026 09:12
@stipsan
stipsan requested review from bjoerge and a balanced review from Copilot and removed request for a team September 29, 2026 09:12
@stipsan
stipsan merged commit 89bbaf7 into main Sep 29, 2026
27 checks passed
@stipsan
stipsan deleted the cody/align-oxfmt-with-ui-e2dd branch September 29, 2026 09:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The migration is internally consistent, documented, comprehensively verified, and has no unresolved code issues.

Review effort: Balanced
Findings: None

What changed in this PR

Aligns repository formatting with sanity-io/ui and migrates the pre-commit formatter from Husky/lint-staged to Lefthook.

Changes:

  • Upgrades oxfmt to 0.71 and aligns configuration.
  • Adds Lefthook-based staged-file formatting.
  • Updates plugin-kit changesets and contributor documentation.
File Description
.changeset/​plugin-kit-oxfmt-0-71.md Records the oxfmt peer update.
.changeset/​plugin-kit-oxfmt-changeset-quotes.md Records the preset quoting change.
.husky/​pre-commit Removes the obsolete Husky hook.
.vscode/​settings.json Points VS Code to the active formatter config.
AGENTS.md Documents formatting and Lefthook workflows.
lefthook.yml Adds staged-file formatting jobs.
oxfmt.config.ts Aligns workspace ignore patterns.
package.json Replaces Husky/lint-staged with Lefthook.
packages/​@sanity/​plugin-kit/​src/​oxfmt.ts Removes the changeset quote override.
pnpm-lock.yaml Locks updated formatter and hook dependencies.
pnpm-workspace.yaml Updates the catalog and permits Lefthook installation.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@squiggler-app squiggler-app Bot mentioned this pull request Sep 29, 2026
cursor Bot pushed a commit that referenced this pull request Sep 29, 2026
Brings in the oxfmt 0.71 alignment and the lefthook pre-commit hook
from #2047. Only pnpm-lock.yaml conflicted.

pnpm-lock.yaml is main's lockfile regenerated with pnpm 12.6.0. npm's
`next` dist-tag has moved to 6.17.0-next.112, and a plain regeneration
re-resolved the Studio `next` overrides to it, so the lockfile was
resolved through a local registry proxy that serves the locked
6.17.0-next.108 as `next` (as AGENTS.md describes); the Studio versions
stay at main's and the lockfile has no localhost or tarball entries.
main's lockfile still had @vitest/browser@4.1.11 and
@vitest/runner@4.1.11 as optional peers of @storybook/addon-vitest, so
it is re-resolved against @vitest/browser@5.0.2 again, which leaves no
vitest 4 package. The @vitejs/devtools/oxc-transform-react toggle in
@sanity/debug-preview-url-secret-plugin ends up at main's variant. The
change set against main is the same as in the previous merge, and a
clean main with this branch's two manifest changes reproduces the
lockfile with the same steps.
cursor Bot pushed a commit that referenced this pull request Sep 29, 2026
Brings in the oxfmt 0.71 alignment with the lefthook pre-commit hook
(#2047) and the Version Packages release (#2053).

- pnpm-workspace.yaml: kept both sides of the adjacent catalog lines
  (main's oxfmt ^0.71.0, this branch's oxlint ^1.86.0 and
  oxlint-tsgolint ^7.0.2003).
- pnpm-lock.yaml: took main's lockfile and let pnpm 12.6.0 re-apply this
  branch's catalog change, so it differs from main only by the oxlint
  and oxlint-tsgolint catalog specifiers. The `next` dist-tag has moved
  to 6.17.0-next.112 since main's lockfile was written, so a plain
  re-resolution would have upgraded the Studio; as AGENTS.md describes,
  it ran through a local registry proxy serving the locked
  6.17.0-next.108 as `next`, and a second re-resolution undid the known
  peer toggle on plugins/@sanity/debug-preview-url-secret-plugin.
cursor Bot pushed a commit that referenced this pull request Sep 29, 2026
#2047 dropped the plugin-kit oxfmt preset's .changeset/*.md override, so changeset frontmatter now uses single quotes like every other file.
cursor Bot pushed a commit that referenced this pull request Sep 29, 2026
Brings in oxfmt 0.71 and the lefthook pre-commit hook from #2047, and
the Version Packages release from #2053.

pnpm-lock.yaml is main's, regenerated with pnpm 12.6.0. npm's `next`
dist-tag for the Studio packages moved to 6.17.0-next.112 this morning,
so the regeneration resolved through a local registry proxy that serves
6.17.0-next.108 as `next`, as AGENTS.md describes; the lockfile has no
proxy or tarball entries. Versions only move for this branch's toolchain,
the rolldown-plugin-dts patch applies with the same hash, and `pnpm
install --fix-lockfile` reverted the debug-preview-url-secret-plugin
optional-peer toggle. The result is identical to git's textual merge of
the two lockfiles.
stipsan pushed a commit that referenced this pull request Oct 2, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @sanity/themer@0.9.0

### Minor Changes

- [#2065](#2065)
[`e1c357b`](e1c357b)
Thanks [@stipsan](https://github.com/stipsan)! - Adopt <Activity>,
<ViewTransition> and React.lazy APIs according to best practice. Removes
the top-level default theme config, it will be added back again later
## @sanity/plugin-kit@10.0.11

### Patch Changes

- [#2047](#2047)
[`89bbaf7`](89bbaf7)
Thanks [@stipsan](https://github.com/stipsan)! - Update the optional
`oxfmt` peer dependency to ^0.71.0

- [#2047](#2047)
[`89bbaf7`](89bbaf7)
Thanks [@stipsan](https://github.com/stipsan)! - The
`@sanity/plugin-kit/oxfmt` preset no longer formats `.changeset/*.md`
files with double quotes, so their frontmatter gets single quotes like
the rest of your code. Changesets 3 formats the changesets it writes
with oxfmt when it finds your `oxfmt.config.ts`, or when
`.changeset/config.json` sets `"format": "oxfmt"`, so they come out the
same way.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Themer’s minor release documents a breaking-adjacent removal of
default theme config; plugin-kit is tooling-only but may change how
changeset files format in repos using the oxfmt preset.
> 
> **Overview**
> This is a **Changesets release** PR that publishes two npm packages by
bumping versions, folding pending changesets into each package’s
`CHANGELOG.md`, and deleting the consumed `.changeset/*.md` files.
> 
> **`@sanity/plugin-kit@10.0.11`** (patch): release notes record a bump
of the optional `oxfmt` peer to `^0.71.0` and a tweak to the
`@sanity/plugin-kit/oxfmt` preset so `.changeset/*.md` frontmatter uses
single quotes, aligning with Changesets 3 when oxfmt is enabled.
> 
> **`@sanity/themer@0.9.0`** (minor): release notes cover adopting React
`<Activity>`, `<ViewTransition>`, and `React.lazy` patterns, and
**removing the top-level default theme config** (called out as temporary
until it returns).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7b2b0b2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: squiggler-app[bot] <265501495+squiggler-app[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview – plugins-studio — 123af257 Deployed Sep 29, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants