diff --git a/.agents/skills/classic-to-default-sync/SKILL.md b/.agents/skills/classic-to-default-sync/SKILL.md deleted file mode 100644 index 282e049..0000000 --- a/.agents/skills/classic-to-default-sync/SKILL.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -name: classic-to-default-sync -description: Inspect a given commit's web/classic changes and sync all features/fixes to web/default. Use when the user provides a commit ID and wants to audit whether web/default already has the same features as web/classic, port missing features, improve suboptimal implementations, fix bugs, and remove redundant code. Trigger phrases include: "/classic-to-default-sync ", "classic-to-default-sync ", "sync classic to default", "port from classic", "compare classic commit", "classic 和 default 对比", "把这次 classic 的修改同步到 default", "查看这次提交 classic 中的修改并同步", or any request supplying a commit hash together with classic/default comparison intent. ---- - -# Classic-to-Default Sync - -Given a **commit ID**, audit all `web/classic` changes and ensure `web/default` reaches feature parity with the best possible implementation. - -## Input - -The user must supply a ``. - -## Workflow - -### Step 1 — Extract classic diff - -```bash -git show -- web/classic -``` - -Read every changed file in `web/classic`. Identify the **logical changes** (new features, UI/UX improvements, bug fixes, config tweaks, removed dead code, etc.) — not just line diffs. - -### Step 2 — Map to default counterparts - -For each logical change found in Step 1, locate the equivalent file(s) in `web/default/src/`. Use Glob/Grep/SemanticSearch as needed. Consider that: - -- `web/classic` uses **React 18 + Vite + Semi Design** -- `web/default` uses **React 19 + Rsbuild + Base UI + Tailwind CSS** -- Component names, file paths, and API shapes may differ; match by **functionality**, not filename. - -### Step 3 — Triage each change - -Classify every logical change as one of: - -| Status | Meaning | -|--------|---------| -| ✅ Already present & optimal | No action needed | -| ⚠️ Present but suboptimal | Improve: logic, layout, style, or code quality | -| ❌ Missing | Implement from scratch in default's stack | - -### Step 4 — Implement - -For each **⚠️** or **❌** item: - -1. **Read the target file(s) in `web/default`** before editing (required by project conventions). -2. Implement using `web/default` conventions: - - React 19 patterns (hooks, Suspense, etc.) - - Base UI primitives where applicable - - Tailwind CSS for styling (no inline styles or Semi Design imports) - - `useTranslation()` + `t('English key')` for all user-visible strings - - TypeScript — explicit types, no `any` - - No dead code, no redundant comments -3. Follow **Rule 6** (pointer types for optional relay DTOs) if touching relay-related TS types. -4. After editing, run `ReadLints` on changed files and fix any introduced lint errors. - -### Step 5 — i18n - -If any new user-visible strings were added, run the i18n sync: - -```bash -cd web/default && bun run i18n:sync -``` - -Then add missing translations for all supported locales (en, zh, fr, ja, ru, vi) following the **i18n-translate** skill. - -### Step 6 — Report - -Summarise the work in a concise table: - -| # | Change (from classic commit) | Status | Action taken | -|---|------------------------------|--------|--------------| -| 1 | … | ✅ / ⚠️ / ❌ | None / Improved / Implemented | - -If every item is ✅ with no action needed, simply reply: **"已完成 — web/default 已具备此次提交的所有功能,且实现质量良好,无需修改。"** - -## Quality bar - -- No unused imports, variables, or components -- No commented-out code left behind -- Consistent naming with surrounding `web/default` code -- All interactive elements accessible (keyboard nav, ARIA labels where Radix doesn't provide them automatically) -- No regressions: existing behaviour in `web/default` must not break diff --git a/.agents/skills/i18n-translate/SKILL.md b/.agents/skills/i18n-translate/SKILL.md deleted file mode 100644 index 26f1ba6..0000000 --- a/.agents/skills/i18n-translate/SKILL.md +++ /dev/null @@ -1,254 +0,0 @@ ---- -name: i18n-translate -description: >- - Complete and maintain frontend i18n translations for this project. Covers - finding missing translation keys, detecting untranslated entries, and adding - translations for all supported locales (en, zh, fr, ja, ru, vi). Use when the - user asks to add translations, fix i18n, complete missing translations, or - when new UI text needs to be internationalized. ---- - -# Frontend i18n Translation Workflow - -## Overview - -- Locale files: `web/default/src/i18n/locales/{en,zh,fr,ja,ru,vi}.json` -- Format: flat JSON under `"translation"` key, keys are English source strings -- Base locale: `en.json` (most keys), fallback: `zh` (Chinese) -- Sync script: `bun run i18n:sync` (from `web/default/`) -- All `t()` calls must have corresponding keys in every locale file - -## Workflow - -### Step 1: Run sync and read report - -```bash -cd web/default && bun run i18n:sync -``` - -Read `web/default/src/i18n/locales/_reports/_sync-report.json` to see per-locale status (missingCount, extrasCount, untranslatedCount). - -### Step 2: Find missing keys (used in code but not in locale files) - -Create and run `web/default/scripts/find-missing-keys.mjs`: - -```javascript -import fs from 'node:fs/promises' -import path from 'node:path' - -const LOCALES_DIR = path.resolve('src/i18n/locales') -const SRC_DIR = path.resolve('src') - -const en = JSON.parse(await fs.readFile(path.join(LOCALES_DIR, 'en.json'), 'utf8')) -const enKeys = new Set(Object.keys(en.translation)) - -const tCallRegex = /\bt\(\s*['"`]([^'"`\n]+?)['"`]\s*[,)]/g -const tCallMultilineRegex = /\bt\(\s*['"`]([^'"`]+?)['"`]\s*\)/g - -async function walkDir(dir) { - const files = [] - const entries = await fs.readdir(dir, { withFileTypes: true }) - for (const entry of entries) { - const fullPath = path.join(dir, entry.name) - if (entry.isDirectory()) { - if (['node_modules', '.git', 'locales', '_reports', '_extras'].includes(entry.name)) continue - files.push(...(await walkDir(fullPath))) - } else if (/\.(tsx?|jsx?)$/.test(entry.name)) { - files.push(fullPath) - } - } - return files -} - -const files = await walkDir(SRC_DIR) -const missingKeys = new Map() - -for (const file of files) { - const content = await fs.readFile(file, 'utf8') - const relPath = path.relative(SRC_DIR, file) - for (const regex of [tCallRegex, tCallMultilineRegex]) { - regex.lastIndex = 0 - let match - while ((match = regex.exec(content)) !== null) { - const key = match[1] - if (key.startsWith('{{') || key.includes('${')) continue - if (!enKeys.has(key)) { - if (!missingKeys.has(key)) missingKeys.set(key, []) - missingKeys.get(key).push(relPath) - } - } - } -} - -if (missingKeys.size === 0) { - console.log('All t() keys found in en.json!') -} else { - console.log(`Found ${missingKeys.size} missing keys:\n`) - for (const [key, files] of [...missingKeys.entries()].sort(([a], [b]) => a.localeCompare(b))) { - console.log(` "${key}"`) - for (const f of [...new Set(files)]) console.log(` -> ${f}`) - } -} -``` - -### Step 3: Find untranslated entries (value equals English) - -Create and run `web/default/scripts/find-untranslated.mjs`: - -```javascript -import fs from 'node:fs/promises' -import path from 'node:path' - -const LOCALES_DIR = path.resolve('src/i18n/locales') -const en = JSON.parse(await fs.readFile(path.join(LOCALES_DIR, 'en.json'), 'utf8')) -const enTrans = en.translation - -// Brand names, URLs, technical terms — skip these -const skipPatterns = [ - /^https?:\/\//, /^smtp\./, /^socks5:/, /^name@/, /^noreply@/, - /^org-/, /^price_/, /^whsec_/, /^edit_this$/, /^my-status$/, - /^_copy$/, /^gpt-/, /^checkout\./, /^footer\./, /^\[?\{/, - /^"default/, /^\/status\//, /^\/your\//, /^example\.com/, - /^AZURE_/, /^AccessKey/, /^OAuth/, /^Client /, /^Webhook URL/, - /^API URL$/, /^Well-Known/, /^Worker URL$/, /^Uptime Kuma/, - /^New API/, /^Baidu V2$/, /^Zhipu V4$/, /^Quota:$/, -] - -const brandNames = new Set([ - 'AIGC2D','Anthropic','API2GPT','Claude','Cloudflare','Cohere','DeepSeek', - 'Discord','DoubaoVideo','FastGPT','Gemini','GitHub','Jimeng','JustSong', - 'LingYiWanWu','LinuxDO','Midjourney','MidjourneyPlus','MiniMax','Mistral', - 'MokaAI','Moonshot','NewAPI','OhMyGPT','Ollama','OpenAI','OpenAIMax', - 'OpenRouter','Passkey','Perplexity','QuantumNous','Replicate','SiliconFlow', - 'Stripe','Submodel','SunoAPI','Telegram','Tencent','Vertex AI','VolcEngine', - 'WeChat','Xinference','Xunfei','AI Proxy','One API', -]) - -const locales = ['fr', 'ja', 'ru', 'zh', 'vi'] - -for (const locale of locales) { - const locFile = JSON.parse(await fs.readFile(path.join(LOCALES_DIR, `${locale}.json`), 'utf8')) - const locTrans = locFile.translation - const untranslated = {} - - for (const [key, enVal] of Object.entries(enTrans)) { - const locVal = locTrans[key] - if (locVal === undefined || locVal !== enVal) continue - if (brandNames.has(key)) continue - if (skipPatterns.some(p => p.test(key))) continue - if (typeof enVal === 'string' && enVal.length < 4) continue - if (/[a-zA-Z]{3,}/.test(String(enVal))) untranslated[key] = enVal - } - - const count = Object.keys(untranslated).length - if (count > 0) { - console.log(`\n=== ${locale} (${count} untranslated) ===`) - for (const [k, v] of Object.entries(untranslated)) - console.log(` ${JSON.stringify(k)}: ${JSON.stringify(v)}`) - } else { - console.log(`\n=== ${locale}: all translated ===`) - } -} -``` - -### Step 4: Add translations - -Create `web/default/scripts/add-missing-keys.mjs` with this structure: - -```javascript -import fs from 'node:fs/promises' -import path from 'node:path' - -const LOCALES_DIR = path.resolve('src/i18n/locales') - -function stableStringify(obj) { - return JSON.stringify(obj, null, 2) + '\n' -} - -const newKeys = { - en: { /* "key": "English value" */ }, - zh: { /* "key": "中文翻译" */ }, - fr: { /* "key": "Traduction française" */ }, - ja: { /* "key": "日本語翻訳" */ }, - ru: { /* "key": "Русский перевод" */ }, - vi: { /* "key": "Bản dịch tiếng Việt" */ }, -} - -async function main() { - let totalAdded = 0 - - for (const [locale, trans] of Object.entries(newKeys)) { - const filePath = path.join(LOCALES_DIR, `${locale}.json`) - const json = JSON.parse(await fs.readFile(filePath, 'utf8')) - - let count = 0 - for (const [key, value] of Object.entries(trans)) { - if (!Object.prototype.hasOwnProperty.call(json.translation, key)) { - json.translation[key] = value - count++ - } else if (json.translation[key] !== value) { - json.translation[key] = value - count++ - } - } - - if (count > 0) { - json.translation = Object.fromEntries( - Object.entries(json.translation).sort(([a], [b]) => a.localeCompare(b)) - ) - await fs.writeFile(filePath, stableStringify(json), 'utf8') - } - - console.log(`${locale}: ${count} translations applied`) - totalAdded += count - } - - console.log(`\nTotal: ${totalAdded} translations applied`) -} - -main().catch((err) => { console.error(err); process.exitCode = 1 }) -``` - -Populate the `newKeys` object with actual translations for each locale. - -### Step 5: Verify and clean up - -```bash -cd web/default -node scripts/add-missing-keys.mjs # apply translations -node scripts/find-missing-keys.mjs # verify: should say "All t() keys found" -bun run i18n:sync # normalize file order -``` - -Delete temporary scripts after completion. - -## Translation Guidelines - -| Language | Code | Notes | -|----------|------|-------| -| English | en | Base locale, key = value | -| Chinese | zh | Fallback locale, must be complete | -| French | fr | Many English cognates are valid (e.g., "Configuration") | -| Japanese | ja | Use katakana for technical loanwords | -| Russian | ru | Use formal register | -| Vietnamese | vi | Use standard Vietnamese | - -**Keep as English (do not translate):** -- Brand/product names (OpenAI, Claude, Gemini, etc.) -- URLs and email placeholders -- Technical identifiers (JSON keys, API paths, model names) -- Code-like strings (gpt-3.5-turbo, price_xxx, etc.) - -**Always translate:** -- UI labels, button text, error messages, descriptions -- Time units (hours, minutes, months, years) -- Action words (Move, Show, Delete, etc.) - -## Key Rules - -1. All scripts run from `web/default/` directory -2. Use `node scripts/xxx.mjs` (ESM format with top-level await) -3. Sort keys alphabetically when writing locale files -4. Always run `bun run i18n:sync` as the final step -5. Delete temporary scripts after completion -6. The `{{variable}}` placeholders in keys must be preserved in all translations diff --git a/.agents/skills/shadcn-ui/SKILL.md b/.agents/skills/shadcn-ui/SKILL.md deleted file mode 100644 index 8307cdc..0000000 --- a/.agents/skills/shadcn-ui/SKILL.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -name: shadcn-ui -description: >- - Give the assistant project-aware shadcn/ui context: components.json, - composition patterns, CLI, registries, theming, and MCP. Use when working on - web/default UI, shadcn components, or presets. Overview aligns with - https://ui.shadcn.com/docs/skills.md; full upstream skill text is vendored - under vendor/shadcn/. ---- - - - -# Skills (shadcn/ui) - -Skills give AI assistants project-aware context about shadcn/ui. When used, the assistant knows how to find, install, compose, and customize components using the correct APIs and patterns for your project. - -For example, you can ask: - -- _"Add a login form with email and password fields."_ -- _"Create a settings page with a form for updating profile information."_ -- _"Build a dashboard with a sidebar, stats cards, and a data table."_ -- _"Switch to --preset [CODE]"_ -- _"Can you add a hero from @tailark?"_ - -The skill reads your project's `components.json` and provides your framework, aliases, installed components, icon library, and base library so it can generate correct code on the first try. - ---- - -## Install (ecosystem vs this repo) - -Official install from [Skills — shadcn/ui](https://ui.shadcn.com/docs/skills.md): - -```bash -npx skills add shadcn/ui -``` - -That installs the skill where the `skills` CLI is available. **This repository** keeps the same intent under `.agents/skills/shadcn-ui/` (overview here + **vendored** upstream docs in [`vendor/shadcn/`](./vendor/shadcn/)) and runs the shadcn CLI from the frontend app root: - -```bash -cd web/default && bunx shadcn@latest info --json -``` - -Learn more about skills at [skills.sh](https://skills.sh). - ---- - -## What's included (and where) - -### Project context - -Run **`shadcn info --json`** (here: `cd web/default && bunx shadcn@latest info --json`) for framework, Tailwind version, aliases, base (`radix` | `base`), icon library, installed components, and resolved paths. - -### CLI commands - -Full command reference (vendored): [`vendor/shadcn/cli.md`](./vendor/shadcn/cli.md). - -### Theming and customization - -Vendored: [`vendor/shadcn/customization.md`](./vendor/shadcn/customization.md). Live docs: [Theming](https://ui.shadcn.com/docs/theming). - -### Registry authoring - -Not duplicated as a single file in the vendor tree; see [Registry](https://ui.shadcn.com/docs/registry) and `build` in [`vendor/shadcn/cli.md`](./vendor/shadcn/cli.md). - -### MCP server - -Vendored: [`vendor/shadcn/mcp.md`](./vendor/shadcn/mcp.md). Live docs: [MCP Server](https://ui.shadcn.com/docs/mcp). - ---- - -## How it works - -1. **Project detection** — Applies when `components.json` exists (here: `web/default/components.json`). -2. **Context injection** — Use `shadcn info --json` as ground truth for imports and APIs. -3. **Pattern enforcement** — Follow rules in [`vendor/shadcn/SKILL.md`](./vendor/shadcn/SKILL.md) and [`vendor/shadcn/rules/`](./vendor/shadcn/rules/). -4. **Component discovery** — `shadcn docs`, `shadcn search`, MCP, or registries — see vendored SKILL + MCP doc. - ---- - -## Learn more (web) - -- [CLI](https://ui.shadcn.com/docs/cli) — complements [`vendor/shadcn/cli.md`](./vendor/shadcn/cli.md) -- [Theming](https://ui.shadcn.com/docs/theming) -- [Registry](https://ui.shadcn.com/docs/registry) -- [skills.sh](https://skills.sh) - ---- - -## Vendored upstream bundle (deep rules) - -Snapshot from [shadcn-ui/ui `skills/shadcn`](https://github.com/shadcn-ui/ui/tree/main/skills/shadcn); revision note in [`vendor/shadcn/UPSTREAM.txt`](./vendor/shadcn/UPSTREAM.txt). - -| Doc | Path | -| --- | --- | -| Full official skill body | [`vendor/shadcn/SKILL.md`](./vendor/shadcn/SKILL.md) | -| CLI reference | [`vendor/shadcn/cli.md`](./vendor/shadcn/cli.md) | -| Theming / customization | [`vendor/shadcn/customization.md`](./vendor/shadcn/customization.md) | -| MCP | [`vendor/shadcn/mcp.md`](./vendor/shadcn/mcp.md) | -| Forms | [`vendor/shadcn/rules/forms.md`](./vendor/shadcn/rules/forms.md) | -| Composition | [`vendor/shadcn/rules/composition.md`](./vendor/shadcn/rules/composition.md) | -| Icons | [`vendor/shadcn/rules/icons.md`](./vendor/shadcn/rules/icons.md) | -| Styling | [`vendor/shadcn/rules/styling.md`](./vendor/shadcn/rules/styling.md) | -| Base vs Radix | [`vendor/shadcn/rules/base-vs-radix.md`](./vendor/shadcn/rules/base-vs-radix.md) | - -**Workflow:** Prefer this **root** `SKILL.md` for repo paths (`web/default`, Bun). Read **`vendor/shadcn/SKILL.md`** for the complete upstream workflow, patterns, and CLI quick reference. Use **`vendor/shadcn/rules/*.md`** when validating concrete markup. diff --git a/.agents/skills/shadcn-ui/vendor/shadcn/SKILL.md b/.agents/skills/shadcn-ui/vendor/shadcn/SKILL.md deleted file mode 100644 index 016f824..0000000 --- a/.agents/skills/shadcn-ui/vendor/shadcn/SKILL.md +++ /dev/null @@ -1,260 +0,0 @@ ---- -name: shadcn -description: Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset". -user-invocable: false -allowed-tools: Bash(npx shadcn@latest *), Bash(pnpm dlx shadcn@latest *), Bash(bunx --bun shadcn@latest *) ---- - -# shadcn/ui - -A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI. - -> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest` — based on the project's `packageManager`. Examples below use `npx shadcn@latest` but substitute the correct runner for the project. - -## Current Project Context - -```json -!`npx shadcn@latest info --json` -``` - -The JSON above contains the project config and installed components. Use `npx shadcn@latest docs ` to get documentation and example URLs for any component. - -## Principles - -1. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too. -2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table. -3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc. -4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`. - -## Critical Rules - -These rules are **always enforced**. Each links to a file with Incorrect/Correct code pairs. - -### Styling & Tailwind → [styling.md](./rules/styling.md) - -- **`className` for layout, not styling.** Never override component colors or typography. -- **No `space-x-*` or `space-y-*`.** Use `flex` with `gap-*`. For vertical stacks, `flex flex-col gap-*`. -- **Use `size-*` when width and height are equal.** `size-10` not `w-10 h-10`. -- **Use `truncate` shorthand.** Not `overflow-hidden text-ellipsis whitespace-nowrap`. -- **No manual `dark:` color overrides.** Use semantic tokens (`bg-background`, `text-muted-foreground`). -- **Use `cn()` for conditional classes.** Don't write manual template literal ternaries. -- **No manual `z-index` on overlay components.** Dialog, Sheet, Popover, etc. handle their own stacking. - -### Forms & Inputs → [forms.md](./rules/forms.md) - -- **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout. -- **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never raw `Input`/`Textarea` inside `InputGroup`. -- **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.** -- **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` with manual active state. -- **`FieldSet` + `FieldLegend` for grouping related checkboxes/radios.** Don't use a `div` with a heading. -- **Field validation uses `data-invalid` + `aria-invalid`.** `data-invalid` on `Field`, `aria-invalid` on the control. For disabled: `data-disabled` on `Field`, `disabled` on the control. - -### Component Structure → [composition.md](./rules/composition.md) - -- **Items always inside their Group.** `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`. -- **Use `asChild` (radix) or `render` (base) for custom triggers.** Check `base` field from `npx shadcn@latest info`. → [base-vs-radix.md](./rules/base-vs-radix.md) -- **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden. -- **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`. -- **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`. -- **`TabsTrigger` must be inside `TabsList`.** Never render triggers directly in `Tabs`. -- **`Avatar` always needs `AvatarFallback`.** For when the image fails to load. - -### Use Components, Not Custom Markup → [composition.md](./rules/composition.md) - -- **Use existing components before custom markup.** Check if a component exists before writing a styled `div`. -- **Callouts use `Alert`.** Don't build custom styled divs. -- **Empty states use `Empty`.** Don't build custom empty state markup. -- **Toast via `sonner`.** Use `toast()` from `sonner`. -- **Use `Separator`** instead of `
` or `
`. -- **Use `Skeleton`** for loading placeholders. No custom `animate-pulse` divs. -- **Use `Badge`** instead of custom styled spans. - -### Icons → [icons.md](./rules/icons.md) - -- **Icons in `Button` use `data-icon`.** `data-icon="inline-start"` or `data-icon="inline-end"` on the icon. -- **No sizing classes on icons inside components.** Components handle icon sizing via CSS. No `size-4` or `w-4 h-4`. -- **Pass icons as objects, not string keys.** `icon={CheckIcon}`, not a string lookup. - -### CLI - -- **Never decode preset codes or build preset URLs manually.** Use `npx shadcn@latest preset decode `, `preset url `, or `preset open `. For project-aware preset detection, use `npx shadcn@latest preset resolve`. -- **Apply preset codes directly with the CLI.** Use `npx shadcn@latest apply ` for existing projects, or `npx shadcn@latest init --preset ` when initializing. - -## Key Patterns - -These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above. - -```tsx -// Form layout: FieldGroup + Field, not div + Label. - - - Email - - - - -// Validation: data-invalid on Field, aria-invalid on the control. - - Email - - Invalid email. - - -// Icons in buttons: data-icon, no sizing classes. - - -// Spacing: gap-*, not space-y-*. -
// correct -
// wrong - -// Equal dimensions: size-*, not w-* h-*. - // correct - // wrong - -// Status colors: Badge variants or semantic tokens, not raw colors. -+20.1% // correct -+20.1% // wrong -``` - -## Component Selection - -| Need | Use | -| -------------------------- | --------------------------------------------------------------------------------------------------- | -| Button/action | `Button` with appropriate variant | -| Form inputs | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` | -| Toggle between 2–5 options | `ToggleGroup` + `ToggleGroupItem` | -| Data display | `Table`, `Card`, `Badge`, `Avatar` | -| Navigation | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` | -| Overlays | `Dialog` (modal), `Sheet` (side panel), `Drawer` (bottom sheet), `AlertDialog` (confirmation) | -| Feedback | `sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` | -| Command palette | `Command` inside `Dialog` | -| Charts | `Chart` (wraps Recharts) | -| Layout | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` | -| Empty states | `Empty` | -| Menus | `DropdownMenu`, `ContextMenu`, `Menubar` | -| Tooltips/info | `Tooltip`, `HoverCard`, `Popover` | - -## Key Fields - -The injected project context contains these key fields: - -- **`aliases`** → use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode. -- **`isRSC`** → when `true`, components using `useState`, `useEffect`, event handlers, or browser APIs need `"use client"` at the top of the file. Always reference this field when advising on the directive. -- **`tailwindVersion`** → `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`. -- **`tailwindCssFile`** → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one. -- **`style`** → component visual treatment (e.g. `nova`, `vega`). -- **`base`** → primitive library (`radix` or `base`). Affects component APIs and available props. -- **`iconLibrary`** → determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`. -- **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc. -- **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA). -- **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`). -- **`preset`** → resolved preset code and values for the current project. Use `npx shadcn@latest preset resolve --json` when you only need preset information. - -See [cli.md — `info` command](./cli.md) for the full field reference. - -## Component Docs, Examples, and Usage - -Run `npx shadcn@latest docs ` to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content. - -```bash -npx shadcn@latest docs button dialog select -``` - -**When creating, fixing, debugging, or using a component, always run `npx shadcn@latest docs` and fetch the URLs first.** This ensures you're working with the correct API and usage patterns rather than guessing. - -## Workflow - -1. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh. -2. **Check installed components first** — before running `add`, always check the `components` list from project context or list the `resolvedPaths.ui` directory. Don't import components that haven't been added, and don't re-add ones already installed. -3. **Find components** — `npx shadcn@latest search`. -4. **Get docs and examples** — run `npx shadcn@latest docs ` to get URLs, then fetch them. Use `npx shadcn@latest view` to browse registry items you haven't installed. To preview changes to installed components, use `npx shadcn@latest add --diff`. -5. **Install or update** — `npx shadcn@latest add`. When updating existing components, use `--dry-run` and `--diff` to preview changes first (see [Updating Components](#updating-components) below). -6. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `npx shadcn@latest info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project. -7. **Review added components** — After adding a component or block from any registry, **always read the added files and verify they are correct**. Check for missing sub-components (e.g. `SelectItem` without `SelectGroup`), missing imports, incorrect composition, or violations of the [Critical Rules](#critical-rules). Also replace any icon imports with the project's `iconLibrary` from the project context (e.g. if the registry item uses `lucide-react` but the project uses `hugeicons`, swap the imports and icon names accordingly). Fix all issues before moving on. -8. **Registry must be explicit** — When the user asks to add a block or component, **do not guess the registry**. If no registry is specified (e.g. user says "add a login block" without specifying `@shadcn`, `@tailark`, etc.), ask which registry to use. Never default to a registry on behalf of the user. -9. **Switching presets** — Ask the user first: **overwrite**, **partial**, **merge**, or **skip**? - - **Inspect current preset**: `npx shadcn@latest preset resolve`. Use `--json` when you need structured values. - - **Inspect incoming preset**: `npx shadcn@latest preset decode `. Use `preset url ` or `preset open ` to share or open the preset builder. - - **Overwrite**: `npx shadcn@latest apply `. Overwrites detected components, fonts, and CSS variables. - - **Partial**: `npx shadcn@latest apply --only theme,font`. Updates only the selected preset parts without reinstalling UI components. Supported values are `theme` and `font`; comma-separated combinations are allowed. `icon` is intentionally not supported, because icon changes may require full component reinstall and transforms. - - **Merge**: `npx shadcn@latest init --preset --force --no-reinstall`, then run `npx shadcn@latest info` to list installed components, then for each installed component use `--dry-run` and `--diff` to [smart merge](#updating-components) it individually. - - **Skip**: `npx shadcn@latest init --preset --force --no-reinstall`. Only updates config and CSS, leaves components as-is. - - **Important**: Always run preset commands inside the user's project directory. `apply` only works in an existing project with a `components.json` file. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch/temp directory (e.g. for `--dry-run` comparisons), pass `--base ` explicitly — preset codes do not encode the base. - -## Updating Components - -When the user asks to update a component from upstream while keeping their local changes, use `--dry-run` and `--diff` to intelligently merge. **NEVER fetch raw files from GitHub manually — always use the CLI.** - -1. Run `npx shadcn@latest add --dry-run` to see all files that would be affected. -2. For each file, run `npx shadcn@latest add --diff ` to see what changed upstream vs local. -3. Decide per file based on the diff: - - No local changes → safe to overwrite. - - Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications. - - User says "just update everything" → use `--overwrite`, but confirm first. -4. **Never use `--overwrite` without the user's explicit approval.** - -## Quick Reference - -```bash -# Create a new project. -npx shadcn@latest init --name my-app --preset base-nova -npx shadcn@latest init --name my-app --preset a2r6bw --template vite - -# Create a monorepo project. -npx shadcn@latest init --name my-app --preset base-nova --monorepo -npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo - -# Initialize existing project. -npx shadcn@latest init --preset base-nova -npx shadcn@latest init --defaults # shortcut: --template=next --preset=nova (base style implied) - -# Apply a preset to an existing project. -npx shadcn@latest apply a2r6bw -npx shadcn@latest apply a2r6bw --only theme -npx shadcn@latest apply a2r6bw --only font -npx shadcn@latest apply a2r6bw --only theme,font - -# Inspect preset codes and project preset state. -npx shadcn@latest preset decode a2r6bw -npx shadcn@latest preset url a2r6bw -npx shadcn@latest preset open a2r6bw -npx shadcn@latest preset resolve -npx shadcn@latest preset resolve --json - -# Add components. -npx shadcn@latest add button card dialog -npx shadcn@latest add @magicui/shimmer-button -npx shadcn@latest add --all - -# Preview changes before adding/updating. -npx shadcn@latest add button --dry-run -npx shadcn@latest add button --diff button.tsx -npx shadcn@latest add @acme/form --view button.tsx - -# Search registries. -npx shadcn@latest search @shadcn -q "sidebar" -npx shadcn@latest search @tailark -q "stats" - -# Get component docs and example URLs. -npx shadcn@latest docs button dialog select - -# View registry item details (for items not yet installed). -npx shadcn@latest view @shadcn/button -``` - -**Named presets:** `nova`, `vega`, `maia`, `lyra`, `mira`, `luma` -**Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`) and `laravel` (not supported for monorepo) -**Preset codes:** Version-prefixed base62 strings (e.g. `a2r6bw` or `b0`), from [ui.shadcn.com](https://ui.shadcn.com). - -## Detailed References - -- [rules/forms.md](./rules/forms.md) — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states -- [rules/composition.md](./rules/composition.md) — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading -- [rules/icons.md](./rules/icons.md) — data-icon, icon sizing, passing icons as objects -- [rules/styling.md](./rules/styling.md) — Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index -- [rules/base-vs-radix.md](./rules/base-vs-radix.md) — asChild vs render, Select, ToggleGroup, Slider, Accordion -- [cli.md](./cli.md) — Commands, flags, presets, templates -- [customization.md](./customization.md) — Theming, CSS variables, extending components diff --git a/.agents/skills/shadcn-ui/vendor/shadcn/UPSTREAM.txt b/.agents/skills/shadcn-ui/vendor/shadcn/UPSTREAM.txt deleted file mode 100644 index c065d2e..0000000 --- a/.agents/skills/shadcn-ui/vendor/shadcn/UPSTREAM.txt +++ /dev/null @@ -1,3 +0,0 @@ -Source: https://github.com/shadcn-ui/ui/tree/56161142f1b83f612462772d18883807b5f0d601/skills/shadcn -Branch: main -Fetched: 2026-04-29 diff --git a/.agents/skills/shadcn-ui/vendor/shadcn/cli.md b/.agents/skills/shadcn-ui/vendor/shadcn/cli.md deleted file mode 100644 index c3a0f0a..0000000 --- a/.agents/skills/shadcn-ui/vendor/shadcn/cli.md +++ /dev/null @@ -1,276 +0,0 @@ -# shadcn CLI Reference - -Configuration is read from `components.json`. - -> **IMPORTANT:** Always run commands using the project's package runner: `npx shadcn@latest`, `pnpm dlx shadcn@latest`, or `bunx --bun shadcn@latest`. Check `packageManager` from project context to choose the right one. Examples below use `npx shadcn@latest` but substitute the correct runner for the project. - -> **IMPORTANT:** Only use the flags documented below. Do not invent or guess flags — if a flag isn't listed here, it doesn't exist. The CLI auto-detects the package manager from the project's lockfile; there is no `--package-manager` flag. - -## Contents - -- Commands: init, apply, add (dry-run, smart merge), search, view, docs, info, build -- Templates: next, vite, start, react-router, astro -- Presets: named, code, URL formats and fields -- Switching presets - ---- - -## Commands - -### `init` — Initialize or create a project - -```bash -npx shadcn@latest init [components...] [options] -``` - -Initializes shadcn/ui in an existing project or creates a new project (when `--name` is provided). Optionally installs components in the same step. - -| Flag | Short | Description | Default | -| ----------------------- | ----- | --------------------------------------------------------- | ------- | -| `--template