Skip to content

feat(gamut-codemods): add @skillsoft/gamut-codemods with a scope-swap preset - #28

Draft
dreamwasp wants to merge 65 commits into
mainfrom
cass-gmt-1790
Draft

dreamwasp wants to merge 65 commits into
mainfrom
cass-gmt-1790

Conversation

@dreamwasp

@dreamwasp dreamwasp commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Adds @skillsoft/gamut-codemods, a jscodeshift CLI that moves consumers from @codecademy/gamut* to @skillsoft/gamut*, along with the breaking Menu/SelectDropdown renames it depends on.

Warning

b1b91a74f adds cass-gmt-1795 to preview.yml so this PR can publish a pkg.pr.new preview. It's temporary. Revert it before either branch ships to main.

Codemod (@skillsoft/gamut-codemods)

  • npx @skillsoft/gamut-codemods scope-swap . runs the scope-swap preset.
  • Renames every module string: imports, exports, require, import(), jest.mock/vi.mock, declare module, import('x').T, and exact package strings like transpilePackages, with one warning per file.
  • Moves Video/VideoProps imports to @skillsoft/gamut/Video.
  • Maps /dist/ deep imports to public entry points and warns where none exists.
  • Replaces @codecademy/gamut-kit in package.json and Module Federation shared config.
  • Updates the ESLint plugin prefix in directive comments and .eslintrc(.json).
  • Refuses to run on a dirty tree unless --force is passed. Ends with a leftovers report and a next-steps checklist.

Codemod structure

  • Presets are one upgrade each: a data manifest plus an ordered list of reusable migrations.
  • Most changes are data (a manifest row and a fixture).
  • String swaps are splice edits on the original text. Recast reprinted neighbouring statements in semicolon-less files and changed JSX text in the spike, so it isn't used for these.
  • manifest.test.ts type-checks every export a manifest points at against the built packages, and checks target versions against the changesets fixed group.

Breaking renames (@skillsoft/gamut)

  • Adds the Menu and SelectDropdown renames that upstream GMT-1740 held back (Codecademy/gamut 009aa43f6).
  • Renames List/ListItem/ListLink/ListButton (and their props) to MenuList*, and IconOption (the component) to IconOptionComponent. The old names would collide with the root List component and IconOption type.
  • Adds MenuToolTipWrapper as a public export. The IconOption type is unchanged.
  • Root export snapshot adds exactly 6 runtime names. Changeset is minor per CONTRIBUTING's 0.x rule.
  • The codemod keeps local names (import { List } becomes import { MenuList as List }).
  • ButtonBase stays private. The codemod still warns on dist/ButtonBase/ButtonBase deep imports.

Fixes from a type-checked run against mono

  • @skillsoft/gamut/Video failed under moduleResolution: "node". Adds a Video/package.json stub, the same approach upstream uses, and removes the attw no-resolution ignore that was hiding it.
  • Adds root exports formFieldStyles, formFieldPaddingStyles, conditionalStyles, plus the HTMLToReactNode and ButtonBaseProps types.
  • package-json no longer overwrites @skillsoft/* entries that are already listed (such as preview URLs). It had been writing ^0.0.1, which 404s. * peer ranges stay *.
  • Deep-import rows that are only partly public list their public names (onlyNames). A new test fails if any row could rewrite a name its target doesn't export.
  • Adds mdx-imports, yarnrc, and tsconfig-dom migrations.

Install surface (46ad288ed)

  • Consumers now need only react, react-dom, @emotion/react, and @emotion/styled alongside @skillsoft/gamut.
  • gamut-styles: stylis, lodash, and @emotion/cache move from peers to dependencies.
  • gamut-icons: drops the unused lodash peer. variance: typescript peer is optional.
  • @skillsoft packages depend on each other with ^ ranges, so installs share one gamut-styles.
  • Third-party exact pins stay. Loosening them re-resolved react-aria-components from 1.7.1 to 1.21.1, which should be tested separately.

Versioning

  • gamut-codemods, gamut-illustrations, and gamut-tests join the changesets fixed group, so all consumer-facing packages share one version (currently 0.0.1).
  • Changeset: @skillsoft/gamut-codemods minor.

PR Checklist

  • Related to designs: N/A
  • Related to JIRA ticket: GMT-1790 (inferred from branch name)
  • Version plan added/updated
  • I have run this code to verify it works
  • This PR includes unit tests for the code change
  • This PR includes testing instructions for the code change

Testing Instructions

  1. yarn nx test gamut-codemods (33 tests, including fixture idempotence and the manifest type-check against built dist) and yarn nx test gamut (1,276 tests, export snapshot updated).
  2. Build the packages, then run the CLI against a throwaway copy of a consumer repo that has @codecademy/gamut imports, including an MDX story and a Video import: npx <built-cli> scope-swap <copy>. Confirm imports, package.json, and .eslintrc are rewritten, and that the leftovers report and warnings look right.
  3. Confirm the dirty-tree guard: edit a file in the copy without committing and rerun. It should refuse unless --force is passed.
  4. In a fresh project, install the packed @skillsoft/gamut tarball with only the four required peers. The only peer warning should be the implicit @types/react.
  5. Check the Menu rename: import { MenuList, IconOptionComponent } from '@skillsoft/gamut' resolves and type-checks.

https://github.com/codecademy-engineering/mono/pull/13803

https://github.com/codecademy-engineering/mono/pull/13834

dreamwasp and others added 30 commits September 16, 2026 10:30
…ut-tests

None of these three packages declared a `sideEffects` field, which is the
most conservative default: webpack must assume every module in the barrel
is side-effectful and cannot drop unused exports. That currently applies to
the packages everything else depends on.

Verified safe to mark `sideEffects: false`:
- no module-level `document`/`window` access or `injectGlobal` in either
  package's source
- gamut-styles' globals/{Reboot,Variables,Typography}.tsx and
  GamutProvider.tsx use Emotion's `<Global>` component, which runs at
  render time inside React, not at module evaluation
- AssetProvider.tsx's createFontLinks is an exported function, not a
  module-eval call

This is PR 0a of the tsdown migration plan (GMT-1741) — a standalone fix
for a live tree-shaking bug on the current Babel build, landing ahead of
the build-tooling change. gamut and gamut-illustrations carry a separate,
deliberately-added sideEffects glob (added in #932 to fix real style-order
drift) that needs a CSS-diff experiment before it can be safely removed;
that's scoped to PR 0b.

Verified: `yarn build`, `jest --selectProjects gamut-styles variance
gamut-tests` (181/181 passing), and `yarn build-storybook` (production
webpack build) all succeed unchanged.
Replaces `babel ./src --out-dir ./dist` with `tsdown` for JS, keeping the
existing `tsc --emitDeclarationOnly` step for declarations (the hybrid).
Chain must migrate atomically (variance -> gamut-styles -> gamut) — a
half-migrated chain doesn't load, because Babel's ESM output has
extensionless relative specifiers that Node's own resolver rejects.

- dts: false in every tsdown.config.ts; tsc keeps emitting declarations
  into the same dist/ (clean: false in tsdown, single `rm -rf ./dist` at
  the head of the build target owns cleaning). Bundled tsdown
  declarations were tried and rejected: 50x TS4023 downstream, since a
  bundled .d.ts doesn't re-export names its dependents need.
- No external/deps.neverBundle needed for variance or gamut-styles —
  tsdown auto-externalizes anything in a package's own `dependencies` /
  `peerDependencies`, which already covers everything they import.
  gamut needs one exception: `deps.neverBundle: [/\.css$/]`, since tsdown
  refuses to bundle a relative .css import without @tsdown/css, and
  externalizing it matches the current cpy-based approach exactly.
- Output naming: since none of these packages set `"type": "module"`,
  tsdown names CJS `dist/index.js` and ESM `dist/index.mjs` (not
  `.cjs`/`.mjs` as sketched in early spike notes) — package.json
  `exports`/`main`/`module`/`types` updated to match the real filenames.
  Kept `main`/`types` accurate (not just `exports`), since this repo's
  tsconfig.base.json uses legacy `moduleResolution: "node"`, which
  ignores `exports` entirely for internal cross-package typechecking.
- gamut-styles: added the missing `types` field and dropped `files`
  entries (core, utils, core.scss, utils.scss) that don't exist on disk.
- gamut: sideEffects reduced to `["**/*.css", "**/*.scss"]` (the two
  `dist/**/[A-Z]**/*.js` globs from #932 are now dead — they matched
  gamut's old per-file dist shape, which no longer exists). Re-verify
  with the CSS-diff + esbuild single-import probe from the sideEffects
  investigation once the leaf packages (icons/patterns/illustrations)
  are also migrated, since gamut's own barrel depth was masking whether
  this field does anything until now.
- BarChart/BarRow/elements.tsx: `@emotion/babel-plugin` stamps a `target`
  on every styled() call unconditionally, and `target` is what makes the
  `${CategoryLabel}` component-selector interpolation work. The plugin
  only runs on the babel path now (jest/Storybook loader), not through
  tsdown, so this is the one site that needs an explicit target to avoid
  a silent `.undefined` fallback in the production bundle. Verified in
  the built dist/index.js: `target: "gmt-category-label"` survives.
- tsconfig.base.json: isolatedModules: true, ratcheting against the
  type-only re-export debt rolldown can't see through (verified 0 errors
  across every build-relevant package before enabling).
- gamut build:watch now runs `tsdown --watch` instead of a full rebuild
  on every source change (watch mode is otherwise unverified — worth
  confirming latency once used for real).

Verified: `yarn nx run-many --target=build --projects=variance,gamut-styles,gamut`,
full jest suite for all four affected packages (1457/1457 passing),
`yarn verify` (isolatedModules didn't break typecheck anywhere), and
direct CJS `require()` of variance's and gamut-styles' dist output.
gamut's own CJS load still fails via require() — but only because it
transitively depends on gamut-icons, which is still Babel-built and has
a pre-existing (unrelated) ERR_UNSUPPORTED_DIR_IMPORT under Node's
require(esm); confirmed identical failure on the untouched dist before
this change. Resolves once gamut-icons migrates next.

Part of the tsdown build migration (GMT-1741).
…ns, gamut-tests

Same hybrid pattern as the previous commit (tsdown for JS, tsc for
declarations), applied to the four remaining Babel-built packages. Nothing
depends on these, so they could lag the dependency chain — but since
gamut itself depends on gamut-icons/gamut-patterns/gamut-illustrations,
finishing them now is what actually resolves gamut's own CJS load (the
previous commit's ERR_UNSUPPORTED_DIR_IMPORT was gamut-icons transitively,
not gamut).

SVGR steps (icon/pattern codegen, the `-icon.svg` rename) are untouched —
tsdown/rolldown only replaces the babel step in each pipeline.

## unbundle: true, added to every package (retroactively, including the
## previous commit's three)

A single-component import probe (`import { FillButton } from
'@skillsoft/gamut'`, bundled with esbuild) found the default tsdown output
— one concatenated dist/index.mjs per package, root-only entry — pulls in
100% of that file's ~428KB plus every heavy dependency any of gamut's ~130
exports uses transitively (@vidstack/react, gamut-icons' whole barrel,
react-aria-components, framer-motion, @formatjs/*, react-select): 1.59MB
for one button, 15x today's Babel-build baseline of 103KB. Same problem on
gamut-icons: importing one icon pulled in all 377 (586KB).

`unbundle: true` (tsdown mirrors src/ file-by-file instead of
concatenating) fixes it completely — 112KB for the gamut probe, 73KB for
the icon probe, both at or below the Babel baseline — while keeping
tsdown's real relative-import extensions (.mjs/.js, not Babel's
extensionless ones) and the speed win. Applied to all seven packages for
consistency; the failure mode is structural (one shared module scope), not
size-dependent, so there's no reason to leave any package on the default.

One benign side effect, checked: unbundle's finer-grained CJS module graph
surfaces a pre-existing circular import in Tip's style utilities as a
Node "accessing non-existent property inside circular dependency" console
warning. Confirmed not a functional bug — the values are only read inside
function bodies, never captured at module-eval time, so by call time the
cycle has resolved; verified by requiring the built module directly and
calling it, real style values came back.

## Storybook deep imports into /src broke — and revealed Storybook doesn't
## actually consume any package's dist

packages/styleguide/.storybook/main.ts already aliases every bare
`@skillsoft/gamut*` specifier straight to that package's `../src`
directory (exact-match, `$`-anchored). That means Storybook has never
consumed built dist output, for any package, independent of this
migration — it only compiles raw TypeScript source through webpack. The
"Storybook proves the dist/exports map works" framing from earlier in
this migration doesn't hold; it only incidentally caught real breaks
because a handful of imports carry an extra `/src` path segment that
doesn't match the bare-specifier alias, so those specific ones fall
through to real node_modules -> exports resolution.

13 such imports broke once the exports map went strict:
- 7 were lazy — the symbols they wanted are already exported at the
  package root (theme, trueColors, Box, FillButton, etc). Fixed by
  importing from the root, matching the codebase's own
  `@skillsoft/gamut/import-paths` eslint rule.
- 6 reach into genuinely internal groupings with no public equivalent
  (icon categories, raw typography variant metadata, the full
  system-props registry for a docs table) — each already carried an
  acknowledged `// eslint-disable-next-line @skillsoft/gamut/import-paths`
  comment, pre-existing debt this migration surfaced rather than
  introduced. Fixed with four new Storybook-only webpack aliases pointing
  at the same monorepo source paths, keeping every package's `exports`
  map an honest description of its published surface instead of growing
  it to fit docs tooling.

Verified: full `yarn build`/`yarn test`/`yarn verify` (10 projects, 1276
tests), direct CJS `require()` of all seven packages' dist output
(matching export counts throughout), `yarn build-storybook` +
`nx run styleguide:storybook-test` (87 suites / 493 tests, including the
icon galleries and typography-variant table the new aliases unblock), and
a 493-story Emotion-CSS diff across sideEffects on vs. off — byte-identical
(0 differences), now under real tree-shaking (unbundle mode), confirming
the 2020 style-order bug (#932) genuinely doesn't reproduce under Emotion
11, not just that it was unreachable to test.

Part of the tsdown build migration (GMT-1741).
…olver, lint rule)

Closes out the remaining PR 1 verification scaffolding from the tsdown
migration plan (GMT-1741): the automated guard that substitutes for
having real published consumers to catch a broken exports map.

## verify-package nx target (publint + attw), all seven packages

Added `publint .` and `attw --pack . --ignore-rules false-cjs` as a new
`verify-package` target, depending on `build`, on every tsdown-migrated
package.

`--ignore-rules false-cjs` suppresses one accepted, deliberate tradeoff
of the hybrid build: attw flags "masquerading as CJS" because a single
shared `dist/index.d.ts` serves both the `import` and `require`
conditions (tsc only emits one declaration tree, not per-format
`.d.mts`/`.d.cts` copies). That only affects `moduleResolution: node16`/
`nodenext` consumers importing via ESM syntax — this repo's own
tsconfig.base.json uses legacy `moduleResolution: "node"`, and the
bundler profile (the actual consumption path) is unaffected. Splitting
declarations per format to satisfy this would mean tsc emitting twice
the output for a benefit no current consumer needs.

Tried adding `"type": "commonjs"` per publint's own suggestion (removes
a minor Node startup perf-hit note) and had to revert it immediately —
it broke tsdown's own ability to load `tsdown.config.ts`, which uses ESM
`import` syntax and lives in the same directory. Every package's config
file depends on the "type" field staying unset; verified by testing the
change, watching `variance:build` fail with "Cannot use import statement
outside a module", and reverting across all seven packages.

## script/verify-exports.mjs

Resolves every package's `exports` map from the repo root the way a real
consumer would: asserts the root subpath resolves AND loads via both
`require()` and `import()`, and asserts old deep `dist/*` paths are
blocked with ERR_PACKAGE_PATH_NOT_EXPORTED.

The ESM `import()` check surfaced a real, pre-existing gap: variance (and
everything depending on it) imports lodash via extensionless deep
subpaths (`lodash/get`, not `lodash/get.js`). lodash ships no `exports`
map, so Node's native ESM resolver — unlike `require()`, and unlike every
bundler's resolver (webpack/esbuild/rollup all probe extensions) —
refuses it outright. This is inherent to lodash's own packaging, predates
this migration, and only matters for a consumer running raw Node ESM
with no bundler in front, which isn't a real path for any package here.
Fixing it means rewriting ~25 files' lodash imports across 5 packages;
scoped out as a fast-follow rather than blocking here. The script treats
it as a clearly-flagged warning, not a failure.

## eslint rule: require-styled-target-for-selector

Codifies the BarChart `target` fix from the first tsdown-migration commit
as an enforced rule, added to `recommended.ts`. Flags a `styled()` call
used via `${Component}` interpolation in a computed style-object key
that has no explicit `target` — the exact silent-`.undefined`-in-production
failure mode `@emotion/babel-plugin` used to paper over automatically.

Verified against the real gamut/gamut-styles/gamut-icons/gamut-patterns/
gamut-illustrations source with `--no-inline-config` (ignoring existing
disable comments): zero violations, confirming BarChart was the only
site and there's nothing else to fix.

## CI

Wired `verify-package` and `verify-exports.mjs` into the storybook-test
job's build step, ahead of the Storybook build.

Verified: full `yarn build`/`yarn test`/`yarn verify`, `yarn nx run-many
--target=verify-package --all` (7/7 clean), `node script/verify-exports.mjs`
(all checks passed, lodash gap flagged not failed), and the new eslint
rule's test suite (60/60 passing across the whole plugin).

Part of the tsdown build migration (GMT-1741).
… into cass-gmt-1741

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
The root tsconfig.json (not used by any real build — every package
verifies against its own scoped tsconfig via cwd) is what editors like
Zed fall back to for files no package-scoped tsconfig covers, which
today means tsdown.config.ts / tsdown.base.ts. Two problems stacked:

- The literal `.ts` extension on `import { baseConfig } from
  '../../tsdown.base.ts'` (required because tsdown's own config loader
  needs it) needs `allowImportingTsExtensions`, which itself requires
  `noEmit` or `emitDeclarationOnly`.
- tsdown itself ships no `main`/`types` fields, only a modern `exports`
  map, so it's completely unresolvable under the inherited
  `moduleResolution: "node"` — confirmed via tsc's own error message.

Scoped to this one root config, not tsconfig.base.json (which every
package inherits) — verified no real build/verify script uses the bare
root config, so this only affects editor diagnostics for the tsdown
config files, with zero effect on any package's real typecheck.

Part of the tsdown build migration (GMT-1741).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	packages/styleguide/.storybook/main.ts
#	yarn.lock
…babelrc

All 7 packages' babel.config.js had a byte-identical `presets` array
(preset-env + preset-react + preset-typescript), differing only in
whether @emotion/babel-plugin was added. Babel's own `extends` merges
arrays rather than overriding them, so moving the shared presets into
babel.defaults.js (which every package already extends, for its
`ignore` patterns) lets each package's own config shrink to just what's
actually different for it — the emotion plugin, or nothing at all.

Verified the merge behavior directly rather than assuming it: ran
@babel/core's transformFileSync against a real gamut-icons component
(JSX transform + TS stripping both applied) and a real gamut-styles
styled() call (target + label stamping both present) with the package's
own config reduced to bare `extends`. Confirmed with the full suite too:
build/test/verify all green, 117 test suites / 1563 tests with jest
cache cleared, and the BarChart Emotion-target site specifically
re-checked given its history this migration.

Also dropped gamut-tests' bogus top-level `include: ['./src/**/*']` key
while simplifying that file — a no-op given babel's only ever invoked
against files already under ./src.

Removed packages/styleguide/.babelrc.json — genuinely dead now that
Storybook's Vite migration (main #9) wires @emotion/babel-plugin
directly via @vitejs/plugin-react's babel option in .storybook/main.ts,
rather than reading this file. Confirmed nothing else discovers it
(no jest config references styleguide; it has no test target).

Part of the tsdown build migration (GMT-1741).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Storybook's Vite preview now uses @vitejs/plugin-react-swc +
@swc/plugin-emotion instead of @vitejs/plugin-react + @emotion/babel-plugin,
removing Babel from Storybook's build pipeline. Speeds up the dev-loop HMR
turnaround (~3-5x faster per-edit in local measurement); cold
build-storybook time is roughly a wash.

@vitejs/plugin-react-swc, @swc/plugin-emotion, and the @swc/core resolution
are pinned to versions from the same release window (June-July 2026) rather
than latest - newer combinations crash with an undocumented WASM/ABI
mismatch between the plugin and swc_core. Bump these three together.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Keep the Storybook SWC Emotion plugin from this branch; take main's
prettier/lint formatting and Storybook interaction/a11y test updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
Base automatically changed from cass-gmt-1795 to main October 14, 2026 19:42
const files = fs.statSync(root).isDirectory() ? walk(root) : [root];
for (const file of files) {
for (const migration of active) {
if (!migration.match(file)) continue;
@codecov

codecov Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.16143% with 8 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@b3b7251). Learn more about missing BASE report.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...s/gamut-codemods/src/migrations/mf-shared/index.ts 95.83% 2 Missing ⚠️
...mut-codemods/src/migrations/moved-exports/index.ts 98.09% 2 Missing ⚠️
packages/gamut-codemods/src/cli.ts 99.06% 1 Missing ⚠️
packages/gamut-codemods/src/lib/package-ranges.ts 95.83% 1 Missing ⚠️
...amut-codemods/src/migrations/deep-imports/index.ts 98.96% 1 Missing ⚠️
packages/gamut-codemods/src/presets/index.ts 93.75% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #28   +/-   ##
=======================================
  Coverage        ?   92.19%           
=======================================
  Files           ?      410           
  Lines           ?     7416           
  Branches        ?     2369           
=======================================
  Hits            ?     6837           
  Misses          ?      570           
  Partials        ?        9           
Flag Coverage Δ
pull-request 92.19% <99.16%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

dreamwasp and others added 16 commits October 16, 2026 10:04
…g, warn on newer-than-source deps, add next-config migration

- Migrations can declare skipReason(); the CLI skips them for the run and notes it in the checklist.
- eslint-comments is skipped when a flat config is present, since the rule prefix follows the plugins key there.
- Leftover scanning ignores quoted gamut/ rule keys under a flat config, and checks .mdc, .code-snippets and extensionless scripts.
- package-json warns when a consumer range is newer than the last upstream release we forked from (manifest.sourceVersions).
- Adds a next-config migration for esmExternals: false.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
A deep import rewritten to the package root often lands next to an
existing import from that root, which trips import/no-duplicates. Fold
each rewritten declaration into the first plain named import of the same
source and kind. Imports the file already had are never merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Codecademy/gamut 74.0.0 already made the Markdown change: iframes and
videos only render through Video when iframeOverride / videoOverride are
passed. A repo on 74+ has either passed them or left them out on purpose,
so adding them would turn iframes back on where they were meant to be off.

skipReason now gets the manifest, and the migration skips itself when
every readable @Codecademy/gamut range in the repo's package.json files is
74.0.0 or newer. `*`, URL, and workspace: ranges are ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onfig

Older builds rewrote `gamut/` directives to `@skillsoft/gamut/` even when a
flat config registers the plugin as `gamut`. Those directives name a rule
that doesn't exist and stop suppressing the real one, and a newer run
skips eslint-comments, so nothing caught them.

Under a flat config, leftovers now include `@skillsoft/gamut/` directives
unless some file registers the plugin under that key. Leftovers can carry
a note explaining why a line is listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JSDoc `@see` lines and usage examples kept the old names, so every one
showed up as a leftover to fix by hand. scope-rename now renames them too.
`/dist` paths and removed packages stay in the leftovers report, since no
rename is right for them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w checks

- Fix the flat-config guidance: directives keep the plugins key prefix.
- Add warning rows for markdown-video-overrides, newer-than-source, and
  next-config, and note skipped migrations.
- Add a section on repos swapped by an older codemod build.
- Add common failures for stale installs and unmerged or unsorted imports,
  and the gamut-kit version scripts that break CI.
- README: describe the import merge, the 74.0.0 skip, and comment renames.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`configs.recommended` was typed with `string` severities, which isn't
assignable to ESLint's Plugin type, so `plugins: { gamut }` failed to
type-check in a typed flat config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The published types import from csstype. It only resolved because
@skillsoft/variance depends on it, which breaks under strict installs
like pnpm or Yarn PnP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The "add markdown scope" merge (98fe229) put @skillsoft/gamut's
dependencies on gamut-icons, gamut-illustrations, gamut-patterns,
gamut-styles, and variance back to exact 0.0.1, undoing the
consumer-friendly-deps change. Exact pins make installs pull a second copy
of gamut-styles and variance whenever versions drift.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Yarn keeps the first build it fetched for a `@<pr>.tgz` URL in the
lockfile and global cache, so later pushes to the PR don't install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It was listed in both dependencies and devDependencies after the "add
markdown scope" merge. Keep it a regular dependency, as upstream has it,
and drop the changeset bullet that said it moved to devDependencies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gain

Moving them to dependencies gave gamut-styles its own stylis 4.4.0 while
@emotion/cache pins 4.2.0. Gamut's prefixer then ran inside Emotion's
copy and crashed (BAM teams.spec, e2e homepage 500). As peers, consumers
share one copy of each, matching the package before the change.

The scope-swap checklist now tells users to add both if yarn warns.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

2 participants