Skip to content

Commit 2a7e930

Browse files
committed
Merge branch 'codex/215-custom-preset-init'
2 parents df3cd27 + 1c30ea3 commit 2a7e930

13 files changed

Lines changed: 301 additions & 133 deletions

File tree

.changeset/fix-auth-env-runner.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66

77
- Fix auth env sync and local auth bootstrap so `kitcn add auth`, `kitcn env push`, and `kitcn dev --bootstrap` use the real Convex CLI entrypoint more reliably across runtimes and platforms.
88
- Fix `kitcn init -t <next|start|vite>` custom shadcn preset exits so they stop with a clear rerun instruction instead of crashing while patching scaffold files.
9+
- Improve `kitcn init -t <next|start|vite>` fresh scaffolds by syncing the shadcn wrapper to `shadcn@4.3.0` and regenerating the starter outputs against the latest upstream template contract.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
title: shadcn pin bumps must sync scaffold doubles and starters
3+
date: 2026-04-17
4+
category: workflow-issues
5+
module: init-scaffolds
6+
problem_type: workflow_issue
7+
component: tooling
8+
symptoms:
9+
- "`packages/kitcn/src/cli/backend-core.ts` still pins an older `shadcn@x.y.z` while upstream starters have already moved on"
10+
- "Local scaffold doubles in `packages/kitcn/src/cli/test-utils.ts` keep passing init tests even though fresh upstream scaffold output has changed"
11+
- "`fixtures:sync` and scenario lanes become the first place real drift shows up"
12+
root_cause: missing_workflow_step
13+
resolution_type: code_fix
14+
severity: medium
15+
tags:
16+
- shadcn
17+
- scaffolding
18+
- fixtures
19+
- scenarios
20+
- parity
21+
- test-doubles
22+
---
23+
24+
# shadcn pin bumps must sync scaffold doubles and starters
25+
26+
## Problem
27+
28+
`kitcn` wraps shadcn scaffolding in two places:
29+
30+
- the real CLI pin used by `init -t`
31+
- fake scaffold output used by local tests
32+
33+
If those move separately, the repo starts lying. Unit tests still pass against
34+
stale fake output while fresh scaffold generation and runtime scenarios follow a
35+
different upstream contract.
36+
37+
## Symptoms
38+
39+
- The pinned `INIT_SHADCN_PACKAGE_SPEC` lags behind the upstream release range.
40+
- Starter package versions and `components.json` fields drift from the current
41+
shadcn template contract.
42+
- `fixtures:sync`, `fixtures:check`, or prepared scenario apps expose drift
43+
that targeted unit tests missed.
44+
45+
## What Didn't Work
46+
47+
- Bumping only the shadcn version pin is incomplete. It leaves fake scaffold
48+
output frozen in old template assumptions.
49+
- Updating only the local doubles is also incomplete. It keeps committed
50+
starters and runtime scenarios on the wrong upstream release.
51+
52+
## Solution
53+
54+
Treat the shadcn pin, the scaffold doubles, and the committed starters as one
55+
contract.
56+
57+
When bumping shadcn:
58+
59+
1. Update the real `INIT_SHADCN_PACKAGE_SPEC`.
60+
2. Sync local scaffold doubles in `packages/kitcn/src/cli/test-utils.ts` to the
61+
same upstream starter shape.
62+
3. Refresh committed starters with `bun run fixtures:sync`.
63+
4. Prove they still match with `bun run fixtures:check`.
64+
5. Run runtime scenario proof for the affected template lanes.
65+
66+
For the `4.0.1 -> 4.3.0` bump, that meant syncing starter dependency versions,
67+
monorepo root metadata, and shadcn-owned `components.json` fields like
68+
`iconLibrary`.
69+
70+
## Why This Works
71+
72+
The real scaffold pin decides what users get. The local doubles decide what the
73+
tests believe users get.
74+
75+
Keeping both on the same upstream release removes the false-green state where:
76+
77+
- unit tests validate stale fake output
78+
- fixture regeneration rewrites half the repo
79+
- scenario lanes become the first honest signal
80+
81+
## Prevention
82+
83+
- Never treat a shadcn version bump as a one-line constant change.
84+
- If `init -t` owns a scaffold lane, its fake output in test helpers must match
85+
the same upstream release.
86+
- After every scaffold contract bump, run both fixture lanes and at least the
87+
relevant runtime scenarios before calling it done.
88+
- If fresh fixtures change more than expected, assume the local doubles are
89+
stale until proven otherwise.

fixtures/next-auth/app/layout.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import { ThemeProvider } from "@/components/theme-provider"
55
import { cn } from "@/lib/utils";
66
import { Providers } from "@/components/providers";
77

8-
const fontSans = Geist({
9-
subsets: ["latin"],
10-
variable: "--font-sans",
11-
})
8+
const geist = Geist({subsets:['latin'],variable:'--font-sans'})
129

1310
const fontMono = Geist_Mono({
1411
subsets: ["latin"],
@@ -24,7 +21,7 @@ export default function RootLayout({
2421
<html
2522
lang="en"
2623
suppressHydrationWarning
27-
className={cn("antialiased", fontMono.variable, "font-sans", fontSans.variable)}
24+
className={cn("antialiased", fontMono.variable, "font-sans", geist.variable)}
2825
>
2926
<body>
3027
<ThemeProvider><Providers>{children}</Providers></ThemeProvider>

fixtures/next-auth/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"hono": "4.12.9",
1111
"kitcn": "workspace:*",
1212
"lucide-react": "^1.8.0",
13-
"next": "16.1.6",
13+
"next": "16.1.7",
1414
"next-themes": "^0.4.6",
1515
"react": "^19.2.4",
1616
"react-dom": "^19.2.4",
@@ -22,16 +22,16 @@
2222
},
2323
"devDependencies": {
2424
"@eslint/eslintrc": "^3",
25-
"@tailwindcss/postcss": "^4.1.18",
26-
"@types/node": "^25.1.0",
27-
"@types/react": "^19.2.10",
25+
"@tailwindcss/postcss": "^4.2.1",
26+
"@types/node": "^25.5.0",
27+
"@types/react": "^19.2.14",
2828
"@types/react-dom": "^19.2.3",
29-
"eslint": "^9.39.2",
30-
"eslint-config-next": "16.1.6",
29+
"eslint": "^9.39.4",
30+
"eslint-config-next": "16.1.7",
3131
"prettier": "^3.8.1",
3232
"prettier-plugin-tailwindcss": "^0.7.2",
3333
"postcss": "^8",
34-
"tailwindcss": "^4.1.18",
34+
"tailwindcss": "^4.2.1",
3535
"typescript": "^5.9.3",
3636
"@types/bun": "latest",
3737
"@concavejs/cli": "latest"

fixtures/next/app/layout.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import { ThemeProvider } from "@/components/theme-provider"
55
import { cn } from "@/lib/utils";
66
import { Providers } from "@/components/providers";
77

8-
const fontSans = Geist({
9-
subsets: ["latin"],
10-
variable: "--font-sans",
11-
})
8+
const geist = Geist({subsets:['latin'],variable:'--font-sans'})
129

1310
const fontMono = Geist_Mono({
1411
subsets: ["latin"],
@@ -24,7 +21,7 @@ export default function RootLayout({
2421
<html
2522
lang="en"
2623
suppressHydrationWarning
27-
className={cn("antialiased", fontMono.variable, "font-sans", fontSans.variable)}
24+
className={cn("antialiased", fontMono.variable, "font-sans", geist.variable)}
2825
>
2926
<body>
3027
<ThemeProvider><Providers>{children}</Providers></ThemeProvider>

fixtures/next/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"hono": "4.12.9",
1010
"kitcn": "workspace:*",
1111
"lucide-react": "^1.8.0",
12-
"next": "16.1.6",
12+
"next": "16.1.7",
1313
"next-themes": "^0.4.6",
1414
"react": "^19.2.4",
1515
"react-dom": "^19.2.4",
@@ -21,16 +21,16 @@
2121
},
2222
"devDependencies": {
2323
"@eslint/eslintrc": "^3",
24-
"@tailwindcss/postcss": "^4.1.18",
25-
"@types/node": "^25.1.0",
26-
"@types/react": "^19.2.10",
24+
"@tailwindcss/postcss": "^4.2.1",
25+
"@types/node": "^25.5.0",
26+
"@types/react": "^19.2.14",
2727
"@types/react-dom": "^19.2.3",
28-
"eslint": "^9.39.2",
29-
"eslint-config-next": "16.1.6",
28+
"eslint": "^9.39.4",
29+
"eslint-config-next": "16.1.7",
3030
"prettier": "^3.8.1",
3131
"prettier-plugin-tailwindcss": "^0.7.2",
3232
"postcss": "^8",
33-
"tailwindcss": "^4.1.18",
33+
"tailwindcss": "^4.2.1",
3434
"typescript": "^5.9.3",
3535
"@types/bun": "latest",
3636
"@concavejs/cli": "latest"

fixtures/start-auth/package.json

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
"@base-ui/react": "^1.4.0",
44
"@fontsource-variable/geist": "^5.2.8",
55
"@opentelemetry/api": "1.9.0",
6-
"@tailwindcss/vite": "^4.1.18",
7-
"@tanstack/react-devtools": "^0.7.0",
6+
"@tailwindcss/vite": "^4.2.1",
7+
"@tanstack/react-devtools": "^0.10.0",
88
"@tanstack/react-query": "5.95.2",
9-
"@tanstack/react-router": "^1.132.0",
10-
"@tanstack/react-router-devtools": "^1.132.0",
11-
"@tanstack/react-router-ssr-query": "^1.131.7",
12-
"@tanstack/react-start": "^1.132.0",
13-
"@tanstack/router-plugin": "^1.132.0",
9+
"@tanstack/react-router": "^1.167.4",
10+
"@tanstack/react-router-devtools": "^1.166.9",
11+
"@tanstack/react-router-ssr-query": "^1.166.9",
12+
"@tanstack/react-start": "^1.166.15",
13+
"@tanstack/router-plugin": "^1.166.13",
1414
"better-auth": "1.6.5",
1515
"class-variance-authority": "^0.7.1",
1616
"clsx": "^2.1.1",
@@ -19,31 +19,31 @@
1919
"kitcn": "workspace:*",
2020
"lucide-react": "^1.8.0",
2121
"nitro": "latest",
22-
"react": "^19.2.0",
23-
"react-dom": "^19.2.0",
22+
"react": "^19.2.4",
23+
"react-dom": "^19.2.4",
2424
"shadcn": "latest",
2525
"superjson": "^2.2.6",
2626
"tailwind-merge": "^3.5.0",
27-
"tailwindcss": "^4.0.6",
27+
"tailwindcss": "^4.2.1",
2828
"tw-animate-css": "^1.4.0",
2929
"vite-tsconfig-paths": "^5.1.4",
3030
"zod": "^4.3.6"
3131
},
3232
"devDependencies": {
33-
"@tanstack/devtools-vite": "^0.3.11",
34-
"@tanstack/eslint-config": "^0.3.0",
35-
"@testing-library/dom": "^10.4.0",
36-
"@testing-library/react": "^16.2.0",
37-
"@types/node": "^22.10.2",
38-
"@types/react": "^19.2.0",
39-
"@types/react-dom": "^19.2.0",
40-
"@vitejs/plugin-react": "^5.0.4",
41-
"jsdom": "^27.0.0",
42-
"prettier": "^3.5.3",
33+
"@tanstack/devtools-vite": "^0.6.0",
34+
"@tanstack/eslint-config": "^0.4.0",
35+
"@testing-library/dom": "^10.4.1",
36+
"@testing-library/react": "^16.3.2",
37+
"@types/node": "^22.19.15",
38+
"@types/react": "^19.2.14",
39+
"@types/react-dom": "^19.2.3",
40+
"@vitejs/plugin-react": "^5.2.0",
41+
"jsdom": "^27.4.0",
42+
"prettier": "^3.8.1",
4343
"prettier-plugin-tailwindcss": "^0.7.2",
44-
"typescript": "^5.7.2",
45-
"vite": "^7.1.7",
46-
"vitest": "^3.0.5",
44+
"typescript": "^5.9.3",
45+
"vite": "^7.3.1",
46+
"vitest": "^3.2.4",
4747
"web-vitals": "^5.1.0",
4848
"@types/bun": "latest",
4949
"@concavejs/cli": "latest"

fixtures/start/package.json

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,46 @@
33
"@base-ui/react": "^1.4.0",
44
"@fontsource-variable/geist": "^5.2.8",
55
"@opentelemetry/api": "1.9.0",
6-
"@tailwindcss/vite": "^4.1.18",
7-
"@tanstack/react-devtools": "^0.7.0",
6+
"@tailwindcss/vite": "^4.2.1",
7+
"@tanstack/react-devtools": "^0.10.0",
88
"@tanstack/react-query": "5.95.2",
9-
"@tanstack/react-router": "^1.132.0",
10-
"@tanstack/react-router-devtools": "^1.132.0",
11-
"@tanstack/react-router-ssr-query": "^1.131.7",
12-
"@tanstack/react-start": "^1.132.0",
13-
"@tanstack/router-plugin": "^1.132.0",
9+
"@tanstack/react-router": "^1.167.4",
10+
"@tanstack/react-router-devtools": "^1.166.9",
11+
"@tanstack/react-router-ssr-query": "^1.166.9",
12+
"@tanstack/react-start": "^1.166.15",
13+
"@tanstack/router-plugin": "^1.166.13",
1414
"class-variance-authority": "^0.7.1",
1515
"clsx": "^2.1.1",
1616
"convex": "1.35.1",
1717
"hono": "4.12.9",
1818
"kitcn": "workspace:*",
1919
"lucide-react": "^1.8.0",
2020
"nitro": "latest",
21-
"react": "^19.2.0",
22-
"react-dom": "^19.2.0",
21+
"react": "^19.2.4",
22+
"react-dom": "^19.2.4",
2323
"shadcn": "latest",
2424
"superjson": "^2.2.6",
2525
"tailwind-merge": "^3.5.0",
26-
"tailwindcss": "^4.0.6",
26+
"tailwindcss": "^4.2.1",
2727
"tw-animate-css": "^1.4.0",
2828
"vite-tsconfig-paths": "^5.1.4",
2929
"zod": "^4.3.6"
3030
},
3131
"devDependencies": {
32-
"@tanstack/devtools-vite": "^0.3.11",
33-
"@tanstack/eslint-config": "^0.3.0",
34-
"@testing-library/dom": "^10.4.0",
35-
"@testing-library/react": "^16.2.0",
36-
"@types/node": "^22.10.2",
37-
"@types/react": "^19.2.0",
38-
"@types/react-dom": "^19.2.0",
39-
"@vitejs/plugin-react": "^5.0.4",
40-
"jsdom": "^27.0.0",
41-
"prettier": "^3.5.3",
32+
"@tanstack/devtools-vite": "^0.6.0",
33+
"@tanstack/eslint-config": "^0.4.0",
34+
"@testing-library/dom": "^10.4.1",
35+
"@testing-library/react": "^16.3.2",
36+
"@types/node": "^22.19.15",
37+
"@types/react": "^19.2.14",
38+
"@types/react-dom": "^19.2.3",
39+
"@vitejs/plugin-react": "^5.2.0",
40+
"jsdom": "^27.4.0",
41+
"prettier": "^3.8.1",
4242
"prettier-plugin-tailwindcss": "^0.7.2",
43-
"typescript": "^5.7.2",
44-
"vite": "^7.1.7",
45-
"vitest": "^3.0.5",
43+
"typescript": "^5.9.3",
44+
"vite": "^7.3.1",
45+
"vitest": "^3.2.4",
4646
"web-vitals": "^5.1.0",
4747
"@types/bun": "latest",
4848
"@concavejs/cli": "latest"

fixtures/vite-auth/package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"@base-ui/react": "^1.4.0",
44
"@fontsource-variable/geist": "^5.2.8",
55
"@opentelemetry/api": "1.9.0",
6-
"@tailwindcss/vite": "^4.1.17",
6+
"@tailwindcss/vite": "^4.2.1",
77
"@tanstack/react-query": "5.95.2",
88
"better-auth": "1.6.5",
99
"class-variance-authority": "^0.7.1",
@@ -12,30 +12,30 @@
1212
"hono": "4.12.9",
1313
"kitcn": "workspace:*",
1414
"lucide-react": "^1.8.0",
15-
"react": "^19.2.0",
16-
"react-dom": "^19.2.0",
15+
"react": "^19.2.4",
16+
"react-dom": "^19.2.4",
1717
"shadcn": "latest",
1818
"superjson": "^2.2.6",
1919
"tailwind-merge": "^3.5.0",
20-
"tailwindcss": "^4.1.17",
20+
"tailwindcss": "^4.2.1",
2121
"tw-animate-css": "^1.4.0",
2222
"zod": "^4.3.6"
2323
},
2424
"devDependencies": {
25-
"@eslint/js": "^9.39.1",
26-
"@types/node": "^24.10.1",
27-
"@types/react": "^19.2.5",
25+
"@eslint/js": "^9.39.4",
26+
"@types/node": "^24.12.0",
27+
"@types/react": "^19.2.14",
2828
"@types/react-dom": "^19.2.3",
29-
"@vitejs/plugin-react": "^5.1.1",
30-
"eslint": "^9.39.1",
29+
"@vitejs/plugin-react": "^5.2.0",
30+
"eslint": "^9.39.4",
3131
"eslint-plugin-react-hooks": "^7.0.1",
32-
"eslint-plugin-react-refresh": "^0.4.24",
32+
"eslint-plugin-react-refresh": "^0.5.2",
3333
"globals": "^16.5.0",
3434
"prettier": "^3.8.1",
3535
"prettier-plugin-tailwindcss": "^0.7.2",
3636
"typescript": "~5.9.3",
37-
"typescript-eslint": "^8.46.4",
38-
"vite": "^7.2.4",
37+
"typescript-eslint": "^8.57.1",
38+
"vite": "^7.3.1",
3939
"@types/bun": "latest",
4040
"@concavejs/cli": "latest"
4141
},

0 commit comments

Comments
 (0)