basalt-ui 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/MIGRATING.md +33 -14
- package/agent/skills/basalt-app/SKILL.md +1 -1
- package/dist/cli/config.d.ts +4 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +6 -0
- package/dist/cli/doctor-upgrade.d.ts +12 -0
- package/dist/cli/doctor-upgrade.d.ts.map +1 -1
- package/dist/cli/doctor-upgrade.js +46 -1
- package/dist/cli/doctor.d.ts +2 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +8 -1
- package/llms.txt +2 -2
- package/package.json +4 -4
- package/src/cli/config.ts +12 -0
- package/src/cli/doctor-upgrade.ts +65 -0
- package/src/cli/doctor.ts +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [2.0.1](https://github.com/jkrumm/basalt-ui/compare/v2.0.0...v2.0.1) (2026-10-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* close argo friction rows 1-3 ([41627c3](https://github.com/jkrumm/basalt-ui/commit/41627c328ad278fc303ca9317cada2d2ab5f99a4))
|
|
7
|
+
|
|
1
8
|
# [2.0.0](https://github.com/jkrumm/basalt-ui/compare/v1.41.0...v2.0.0) (2026-10-14)
|
|
2
9
|
|
|
3
10
|
|
package/MIGRATING.md
CHANGED
|
@@ -66,18 +66,18 @@ There is one row per SURFACE, not per export, and a surface earns a row once any
|
|
|
66
66
|
shipped lefthook preset both changed in 1.30.0 with no row that owned them — which is how a
|
|
67
67
|
consumer read this index, found nothing, and diffed a KPI row that had silently gone 4-up → 2-up.
|
|
68
68
|
|
|
69
|
-
| Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | 1.39.0 | 1.40.0 | 1.40.1 | 1.40.2 | 1.40.3 | 1.41.0 | 2.0.0 | Unreleased |
|
|
70
|
-
| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | ------ | ------ | ------ | ------ | ------------------------------------------------------------ | ---------- | --- | --- |
|
|
71
|
-
| **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — | — | — | — | — | — | — | — |
|
|
72
|
-
| **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
73
|
-
| **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — | — | — | — | — | — | — | — |
|
|
74
|
-
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
75
|
-
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
76
|
-
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
77
|
-
| **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
78
|
-
| **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
79
|
-
| **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | the managed block moves `CLAUDE.md` → `AGENTS.md` (§ 1.41.0) | — | — |
|
|
80
|
-
| **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
69
|
+
| Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | 1.32.1 | 1.33.0 | 1.34.0 | 1.34.1 | 1.35.0 | 1.36.0 | 1.36.1 | 1.37.0 | 1.37.1 | 1.38.0 | 1.38.1 | 1.39.0 | 1.40.0 | 1.40.1 | 1.40.2 | 1.40.3 | 1.41.0 | 2.0.0 | 2.0.1 | Unreleased |
|
|
70
|
+
| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------- | ------ | ------ | -------------------------------------------------------------------------------------------- | ------ | ------ | ------ | ------ | ------ | ----------------------------------------------- | ------ | ------ | ------ | ------ | ------------------------------------------------------------ | ---------- | --- | --- | --- |
|
|
71
|
+
| **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | `CONTAINER_KEYS` (§ 1.34.0) | — | — | — | — | — | — | — | | `appShellInset` 20 → 16 (§ 1.38.1) | — | — | — | — | — | — | — | — | — |
|
|
72
|
+
| **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
73
|
+
| **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | `useBreakpoint` removed (§ 1.34.0) | — | — | `useCoarsePointer()` (§ `useCoarsePointer()`) | — | — | — | — | | content gutter 16, block 8 from `sm` (§ 1.38.1) | — | — | — | — | — | — | — | — | — |
|
|
74
|
+
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — | — | — | `FormSection`/`FormRow`/`FormGroup`/`FormActions` move here (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
75
|
+
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — | — | — | the layout + `useForm`/`schemaResolver` deprecated, removed 1.37.0 (§ The form layout moves) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
76
|
+
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
77
|
+
| **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
78
|
+
| **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
79
|
+
| **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | the managed block moves `CLAUDE.md` → `AGENTS.md` (§ 1.41.0) | — | — | — |
|
|
80
|
+
| **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — | — | — | `unknown-vx-token` → `error`; the token factories throw (§ Guards) | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
|
81
81
|
|
|
82
82
|
---
|
|
83
83
|
|
|
@@ -88,8 +88,10 @@ Contract: `docs/V2-SPEC.md`. Every removal and move is one row, grouped by area.
|
|
|
88
88
|
### Upgrading from 1.x
|
|
89
89
|
|
|
90
90
|
1. Go to `1.41.0` first and clear its deprecations: 2.0 retires the lifecycle, so nothing deprecated survives.
|
|
91
|
-
2. Install `basalt-ui@2` and the now-required peers (§ Subpaths, peers and gates); delete
|
|
92
|
-
`@mantine
|
|
91
|
+
2. Install `basalt-ui@2` and the now-required peers (§ Subpaths, peers and gates); delete only the
|
|
92
|
+
`@mantine/{core,notifications,spotlight}/styles.layer.css` imports, because `basalt-ui/styles.css`
|
|
93
|
+
`@import`s exactly those three. Keep every extension package's layer CSS (`@mantine/dates`,
|
|
94
|
+
`@mantine/schedule`, …) imported AFTER `basalt-ui/styles.css`.
|
|
93
95
|
3. Replace the hand-built root (providers, `QueryClient`, router) with `BasaltProvider` +
|
|
94
96
|
`createBasaltRouter` (§ Provider and wiring).
|
|
95
97
|
4. Rewrite imports by area, using the tables below. A `move` changes only the specifier.
|
|
@@ -990,6 +992,23 @@ optional, subpath-required peers.
|
|
|
990
992
|
_Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
|
|
991
993
|
release renames it and opens a new one here._
|
|
992
994
|
|
|
995
|
+
## 2.0.1
|
|
996
|
+
|
|
997
|
+
_Nothing to migrate in this release._
|
|
998
|
+
|
|
999
|
+
## Next patch — doctor reads the peers and the config
|
|
1000
|
+
|
|
1001
|
+
- `doctor` gains `exact-peers`: for each exact-pinned peer of the installed basalt-ui (the three
|
|
1002
|
+
`@fontsource-variable/*`, `motion`, `remend`, …) it compares your installed version and prints a
|
|
1003
|
+
one-line `bun add <pkg>@<version>` fix on a mismatch. `bun add` accepts the mismatch silently.
|
|
1004
|
+
The three font peers now pin `5.3.0`.
|
|
1005
|
+
- `doctor` gains `config-keys`: a key in the package.json `basalt` object that the config does not
|
|
1006
|
+
read fails with its fix. `basalt.chartMissingAriaLabel` is gone with its guard kind; `ariaLabel`
|
|
1007
|
+
is required on a chart now, so delete the key.
|
|
1008
|
+
- Corrected the § 2.0 "Upgrading from 1.x" step 2: delete only the core, notifications and
|
|
1009
|
+
spotlight layer imports; extension packages (`@mantine/dates`, `@mantine/schedule`) stay, after
|
|
1010
|
+
`basalt-ui/styles.css`.
|
|
1011
|
+
|
|
993
1012
|
## 2.0.0
|
|
994
1013
|
|
|
995
1014
|
_Nothing to migrate in this release._
|
|
@@ -26,7 +26,7 @@ declare module '@tanstack/react-router' {
|
|
|
26
26
|
createRoot(document.getElementById('root')!).render(<BasaltProvider router={router} />)
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
3.
|
|
29
|
+
3. Import extension layer CSS (`@mantine/dates` for `basalt-ui/controls-dates`, `@mantine/schedule`) after `basalt-ui/styles.css` (core must precede them in `@layer mantine`).
|
|
30
30
|
4. Install the peers of each subpath you import: read its `Install: bun add …` line in `node_modules/basalt-ui/llms.txt`; a subpath with no `Install:` line needs only the required peers listed at the top of that file.
|
|
31
31
|
5. In `vite.config.ts` spread `...basaltViteConfig({ port, apiTarget })` and register, in this order, `plugins: [tanstackRouter({ target: 'react', autoCodeSplitting: true }), react(), ...basaltAppPlugin({ name, description })]`. Run `bun add -d @tanstack/router-plugin` and import `tanstackRouter` from `@tanstack/router-plugin/vite`.
|
|
32
32
|
6. Run `vite build` once so the plugin writes `src/routeTree.gen.ts`; commit it (`tsc -b` fails without it).
|
package/dist/cli/config.d.ts
CHANGED
|
@@ -165,4 +165,8 @@ export declare const DEFAULT_ROOTS: string[];
|
|
|
165
165
|
* "matches zero files" break this derivation exists to prevent.
|
|
166
166
|
*/
|
|
167
167
|
export declare function resolveRoots(cfg: BasaltConfig): string[];
|
|
168
|
+
/** Every `BasaltConfig` key, as data for `doctor`'s `config-keys` (a test pins it to the type). */
|
|
169
|
+
export declare const BASALT_CONFIG_KEYS: (keyof BasaltConfig)[];
|
|
170
|
+
/** Keys removed from `BasaltConfig`, with the reason `doctor` prints. */
|
|
171
|
+
export declare const RETIRED_CONFIG_KEYS: Readonly<Record<string, string>>;
|
|
168
172
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/cli/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExD,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG;IACzB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IACnC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;wFACoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAA;IACpD,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,CAAA;IACzD;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5E,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,EAAE,CAG5E;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAGlF;AAED,eAAO,MAAM,YAAY,QAAQ,CAAA;AACjC,eAAO,MAAM,aAAa,UAAiB,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE,CAExD"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/cli/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExD,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG;IACzB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,aAAa,CAAA;IACnC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;wFACoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAA;IACpD,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,CAAA;IACzD;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5E,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,EAAE,CAG5E;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAGlF;AAED,eAAO,MAAM,YAAY,QAAQ,CAAA;AACjC,eAAO,MAAM,aAAa,UAAiB,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,EAAE,CAExD;AAED,mGAAmG;AACnG,eAAO,MAAM,kBAAkB,EAIf,CAAC,MAAM,YAAY,CAAC,EAAE,CAAA;AAEtC,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEhE,CAAA"}
|
package/dist/cli/config.js
CHANGED
|
@@ -11,9 +11,15 @@ const DEFAULT_ROOTS = [DEFAULT_ROOT];
|
|
|
11
11
|
function resolveRoots(cfg) {
|
|
12
12
|
return cfg.roots?.length ? cfg.roots : DEFAULT_ROOTS;
|
|
13
13
|
}
|
|
14
|
+
const BASALT_CONFIG_KEYS = "roots exempt profile include spacingSteps severity forbiddenAccents accentHue rawRadius rawSurface cardWithBorder offSystemSurfaceVar mantineShadeIndex rawHtmlLayout inlineSpacing inlineDisplay rawMotionValue rawFormControl sub16InputFont seriesModulePath exemptRules aiMajorSkewReason".split(" ");
|
|
15
|
+
const RETIRED_CONFIG_KEYS = {
|
|
16
|
+
chartMissingAriaLabel: "its guard kind is gone in 2.0 (`ariaLabel` is required on a chart now)"
|
|
17
|
+
};
|
|
14
18
|
export {
|
|
19
|
+
BASALT_CONFIG_KEYS,
|
|
15
20
|
DEFAULT_ROOT,
|
|
16
21
|
DEFAULT_ROOTS,
|
|
22
|
+
RETIRED_CONFIG_KEYS,
|
|
17
23
|
exemptRulePaths,
|
|
18
24
|
exemptRuleReason,
|
|
19
25
|
resolveRoots
|
|
@@ -28,4 +28,16 @@ export declare function seedTsconfigExtends(cwd: string): string | null;
|
|
|
28
28
|
* proves nothing.
|
|
29
29
|
*/
|
|
30
30
|
export declare function appWiringCheck(cwd: string): Check;
|
|
31
|
+
/**
|
|
32
|
+
* `config-keys`: a key in package.json's `basalt` object that `BasaltConfig` does not declare is
|
|
33
|
+
* silently ignored, so a key retired in 2.0 keeps looking configured. Reads the raw file, not
|
|
34
|
+
* `readBasaltConfig`, which is typed and would hide the very keys this looks for.
|
|
35
|
+
*/
|
|
36
|
+
export declare function unknownConfigKeysCheck(cwd: string): Check;
|
|
37
|
+
/**
|
|
38
|
+
* `exact-peers`: basalt-ui pins some peers to one exact version, and `bun add` accepts any other
|
|
39
|
+
* version without a word. Compares each installed one against the install's declared pin; a peer
|
|
40
|
+
* that is not installed is not this check's business (optional peers are legitimately absent).
|
|
41
|
+
*/
|
|
42
|
+
export declare function exactPeersCheck(cwd: string, install: BasaltInstall): Check;
|
|
31
43
|
//# sourceMappingURL=doctor-upgrade.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-upgrade.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-upgrade.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor-upgrade.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-upgrade.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C,MAAM,MAAM,KAAK,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAgB9D,wEAAwE;AACxE,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,KAAG,MACc,CAAA;AA+CvD,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAqBpD;AA+CD,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,KAAK,CAyBhF;AA4CD,mGAAmG;AACnG,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,aAAa,GACrB,KAAK,CA8BP;AAUD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkC9D;AAoDD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CA+BjD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAezD;AAaD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,KAAK,CAwB1E"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { dirname, relative, resolve } from "node:path";
|
|
4
|
+
import { BASALT_CONFIG_KEYS, RETIRED_CONFIG_KEYS } from "./config.js";
|
|
4
5
|
import { parseJsonc, readIfExists, scannableFiles } from "./index.js";
|
|
5
6
|
const guarded = (id, run) => {
|
|
6
7
|
try {
|
|
@@ -259,11 +260,55 @@ function appWiringCheck(cwd) {
|
|
|
259
260
|
};
|
|
260
261
|
});
|
|
261
262
|
}
|
|
263
|
+
function unknownConfigKeysCheck(cwd) {
|
|
264
|
+
return guarded("config-keys", () => {
|
|
265
|
+
const raw = readIfExists(resolve(cwd, "package.json"));
|
|
266
|
+
const block = raw === null ? null : JSON.parse(raw).basalt;
|
|
267
|
+
if (typeof block !== "object" || block === null || Array.isArray(block)) return null;
|
|
268
|
+
const known = new Set(BASALT_CONFIG_KEYS);
|
|
269
|
+
const unknown = Object.keys(block).filter((k) => !known.has(k));
|
|
270
|
+
if (unknown.length === 0) return null;
|
|
271
|
+
const named = unknown.map(
|
|
272
|
+
(k) => `basalt.${k} (${RETIRED_CONFIG_KEYS[k] ?? "not a basalt key"})`
|
|
273
|
+
);
|
|
274
|
+
return {
|
|
275
|
+
fail: `config-keys: package.json sets keys basalt-ui does not read: ${named.join("; ")}. Fix: delete each key.`
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const EXACT_VERSION = /^\d+\.\d+\.\d+$/;
|
|
280
|
+
function installedVersion(cwd, pkg) {
|
|
281
|
+
for (let dir = cwd; ; dir = dirname(dir)) {
|
|
282
|
+
const raw = readIfExists(resolve(dir, "node_modules", pkg, "package.json"));
|
|
283
|
+
if (raw !== null) return JSON.parse(raw).version ?? null;
|
|
284
|
+
if (dirname(dir) === dir) return null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function exactPeersCheck(cwd, install) {
|
|
288
|
+
const id = "exact-peers";
|
|
289
|
+
if (install.dir === null)
|
|
290
|
+
return { skip: `${id}: basalt-ui does not resolve, so its peers cannot be read.` };
|
|
291
|
+
const dir = install.dir;
|
|
292
|
+
return guarded(id, () => {
|
|
293
|
+
const raw = readIfExists(resolve(dir, "package.json"));
|
|
294
|
+
const peers = (raw === null ? {} : JSON.parse(raw).peerDependencies) ?? {};
|
|
295
|
+
const off = Object.entries(peers).filter(([, range]) => EXACT_VERSION.test(range)).flatMap(([pkg, pin]) => {
|
|
296
|
+
const have = installedVersion(cwd, pkg);
|
|
297
|
+
return have === null || have === pin ? [] : [`${pkg}@${have} (basalt-ui pins ${pin}): \`bun add ${pkg}@${pin}\``];
|
|
298
|
+
});
|
|
299
|
+
if (off.length === 0) return null;
|
|
300
|
+
return {
|
|
301
|
+
fail: `${id}: installed peers differ from basalt-ui's exact pins. Fix: ${off.join("; ")}.`
|
|
302
|
+
};
|
|
303
|
+
});
|
|
304
|
+
}
|
|
262
305
|
export {
|
|
263
306
|
appWiringCheck,
|
|
264
307
|
droppedSubpathsCheck,
|
|
308
|
+
exactPeersCheck,
|
|
265
309
|
retiredLintRulesCheck,
|
|
266
310
|
seedTsconfigExtends,
|
|
267
311
|
tsconfigBaseCheck,
|
|
268
|
-
tsconfigFile
|
|
312
|
+
tsconfigFile,
|
|
313
|
+
unknownConfigKeysCheck
|
|
269
314
|
};
|
package/dist/cli/doctor.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ export type DoctorResult = {
|
|
|
22
22
|
* 4. `oxlint-preset`: `.oxlintrc.json` extends the shipped preset AND that path resolves.
|
|
23
23
|
* 7. `ai-major-parity`: the `ai` major agrees across this package.json's dependency fields
|
|
24
24
|
* (exempt via `basalt.aiMajorSkewReason`; a stale reason warns).
|
|
25
|
-
* 8-
|
|
25
|
+
* 8-13. `tsconfig-base`, `retired-lint-rules`, `dropped-subpaths`, `app-wiring`, `exact-peers`,
|
|
26
|
+
* `config-keys` (./doctor-upgrade);
|
|
26
27
|
* a check that cannot run is SKIPPED and exits non-zero.
|
|
27
28
|
*
|
|
28
29
|
* Warning (non-fatal):
|
package/dist/cli/doctor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAuDA,MAAM,MAAM,YAAY,GAAG;IACzB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AA8CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,MAAM,CAAC,aAAa,GAAE,MAAsB,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,MAAM,CAsS1F"}
|
package/dist/cli/doctor.js
CHANGED
|
@@ -29,8 +29,10 @@ import { resolveRoots } from "./config.js";
|
|
|
29
29
|
import {
|
|
30
30
|
appWiringCheck,
|
|
31
31
|
droppedSubpathsCheck,
|
|
32
|
+
exactPeersCheck,
|
|
32
33
|
retiredLintRulesCheck,
|
|
33
|
-
tsconfigBaseCheck
|
|
34
|
+
tsconfigBaseCheck,
|
|
35
|
+
unknownConfigKeysCheck
|
|
34
36
|
} from "./doctor-upgrade.js";
|
|
35
37
|
import { findManifestAbove, parentInstallAdvice } from "./sync.js";
|
|
36
38
|
function isSameFile(a, b) {
|
|
@@ -265,6 +267,11 @@ basalt-ui doctor \u2014 ${cwd}
|
|
|
265
267
|
[
|
|
266
268
|
"app-wiring: the entry mounts BasaltProvider and the router tree is generated",
|
|
267
269
|
appWiringCheck(cwd)
|
|
270
|
+
],
|
|
271
|
+
["exact-peers: installed exact-pinned peers match basalt-ui", exactPeersCheck(cwd, install)],
|
|
272
|
+
[
|
|
273
|
+
"config-keys: the basalt config block sets only keys basalt-ui reads",
|
|
274
|
+
unknownConfigKeysCheck(cwd)
|
|
268
275
|
]
|
|
269
276
|
];
|
|
270
277
|
for (const [ok, check] of upgrade) {
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v2.0.
|
|
1
|
+
# basalt-ui v2.0.1
|
|
2
2
|
# Opinionated framework for Mantine-based React apps — theme, app shell, TanStack Charts, toolchain presets
|
|
3
3
|
#
|
|
4
4
|
# Entry points: use the exact import specifier below; do not guess.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# A subpath's `Install:` line is its required peers; `OptionalPeers:` are import()-only, install on use.
|
|
14
14
|
|
|
15
15
|
Package: basalt-ui
|
|
16
|
-
Version: 2.0.
|
|
16
|
+
Version: 2.0.1
|
|
17
17
|
|
|
18
18
|
## basalt-ui
|
|
19
19
|
Import: import { ... } from 'basalt-ui'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "basalt-ui",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Opinionated framework for Mantine-based React apps — theme, app shell, TanStack Charts, toolchain presets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"charts",
|
|
@@ -165,9 +165,9 @@
|
|
|
165
165
|
},
|
|
166
166
|
"peerDependencies": {
|
|
167
167
|
"@ai-sdk/provider": "^4.0.26",
|
|
168
|
-
"@fontsource-variable/hubot-sans": "5.
|
|
169
|
-
"@fontsource-variable/jetbrains-mono": "5.
|
|
170
|
-
"@fontsource-variable/nunito-sans": "5.
|
|
168
|
+
"@fontsource-variable/hubot-sans": "5.3.0",
|
|
169
|
+
"@fontsource-variable/jetbrains-mono": "5.3.0",
|
|
170
|
+
"@fontsource-variable/nunito-sans": "5.3.0",
|
|
171
171
|
"@mantine/core": "^9.7.0",
|
|
172
172
|
"@mantine/dates": "^9.7.0",
|
|
173
173
|
"@mantine/form": "^9.7.0",
|
package/src/cli/config.ts
CHANGED
|
@@ -178,3 +178,15 @@ export const DEFAULT_ROOTS = [DEFAULT_ROOT]
|
|
|
178
178
|
export function resolveRoots(cfg: BasaltConfig): string[] {
|
|
179
179
|
return cfg.roots?.length ? cfg.roots : DEFAULT_ROOTS
|
|
180
180
|
}
|
|
181
|
+
|
|
182
|
+
/** Every `BasaltConfig` key, as data for `doctor`'s `config-keys` (a test pins it to the type). */
|
|
183
|
+
export const BASALT_CONFIG_KEYS = (
|
|
184
|
+
'roots exempt profile include spacingSteps severity forbiddenAccents accentHue rawRadius rawSurface ' +
|
|
185
|
+
'cardWithBorder offSystemSurfaceVar mantineShadeIndex rawHtmlLayout inlineSpacing inlineDisplay ' +
|
|
186
|
+
'rawMotionValue rawFormControl sub16InputFont seriesModulePath exemptRules aiMajorSkewReason'
|
|
187
|
+
).split(' ') as (keyof BasaltConfig)[]
|
|
188
|
+
|
|
189
|
+
/** Keys removed from `BasaltConfig`, with the reason `doctor` prints. */
|
|
190
|
+
export const RETIRED_CONFIG_KEYS: Readonly<Record<string, string>> = {
|
|
191
|
+
chartMissingAriaLabel: 'its guard kind is gone in 2.0 (`ariaLabel` is required on a chart now)',
|
|
192
|
+
}
|
|
@@ -6,6 +6,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
|
6
6
|
import { createRequire } from 'node:module'
|
|
7
7
|
import { dirname, relative, resolve } from 'node:path'
|
|
8
8
|
|
|
9
|
+
import { BASALT_CONFIG_KEYS, RETIRED_CONFIG_KEYS } from './config'
|
|
9
10
|
import type { BasaltConfig } from './config'
|
|
10
11
|
import { parseJsonc, readIfExists, scannableFiles } from './index'
|
|
11
12
|
import type { BasaltInstall } from './index'
|
|
@@ -390,3 +391,67 @@ export function appWiringCheck(cwd: string): Check {
|
|
|
390
391
|
}
|
|
391
392
|
})
|
|
392
393
|
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* `config-keys`: a key in package.json's `basalt` object that `BasaltConfig` does not declare is
|
|
397
|
+
* silently ignored, so a key retired in 2.0 keeps looking configured. Reads the raw file, not
|
|
398
|
+
* `readBasaltConfig`, which is typed and would hide the very keys this looks for.
|
|
399
|
+
*/
|
|
400
|
+
export function unknownConfigKeysCheck(cwd: string): Check {
|
|
401
|
+
return guarded('config-keys', () => {
|
|
402
|
+
const raw = readIfExists(resolve(cwd, 'package.json'))
|
|
403
|
+
const block = raw === null ? null : (JSON.parse(raw) as { basalt?: unknown }).basalt
|
|
404
|
+
if (typeof block !== 'object' || block === null || Array.isArray(block)) return null
|
|
405
|
+
const known = new Set<string>(BASALT_CONFIG_KEYS)
|
|
406
|
+
const unknown = Object.keys(block).filter((k) => !known.has(k))
|
|
407
|
+
if (unknown.length === 0) return null
|
|
408
|
+
const named = unknown.map(
|
|
409
|
+
(k) => `basalt.${k} (${RETIRED_CONFIG_KEYS[k] ?? 'not a basalt key'})`,
|
|
410
|
+
)
|
|
411
|
+
return {
|
|
412
|
+
fail: `config-keys: package.json sets keys basalt-ui does not read: ${named.join('; ')}. Fix: delete each key.`,
|
|
413
|
+
}
|
|
414
|
+
})
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const EXACT_VERSION = /^\d+\.\d+\.\d+$/
|
|
418
|
+
|
|
419
|
+
/** `node_modules/<pkg>/package.json`'s version, searching `cwd` then every ancestor. */
|
|
420
|
+
function installedVersion(cwd: string, pkg: string): string | null {
|
|
421
|
+
for (let dir = cwd; ; dir = dirname(dir)) {
|
|
422
|
+
const raw = readIfExists(resolve(dir, 'node_modules', pkg, 'package.json'))
|
|
423
|
+
if (raw !== null) return (JSON.parse(raw) as { version?: string }).version ?? null
|
|
424
|
+
if (dirname(dir) === dir) return null
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* `exact-peers`: basalt-ui pins some peers to one exact version, and `bun add` accepts any other
|
|
430
|
+
* version without a word. Compares each installed one against the install's declared pin; a peer
|
|
431
|
+
* that is not installed is not this check's business (optional peers are legitimately absent).
|
|
432
|
+
*/
|
|
433
|
+
export function exactPeersCheck(cwd: string, install: BasaltInstall): Check {
|
|
434
|
+
const id = 'exact-peers'
|
|
435
|
+
if (install.dir === null)
|
|
436
|
+
return { skip: `${id}: basalt-ui does not resolve, so its peers cannot be read.` }
|
|
437
|
+
const dir = install.dir
|
|
438
|
+
return guarded(id, () => {
|
|
439
|
+
const raw = readIfExists(resolve(dir, 'package.json'))
|
|
440
|
+
const peers =
|
|
441
|
+
(raw === null
|
|
442
|
+
? {}
|
|
443
|
+
: (JSON.parse(raw) as { peerDependencies?: Record<string, string> }).peerDependencies) ?? {}
|
|
444
|
+
const off = Object.entries(peers)
|
|
445
|
+
.filter(([, range]) => EXACT_VERSION.test(range))
|
|
446
|
+
.flatMap(([pkg, pin]) => {
|
|
447
|
+
const have = installedVersion(cwd, pkg)
|
|
448
|
+
return have === null || have === pin
|
|
449
|
+
? []
|
|
450
|
+
: [`${pkg}@${have} (basalt-ui pins ${pin}): \`bun add ${pkg}@${pin}\``]
|
|
451
|
+
})
|
|
452
|
+
if (off.length === 0) return null
|
|
453
|
+
return {
|
|
454
|
+
fail: `${id}: installed peers differ from basalt-ui's exact pins. Fix: ${off.join('; ')}.`,
|
|
455
|
+
}
|
|
456
|
+
})
|
|
457
|
+
}
|
package/src/cli/doctor.ts
CHANGED
|
@@ -36,8 +36,10 @@ import { resolveRoots } from './config'
|
|
|
36
36
|
import {
|
|
37
37
|
appWiringCheck,
|
|
38
38
|
droppedSubpathsCheck,
|
|
39
|
+
exactPeersCheck,
|
|
39
40
|
retiredLintRulesCheck,
|
|
40
41
|
tsconfigBaseCheck,
|
|
42
|
+
unknownConfigKeysCheck,
|
|
41
43
|
} from './doctor-upgrade'
|
|
42
44
|
import type { Check } from './doctor-upgrade'
|
|
43
45
|
import { findManifestAbove, parentInstallAdvice } from './sync'
|
|
@@ -120,7 +122,8 @@ function resolveAiMajorSkewReason(cfg: BasaltConfig): {
|
|
|
120
122
|
* 4. `oxlint-preset`: `.oxlintrc.json` extends the shipped preset AND that path resolves.
|
|
121
123
|
* 7. `ai-major-parity`: the `ai` major agrees across this package.json's dependency fields
|
|
122
124
|
* (exempt via `basalt.aiMajorSkewReason`; a stale reason warns).
|
|
123
|
-
* 8-
|
|
125
|
+
* 8-13. `tsconfig-base`, `retired-lint-rules`, `dropped-subpaths`, `app-wiring`, `exact-peers`,
|
|
126
|
+
* `config-keys` (./doctor-upgrade);
|
|
124
127
|
* a check that cannot run is SKIPPED and exits non-zero.
|
|
125
128
|
*
|
|
126
129
|
* Warning (non-fatal):
|
|
@@ -370,7 +373,7 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
|
|
|
370
373
|
pass('ai-major-parity: this package.json declares no ai dependency — nothing to compare')
|
|
371
374
|
}
|
|
372
375
|
|
|
373
|
-
// ── Hard checks 8-
|
|
376
|
+
// ── Hard checks 8-13: strictness and the 1.x → 2.0 upgrade path (./doctor-upgrade) ──────────
|
|
374
377
|
if (profile === 'tokens-only') {
|
|
375
378
|
pass(
|
|
376
379
|
'tsconfig-base / retired-lint-rules / dropped-subpaths / app-wiring: n/a — a tokens-only consumer',
|
|
@@ -390,6 +393,11 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
|
|
|
390
393
|
'app-wiring: the entry mounts BasaltProvider and the router tree is generated',
|
|
391
394
|
appWiringCheck(cwd),
|
|
392
395
|
],
|
|
396
|
+
['exact-peers: installed exact-pinned peers match basalt-ui', exactPeersCheck(cwd, install)],
|
|
397
|
+
[
|
|
398
|
+
'config-keys: the basalt config block sets only keys basalt-ui reads',
|
|
399
|
+
unknownConfigKeysCheck(cwd),
|
|
400
|
+
],
|
|
393
401
|
]
|
|
394
402
|
for (const [ok, check] of upgrade) {
|
|
395
403
|
if (check === null) pass(ok)
|