fix(cli): route presets through /init registry endpoint#1764
Conversation
Mirror shadcn-ui's preset pipeline so the `create`/preset flow actually applies font, theme, base color, radius, menu options, chart palette, and generated CSS vars — not just writes a handful of strings to components.json. - Add `shadcn-vue/preset` package subpath (browser-safe bit-packed encoder/decoder) as the single source of truth shared between CLI and web (deletes the diverging copy in apps/v4/lib) - Add `packages/cli/src/preset/presets.ts` with `DEFAULT_PRESETS`, `resolveInitUrl`, `resolveRegistryBaseConfig`, `promptForPreset` - Add Nuxt `/init` server route that decodes the preset, validates via `designSystemConfigSchema`, and returns a full `registry:base` item via the existing `buildRegistryBase` - Extend `buildRegistryBase` to include `font`, `rtl`, and `fontHeading` dependencies in the emitted config - Rewrite `init.ts` preset handling to inject the init URL into the component list, fetch the registry:base config, and `mergeConfig` it into the final components.json — following shadcn-ui's flow - Sync CLI `BASE_COLORS` and `FONTS` constants with the web registry (replaces gray/slate with mauve/olive/mist/taupe; expands fonts to the full 11 used by the site) - Widen `rawConfigSchema.menuColor` to include the translucent variants used by presets - Update tests to the new preset naming (`vega`/`nova`/...) and drop `resolvePreset` tests (function removed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughReplaces legacy preset encoders with a new bit-packed base62 preset system; adds URL-driven design-system parsing and a /init server route; refactors CLI preset handling (name|code|URL) with DEFAULT_PRESETS and registry resolution; updates registry constants/schemas; and removes old preset-encoding modules. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Server as init.get
participant Parser as parseDesignSystemConfig
participant Decoder as decodePreset
participant Registry as buildRegistryBase
participant Validator as registryItemSchema
Client->>Server: GET /init?preset=<code>&template=vite
Server->>Parser: parseDesignSystemConfig(searchParams)
Parser->>Decoder: decodePreset(code)
Decoder-->>Parser: PresetConfig|null
Parser->>Parser: assemble configInput (preset + overrides)
Parser->>Parser: designSystemConfigSchema.safeParse
alt parse fail
Parser-->>Server: { success: false, error }
Server-->>Client: 400 Bad Request
else parse success
Parser-->>Server: { success: true, data }
Server->>Registry: buildRegistryBase(data)
Registry-->>Server: registryBase
Server->>Validator: registryItemSchema.safeParse(registryBase)
alt validation fail
Validator-->>Server: errors
Server-->>Client: 500 Internal Server Error
else
Server-->>Client: 200 OK + JSON (Cache-Control)
end
end
sequenceDiagram
participant User
participant CLI as init Command
participant Prompt as promptForPreset
participant URL as resolveInitUrl
participant Registry as resolveRegistryBaseConfig
participant Server as init.get
User->>CLI: run init --preset [name|code|url]
CLI->>Prompt: promptForPreset(options)
Prompt->>User: interactive selection
User-->>Prompt: select named preset
Prompt->>URL: resolveInitUrl(selectedPreset)
URL-->>Prompt: init URL
Prompt->>Registry: resolveRegistryBaseConfig(initUrl)
Registry->>Server: fetch registry items for initUrl
Server-->>Registry: registry items (include registry:base)
Registry-->>CLI: { registryBaseConfig, installStyleIndex, url }
CLI->>CLI: merge registryBaseConfig into components.json (respecting CLI rtl)
CLI-->>User: complete
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Note Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it. Generating unit tests... This may take up to 20 minutes. |
|
✅ Created PR with unit tests: #1765 |
Three issues surfaced running the preset flow end-to-end against a
fresh Vite project:
- `designSystemConfigSchema.fontHeading` rejected its own default
"inherit" (enum was just fontValues). Widen to include "inherit".
- `buildRegistryBase` added `font-${config.font}` to
registryDependencies, mirroring shadcn-ui — but shadcn-vue does not
publish font-* registry items. The CLI already handles fonts via
the local FONTS constant + `getFontImport`, so drop the dep.
- `getRegistryBaseColor` called `handleError` on 404, aborting init
when newer base colors (mauve/olive/mist/taupe) have no published
`colors/<name>.json`. Return undefined on RegistryNotFoundError —
the mapping is only used for inline class color remapping when
cssVariables is false, so degrading gracefully is safe.
Verified end-to-end: `init --preset <code>` against a Vite project
now writes the correct style, font, baseColor, iconLibrary,
menuAccent, menuColor to components.json AND applies the full
theme, radius, and font import to style.css.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
apps/v4/server/routes/init.get.ts (1)
16-22: Consider limiting error details in 500 response.The formatted Zod error in
datacould expose internal schema structure. For a 500 (internal server error), consider logging the full error server-side while returning a generic message to clients.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/v4/server/routes/init.get.ts` around lines 16 - 22, Log the full Zod error server-side and return a generic client-facing message: keep the existing check of parseResult.success, but before throwing createError call your server logger (or console.error) with parseResult.error.format() or the raw error to capture details for debugging; then throw createError({ statusCode: 500, statusMessage: 'Invalid registry base item', data: { message: 'Internal server error' } }) (or omit the detailed data) so the createError payload no longer exposes parseResult.error.format() to clients; refer to parseResult, parseResult.error.format(), and createError in init.get.ts when making this change.packages/cli/test/commands/init.test.ts (1)
183-194: Consider adding coverage forfontHeadingandrtlfields.
DEFAULT_PRESETSincludesfontHeadingandrtlfields (per the context snippet), but these aren't verified in the test. Adding assertions would ensure complete coverage of the preset structure.💡 Optional addition
expect(preset.menuAccent).toBeDefined() expect(preset.menuColor).toBeDefined() expect(preset.radius).toBeDefined() + expect(preset.fontHeading).toBeDefined() + expect(preset.rtl).toBeDefined() }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/test/commands/init.test.ts` around lines 183 - 194, The test "each preset has a complete design system config" iterates over DEFAULT_PRESETS but misses asserting two fields; update that test (the it block) to also assert that preset.fontHeading and preset.rtl are defined by adding expect(preset.fontHeading).toBeDefined() and expect(preset.rtl).toBeDefined() alongside the existing assertions so every preset field is covered.packages/cli/src/preset/presets.ts (1)
331-340: Consider addingisUrlvalidation beforenew URL().The
isShadcnVueInitUrlfunction catches exceptions fromnew URL(), but it could avoid the try/catch overhead by first checkingisUrl(url)(which is already imported and re-exported).♻️ Optional: use isUrl check
function isShadcnVueInitUrl(url: string) { + if (!isUrl(url)) { + return false + } try { return new URL(url).pathname === '/init' && url.startsWith(SHADCN_VUE_URL) } catch { return false } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/preset/presets.ts` around lines 331 - 340, Refactor isShadcnVueInitUrl to call the existing isUrl(url) first and immediately return false if that check fails, then safely construct new URL(url) and evaluate pathname === '/init' && url.startsWith(SHADCN_VUE_URL); this removes the need for the try/catch around new URL(), references the isShadcnVueInitUrl and isUrl symbols, and preserves the same boolean behavior.apps/v4/composables/useDesignSystemSearchParams.ts (1)
25-37: Consider aligningchartColordefault withDEFAULT_PRESET_CONFIG.The
chartColordefault here is hardcoded to'emerald', whileDEFAULT_PRESET_CONFIGinpackages/cli/src/preset/preset.tsderives it fromPRESET_CHART_COLORS[0]which is'neutral'(sincePRESET_CHART_COLORS = PRESET_THEMESand themes start with'neutral').If consistency is desired, consider importing and using
DEFAULT_PRESET_CONFIG.chartColoror ensuring both defaults match intentionally.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/v4/composables/useDesignSystemSearchParams.ts` around lines 25 - 37, PRESET_DEFAULTS currently hardcodes chartColor to 'emerald' which is inconsistent with DEFAULT_PRESET_CONFIG (which derives chartColor from PRESET_CHART_COLORS[0]/'neutral'); update PRESET_DEFAULTS to use the shared default instead of a literal: import and use DEFAULT_PRESET_CONFIG.chartColor (or derive from PRESET_CHART_COLORS[0] if import is undesirable) and replace the 'emerald' literal in the chartColor field so both defaults stay consistent; the key symbols to change are PRESET_DEFAULTS and its chartColor entry, and you may reference DEFAULT_PRESET_CONFIG or PRESET_CHART_COLORS/PRESET_THEMES as the source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/v4/server/routes/init.get.ts`:
- Around line 13-14: buildRegistryBase can throw when the requested base or icon
library is missing, causing an unhandled exception; wrap the call to
buildRegistryBase(result.data) in a try-catch, catch the Error, log/return a
proper 400/422 response (or propagate a controlled error) with a clear message,
and only call registryItemSchema.safeParse(registryBase) when the build
succeeded — update the block around buildRegistryBase, registryBase, parseResult
and registryItemSchema to handle and surface the error instead of allowing a
500.
In `@packages/cli/src/commands/init.ts`:
- Around line 371-384: Wrap the call to resolveRegistryBaseConfig(...) in its
own try-catch so failures during registry/preset resolution are logged with
specific context before delegating to the existing error handling; inside the
catch, include the registry URL (components[0] / cleanUrl) and operation name
(registry/preset config resolution) in a descriptive error message via the same
logging mechanism used elsewhere, then rethrow or pass the original error to
handleError so stack is preserved; ensure resolveRegistryBaseConfig,
options.registryBaseConfig, options.installStyleIndex, options.baseStyle and the
mutated components array are still set only on success.
In `@packages/cli/src/registry/schema.ts`:
- Around line 43-51: Update the preset schema to match the raw config's allowed
menuColor values: change presetSchema.menuColor (the enum used for presets) so
it includes "default-translucent" and "inverted-translucent" in addition to
"default" and "inverted", and ensure its default/optional behavior matches
rawConfigSchema.menuColor so presets can validly specify translucent menu
colors.
---
Nitpick comments:
In `@apps/v4/composables/useDesignSystemSearchParams.ts`:
- Around line 25-37: PRESET_DEFAULTS currently hardcodes chartColor to 'emerald'
which is inconsistent with DEFAULT_PRESET_CONFIG (which derives chartColor from
PRESET_CHART_COLORS[0]/'neutral'); update PRESET_DEFAULTS to use the shared
default instead of a literal: import and use DEFAULT_PRESET_CONFIG.chartColor
(or derive from PRESET_CHART_COLORS[0] if import is undesirable) and replace the
'emerald' literal in the chartColor field so both defaults stay consistent; the
key symbols to change are PRESET_DEFAULTS and its chartColor entry, and you may
reference DEFAULT_PRESET_CONFIG or PRESET_CHART_COLORS/PRESET_THEMES as the
source of truth.
In `@apps/v4/server/routes/init.get.ts`:
- Around line 16-22: Log the full Zod error server-side and return a generic
client-facing message: keep the existing check of parseResult.success, but
before throwing createError call your server logger (or console.error) with
parseResult.error.format() or the raw error to capture details for debugging;
then throw createError({ statusCode: 500, statusMessage: 'Invalid registry base
item', data: { message: 'Internal server error' } }) (or omit the detailed data)
so the createError payload no longer exposes parseResult.error.format() to
clients; refer to parseResult, parseResult.error.format(), and createError in
init.get.ts when making this change.
In `@packages/cli/src/preset/presets.ts`:
- Around line 331-340: Refactor isShadcnVueInitUrl to call the existing
isUrl(url) first and immediately return false if that check fails, then safely
construct new URL(url) and evaluate pathname === '/init' &&
url.startsWith(SHADCN_VUE_URL); this removes the need for the try/catch around
new URL(), references the isShadcnVueInitUrl and isUrl symbols, and preserves
the same boolean behavior.
In `@packages/cli/test/commands/init.test.ts`:
- Around line 183-194: The test "each preset has a complete design system
config" iterates over DEFAULT_PRESETS but misses asserting two fields; update
that test (the it block) to also assert that preset.fontHeading and preset.rtl
are defined by adding expect(preset.fontHeading).toBeDefined() and
expect(preset.rtl).toBeDefined() alongside the existing assertions so every
preset field is covered.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 71341d94-98bb-428c-8d37-74c63abd56f2
📒 Files selected for processing (18)
apps/v4/composables/useDesignSystemSearchParams.tsapps/v4/lib/parse-design-system-config.tsapps/v4/lib/parse-preset-input.tsapps/v4/lib/preset-encoding.tsapps/v4/registry/config.tsapps/v4/server/routes/init.get.tspackages/cli/package.jsonpackages/cli/src/commands/init.tspackages/cli/src/preset/index.tspackages/cli/src/preset/preset.tspackages/cli/src/preset/presets.tspackages/cli/src/registry/api.tspackages/cli/src/registry/constants.tspackages/cli/src/registry/schema.tspackages/cli/src/utils/preset-encoding.tspackages/cli/test/commands/init.test.tspackages/cli/test/utils/registry-api.test.tspackages/cli/tsdown.config.ts
💤 Files with no reviewable changes (2)
- packages/cli/src/utils/preset-encoding.ts
- apps/v4/lib/preset-encoding.ts
- init.get.ts: wrap buildRegistryBase in try/catch so invalid base/iconLibrary lookups return 400 with the underlying message instead of a bare 500; stop exposing the Zod error shape in the 500 payload (log server-side only). - schema.ts: widen presetSchema.menuColor to include the translucent variants, matching the earlier rawConfigSchema widening. - presets.ts: guard isShadcnVueInitUrl with isUrl() instead of a try/catch around new URL(). - init.test.ts: extend the default-preset coverage to assert fontHeading and rtl are defined. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/cli/src/preset/presets.ts`:
- Around line 242-244: The promptForPreset function currently calls
process.exit(...) when the user makes no selection (and again around the 258-263
block); remove those process.exit calls and instead return a distinct control
result (e.g., an object with result.kind set to 'cancelled' or 'no-selection')
from promptForPreset so callers can handle shutdown/cleanup; update the
function's return type accordingly and ensure callers (notably the init command)
branch on result.kind and perform process.exit there if desired, preserving
existing finally/teardown behavior.
- Around line 331-335: The function isShadcnVueInitUrl uses
url.startsWith(SHADCN_VUE_URL) which is a weak host validation; update
isShadcnVueInitUrl to parse the candidate URL and the SHADCN_VUE_URL with new
URL(...) and compare their origin (or host) instead of using startsWith, e.g.,
after isUrl(url) create const candidate = new URL(url) and const trusted = new
URL(SHADCN_VUE_URL) and return candidate.origin === trusted.origin &&
candidate.pathname === '/init' (preserving the pathname check) to ensure proper
host validation for SHADCN_VUE_URL.
- Around line 313-327: The code currently allows registryBaseConfig to be
undefined which silently falls back to defaults; update the logic after
computing registryBaseConfig (the const registryBaseConfig = ... using
item?.type === 'registry:base' and item.config) to throw an explicit error when
registryBaseConfig is undefined (include initUrl and any item identifier in the
message for context), so that when isShadcnVueInitUrl(initUrl) or subsequent
processing expects a registry:base item the function fails fast instead of
continuing with defaults; keep the existing URL cleanup (cleanUrl) logic
unchanged and ensure the thrown error prevents returning the object that
contains registryBaseConfig, installStyleIndex, and url.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f5615c8b-dca0-4378-936a-0a3988fb6e7d
📒 Files selected for processing (4)
apps/v4/server/routes/init.get.tspackages/cli/src/preset/presets.tspackages/cli/src/registry/schema.tspackages/cli/test/commands/init.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/v4/server/routes/init.get.ts
- packages/cli/src/registry/schema.ts
- packages/cli/test/commands/init.test.ts
The preset init was loading the Google Fonts @import but never declaring `--font-sans` anywhere, so Tailwind v4 kept falling back to its default sans stack. Extend buildRegistryBase to look up the font in apps/v4/registry/fonts.ts and emit: - cssVars.theme[font.variable] = font.family — lands inside @theme inline { --font-sans: 'JetBrains Mono Variable', monospace } - body: "@apply font-sans" (or font-mono / font-serif) — lands in @layer base so the body actually uses the font Also add packages/cli/scripts/test-preset-init.sh: copies the vite fixture to a temp dir, patches tsconfig.json with the @ alias, runs the CLI against localhost:3000 /init, and prints components.json + style.css + utils.ts so the whole preset flow can be smoke-tested locally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/cli/scripts/test-preset-init.sh (2)
27-28: Remove unusedREPO_DIRvariable.At Line 28,
REPO_DIRis assigned but never used.Proposed fix
CLI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -REPO_DIR="$(cd "$CLI_DIR/../.." && pwd)" FIXTURE="$CLI_DIR/test/fixtures/frameworks/vite"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/scripts/test-preset-init.sh` around lines 27 - 28, Remove the unused REPO_DIR variable assignment in the script: delete the line that defines REPO_DIR (the assignment using "$(cd "$CLI_DIR/../.." && pwd)") in packages/cli/scripts/test-preset-init.sh since CLI_DIR is already defined and REPO_DIR is never referenced; ensure no other references to REPO_DIR remain, and run shellcheck or a quick test to confirm no breakage.
37-37: URL-encodepresetin the reachability probe.At Line 37, probing with raw
$PRESETcan produce false negatives when preset contains reserved URL characters (e.g., URL-form presets).Proposed fix
-if ! curl -fsS -o /dev/null "http://localhost:3000/init?preset=$PRESET&track=0"; then +ENC_PRESET="$(node -p "encodeURIComponent(process.argv[1])" "$PRESET")" +if ! curl -fsS -o /dev/null "http://localhost:3000/init?preset=$ENC_PRESET&track=0"; then🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/scripts/test-preset-init.sh` at line 37, The reachability probe uses an unencoded $PRESET in the curl URL which can break when $PRESET contains reserved characters; update the curl invocation in the test-preset-init.sh script to URL-encode the preset (use curl --get with --data-urlencode "preset=$PRESET" and include track=0 as a separate query param) so the probe constructs a safe /init?preset=...&track=0 request even when PRESET contains special characters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/cli/scripts/test-preset-init.sh`:
- Line 24: The script's safety flags currently use "set -uo pipefail" which
omits -e (exit-on-error); update the shell options by changing the invocation to
include -e (i.e., use "set -euo pipefail") so the test fails fast if any command
(copy/init/readback) errors, ensuring the success message cannot be reached on
failures.
---
Nitpick comments:
In `@packages/cli/scripts/test-preset-init.sh`:
- Around line 27-28: Remove the unused REPO_DIR variable assignment in the
script: delete the line that defines REPO_DIR (the assignment using "$(cd
"$CLI_DIR/../.." && pwd)") in packages/cli/scripts/test-preset-init.sh since
CLI_DIR is already defined and REPO_DIR is never referenced; ensure no other
references to REPO_DIR remain, and run shellcheck or a quick test to confirm no
breakage.
- Line 37: The reachability probe uses an unencoded $PRESET in the curl URL
which can break when $PRESET contains reserved characters; update the curl
invocation in the test-preset-init.sh script to URL-encode the preset (use curl
--get with --data-urlencode "preset=$PRESET" and include track=0 as a separate
query param) so the probe constructs a safe /init?preset=...&track=0 request
even when PRESET contains special characters.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2c455d57-b83c-48ba-bd0e-25ebfd90a469
📒 Files selected for processing (2)
apps/v4/registry/config.tspackages/cli/scripts/test-preset-init.sh
- presets.ts: promptForPreset now returns a discriminated result
({ kind: 'preset' | 'custom' | 'cancelled' }) instead of calling
process.exit, so the command-layer finally block still runs.
Init.ts handles the three cases explicitly.
- presets.ts: resolveRegistryBaseConfig now fails fast when the init
URL does not resolve to a registry:base item with a config, so
broken preset propagation can't silently fall back to defaults.
- presets.ts: isShadcnVueInitUrl now compares URL.origin instead of
using startsWith, closing a weak host-validation prefix match.
- test-preset-init.sh: re-enable 'set -e' and guard the init step
with an explicit status check so artifacts can still be printed
on failure but the script exits non-zero.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/cli/src/commands/init.ts (1)
319-329:⚠️ Potential issue | 🟡 MinorReturn from the action instead of calling
process.exit()here.These branches are still inside the command handler's
try, soprocess.exit()skips the surroundingfinallydespite the comment on Line 320. If you want the cleanup path to run, setprocess.exitCodefor cancel andreturnfrom the handler.Suggested fix
if (result.kind === 'cancelled') { logger.break() - process.exit(1) + process.exitCode = 1 + return } @@ if (result.kind === 'custom') { logger.break() - process.exit(0) + return }#!/bin/bash node -e 'try { process.exit(0) } finally { console.log("finally ran") }' printf 'exit=%s\n' "$?"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/src/commands/init.ts` around lines 319 - 329, The cancel/custom branches in the command handler use process.exit() which prevents the surrounding try/finally cleanup from running; change both branches (the checks on result.kind === 'cancelled' and result.kind === 'custom' where logger.break() is called) to set process.exitCode (e.g., 1 for cancelled, 0 for custom) and then return from the handler instead of calling process.exit() so the outer finally block executes as intended.
🧹 Nitpick comments (1)
packages/cli/scripts/test-preset-init.sh (1)
28-28: Remove the unusedREPO_DIRvariable.ShellCheck is right here: the path is never read, so it is just stale state to maintain in a smoke test.
Suggested fix
-REPO_DIR="$(cd "$CLI_DIR/../.." && pwd)"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/cli/scripts/test-preset-init.sh` at line 28, The script defines an unused variable REPO_DIR via the assignment REPO_DIR="$(cd "$CLI_DIR/../.." && pwd)" which is stale and flagged by ShellCheck; remove that line so the variable is not set or referenced, leaving the rest of test-preset-init.sh unchanged (no other code depends on REPO_DIR).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/cli/src/commands/init.ts`:
- Around line 277-282: The validation currently uses the `in` operator to check
`opts.preset` against `presetsByName`, which can match prototype properties;
change both checks that use `in` (the initial validation around opts.preset and
the later usage when resolving the preset) to use an own-property test like
`Object.prototype.hasOwnProperty.call(presetsByName, opts.preset)` so inherited
properties (e.g., "toString") are rejected; update the conditional that
references `presetsByName` and any later branch that indexes
`presetsByName[opts.preset]` to rely on this hasOwnProperty check before
treating the value as a valid preset.
---
Duplicate comments:
In `@packages/cli/src/commands/init.ts`:
- Around line 319-329: The cancel/custom branches in the command handler use
process.exit() which prevents the surrounding try/finally cleanup from running;
change both branches (the checks on result.kind === 'cancelled' and result.kind
=== 'custom' where logger.break() is called) to set process.exitCode (e.g., 1
for cancelled, 0 for custom) and then return from the handler instead of calling
process.exit() so the outer finally block executes as intended.
---
Nitpick comments:
In `@packages/cli/scripts/test-preset-init.sh`:
- Line 28: The script defines an unused variable REPO_DIR via the assignment
REPO_DIR="$(cd "$CLI_DIR/../.." && pwd)" which is stale and flagged by
ShellCheck; remove that line so the variable is not set or referenced, leaving
the rest of test-preset-init.sh unchanged (no other code depends on REPO_DIR).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dd01396d-3a29-4033-8d99-bcedfff590ee
📒 Files selected for processing (3)
packages/cli/scripts/test-preset-init.shpackages/cli/src/commands/init.tspackages/cli/src/preset/presets.ts
Summary
Fixes #1763. The
create/preset flow silently drops most of the design system config — font, theme, radius, menu color, chart palette, and generated CSS vars never reach the generated project. Only a handful of scalar fields were copied tocomponents.json, and even those diverged between the web encoder and CLI decoder.This PR mirrors shadcn-ui's preset pipeline so presets now deliver the full config.
What changed
Single source of truth — new
shadcn-vue/presetsubpath export (browser-safe, bit-packed encoder/decoder). Deletes the divergingapps/v4/lib/preset-encoding.ts; web composable +parse-preset-input.tsimport from the CLI package.Server — new Nuxt route
apps/v4/server/routes/init.get.tsdecodes the preset, validates viadesignSystemConfigSchema, and returns a fullregistry:baseitem via the existingbuildRegistryBase(extended to includefont,rtl,fontHeading).CLI — new
packages/cli/src/preset/presets.tswithDEFAULT_PRESETS,resolveInitUrl,resolveRegistryBaseConfig. Rewroteinit.tsaction to inject the/initURL intocomponents[0], fetch theregistry:baseitem, andmergeConfigitsconfiginto the finalcomponents.json— the same flow shadcn-ui uses.Sync — CLI
BASE_COLORSnow matches the web (neutral, stone, zinc, mauve, olive, mist, taupe);FONTSexpanded to the full 11 used by the site;rawConfigSchema.menuColorwidened to include translucent variants.Removed — old
packages/cli/src/utils/preset-encoding.ts,resolvePreset, and thePRESETSconstant (superseded byDEFAULT_PRESETS).Breaking
4PLVH59KVRVY6) no longer decode. New codes use a version-prefixed bit-packed format (a…). Old codes never applied correctly anyway, so existing users aren't losing working behavior.reka-vega/reka-nova/… tovega/nova/… to match shadcn-ui.--font geist→--font geist-sans(aligned with web registryfont-geist-sans).--base-color gray/slateremoved; addedmauve/olive/mist/taupe.Test plan
pnpm testinpackages/cli— 392 pass, 0 new failurespnpm typecheckinpackages/cli— no new errors (unrelated pre-existing only)pnpm buildinpackages/cli—dist/preset/index.{js,d.ts}emittedpnpm nuxt typecheckinapps/v4— no new errors (one fewer than main)bunx shadcn-vue@latest init --preset <code> --template viteon a fresh Vite app, confirmcomponents.jsonreflects the selected font / base color and that the generated style.css has the correct theme tokens🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements
Tests / Tools