@owlmeans/agent-skills 0.1.8
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/README.md +92 -0
- package/agent-meta/instructions/shadcn-versions.instructions.md +46 -0
- package/agent-meta/instructions/shadcn-web.instructions.md +94 -0
- package/agent-meta/manifest.json +37 -0
- package/agent-meta/skills/shadcn-versions/SKILL.md +126 -0
- package/agent-meta/skills/shadcn-web/SKILL.md +222 -0
- package/build/apply.d.ts +13 -0
- package/build/apply.d.ts.map +1 -0
- package/build/apply.js +28 -0
- package/build/apply.js.map +1 -0
- package/build/args.d.ts +14 -0
- package/build/args.d.ts.map +1 -0
- package/build/args.js +93 -0
- package/build/args.js.map +1 -0
- package/build/bin.d.ts +3 -0
- package/build/bin.d.ts.map +1 -0
- package/build/bin.js +21 -0
- package/build/bin.js.map +1 -0
- package/build/discover.d.ts +41 -0
- package/build/discover.d.ts.map +1 -0
- package/build/discover.js +160 -0
- package/build/discover.js.map +1 -0
- package/build/index.d.ts +11 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +6 -0
- package/build/index.js.map +1 -0
- package/build/linked.d.ts +15 -0
- package/build/linked.d.ts.map +1 -0
- package/build/linked.js +44 -0
- package/build/linked.js.map +1 -0
- package/build/plan.d.ts +15 -0
- package/build/plan.d.ts.map +1 -0
- package/build/plan.js +40 -0
- package/build/plan.js.map +1 -0
- package/build/prompt.d.ts +4 -0
- package/build/prompt.d.ts.map +1 -0
- package/build/prompt.js +21 -0
- package/build/prompt.js.map +1 -0
- package/build/run.d.ts +18 -0
- package/build/run.d.ts.map +1 -0
- package/build/run.js +124 -0
- package/build/run.js.map +1 -0
- package/package.json +37 -0
- package/src/apply.ts +38 -0
- package/src/args.ts +108 -0
- package/src/bin.ts +20 -0
- package/src/discover.ts +202 -0
- package/src/index.ts +14 -0
- package/src/linked.ts +51 -0
- package/src/plan.ts +69 -0
- package/src/prompt.ts +25 -0
- package/src/run.ts +167 -0
- package/tests/installer.test.ts +297 -0
- package/tsconfig.json +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# @owlmeans/agent-skills
|
|
2
|
+
|
|
3
|
+
CLI installer that lifts embedded Claude Code skills and GitHub Copilot instructions
|
|
4
|
+
out of installed `@owlmeans/*` packages and places them into your project's native
|
|
5
|
+
agent-guidance locations.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
After installing `@owlmeans/*` packages, run once:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx @owlmeans/agent-skills
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The installer scans `node_modules/@owlmeans/*/agent-meta/`, shows you what guidance
|
|
16
|
+
is available, and (with your confirmation) copies it into:
|
|
17
|
+
|
|
18
|
+
- **Claude Code**: `.claude/skills/<name>/SKILL.md`
|
|
19
|
+
- **GitHub Copilot**: `.github/instructions/<name>.instructions.md`
|
|
20
|
+
|
|
21
|
+
Re-run after updating `@owlmeans/*` packages to pick up revised guidance.
|
|
22
|
+
|
|
23
|
+
## Flags
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
--dir <path> target project directory (default: current working directory)
|
|
27
|
+
--yes, -y skip interactive confirmation (non-destructive; conflicts still skip)
|
|
28
|
+
--only <pkg,...> install guidance from these packages only (comma-separated @owlmeans/* names)
|
|
29
|
+
--claude-only install only Claude Code skills (.claude/skills/)
|
|
30
|
+
--copilot-only install only Copilot instructions (.github/instructions/)
|
|
31
|
+
--extras include extras bundled in the installer itself (default: on)
|
|
32
|
+
--no-extras skip extras bundled in the installer
|
|
33
|
+
--force overwrite locally-edited files (no AUTO-GENERATED banner)
|
|
34
|
+
--dry-run print plan without writing any files
|
|
35
|
+
--help, -h show this help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Conflict policy
|
|
39
|
+
|
|
40
|
+
Files managed by the installer carry an `AUTO-GENERATED` banner. On re-run:
|
|
41
|
+
|
|
42
|
+
- **Managed files** (banner present) — always updated to the latest embedded version.
|
|
43
|
+
- **Locally-edited files** (no banner) — **skipped** and reported as conflicts by default.
|
|
44
|
+
Pass `--force` to overwrite, or confirm individually in interactive mode.
|
|
45
|
+
|
|
46
|
+
## Extras (shadcn)
|
|
47
|
+
|
|
48
|
+
The installer ships `shadcn-web` and `shadcn-versions` as bundled extras — design
|
|
49
|
+
system guidance that spans multiple packages and has no single lead package. These
|
|
50
|
+
are installed by default alongside package-specific guidance from `node_modules`.
|
|
51
|
+
|
|
52
|
+
## Linked monorepo
|
|
53
|
+
|
|
54
|
+
If any `@owlmeans/*` packages are **symlinked** (e.g. via a `libraries/` workspace
|
|
55
|
+
link in an OwlMeans monorepo), the installer refuses and exits with code 4. In that
|
|
56
|
+
setup agents already load guidance from the linked monorepo's root `.claude/skills/`
|
|
57
|
+
and `.github/instructions/` — running the installer would install stale copies.
|
|
58
|
+
|
|
59
|
+
Pass `--force` only if you understand this and want to proceed anyway.
|
|
60
|
+
|
|
61
|
+
## Schema
|
|
62
|
+
|
|
63
|
+
Each `@owlmeans/*` package ships its embedded guidance under:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
agent-meta/
|
|
67
|
+
manifest.json # package, version, entries list
|
|
68
|
+
skills/<name>/
|
|
69
|
+
SKILL.md # Claude Code skill
|
|
70
|
+
instructions/
|
|
71
|
+
<name>.instructions.md # GitHub Copilot instruction
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Embedded files are **generated and read-only**. To contribute guidance edits, open
|
|
75
|
+
a PR against [owlmeans/common](https://github.com/owlmeans/common).
|
|
76
|
+
|
|
77
|
+
<!-- owlmeans:agent-guidance:start -->
|
|
78
|
+
## Agent guidance
|
|
79
|
+
|
|
80
|
+
This package ships embedded Claude Code skills and GitHub Copilot instructions under
|
|
81
|
+
`agent-meta/`. After installing your `@owlmeans/*` packages, run the OwlMeans
|
|
82
|
+
agent-skills installer to place them into your project's native locations
|
|
83
|
+
(`.claude/skills/` and `.github/instructions/`):
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
npx @owlmeans/agent-skills
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The embedded files are version-matched to this package release. Do not edit them
|
|
90
|
+
directly — they are regenerated on each publish. To contribute guidance edits,
|
|
91
|
+
open a PR against the source monorepo.
|
|
92
|
+
<!-- owlmeans:agent-guidance:end -->
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to update Tailwind CSS, shadcn UI primitives, and related UI lib versions across shadcn-based OwlMeans packages. Distinct from the @owlmeans/* version sync (see versions.instructions.md).
|
|
3
|
+
applyTo: "**/components.json"
|
|
4
|
+
---
|
|
5
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
6
|
+
|
|
7
|
+
# shadcn + Tailwind version management
|
|
8
|
+
|
|
9
|
+
This covers **external UI dependency versions** across shadcn-based OwlMeans packages. It is separate from the `@owlmeans/*` version sync (see `versions.instructions.md`).
|
|
10
|
+
|
|
11
|
+
## What to update
|
|
12
|
+
|
|
13
|
+
- `tailwindcss`, `@tailwindcss/vite`, `@tailwindcss/postcss`
|
|
14
|
+
- `class-variance-authority`, `clsx`, `tailwind-merge`, `lucide-react`
|
|
15
|
+
- `@radix-ui/*` (added per component as primitives are copied in)
|
|
16
|
+
- Shadcn primitive `.tsx` files in `src/@/components/ui/` (copied source, not npm)
|
|
17
|
+
|
|
18
|
+
## Bumping npm versions
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Example: bump tailwindcss in a shadcn package (run per package)
|
|
22
|
+
sed -i 's/"tailwindcss": "[^"]*"/"tailwindcss": "^4.1.0"/g' <shadcn-package>/package.json
|
|
23
|
+
bun install
|
|
24
|
+
bun run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Re-syncing copied primitives
|
|
28
|
+
|
|
29
|
+
1. Find the new source for the component in shadcn GitHub.
|
|
30
|
+
2. Diff against the local copy to preserve any project-local changes.
|
|
31
|
+
3. Update the version comment: `// shadcn <name> — sourced from shadcn@<version> <date>`.
|
|
32
|
+
4. Run `bun run build` and category-D UI tests.
|
|
33
|
+
|
|
34
|
+
## Tailwind major upgrades
|
|
35
|
+
|
|
36
|
+
Follow the official Tailwind upgrade guide. Check `@theme` token compatibility and `@source` syntax. Update `@tailwindcss/vite` to a matching major version.
|
|
37
|
+
|
|
38
|
+
## Verification
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
bun run build
|
|
42
|
+
# Run category-D UI tests for shadcn packages
|
|
43
|
+
bun test --filter <shadcn-pkg-name> ./tests
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
See `.claude/skills/shadcn-versions/SKILL.md` for full procedure.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to build and maintain shadcn UI + Tailwind v4 web packages in OwlMeans Common. Load when editing components.json, tailwind.config.*, globals.css, or files under components/ui/.
|
|
3
|
+
applyTo: "**/components.json, **/tailwind.config.{ts,js,mjs}, **/globals.css, **/components/ui/**, **/@/lib/utils.ts"
|
|
4
|
+
---
|
|
5
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
6
|
+
|
|
7
|
+
# shadcn UI + Tailwind v4 — OwlMeans web packages
|
|
8
|
+
|
|
9
|
+
Shadcn-based web packages are the next-generation Web layer replacing `web-panel` (MUI). They wrap the same headless `@owlmeans/client-panel` logic and mirror `web-panel`'s package shape — swapping MUI for shadcn UI + Tailwind v4.
|
|
10
|
+
|
|
11
|
+
## The `@` contract — three invariants
|
|
12
|
+
|
|
13
|
+
1. **No shadcn registries.** Primitives are **hand-copied** into `src/@/components/ui/`. Never use `registries` in `components.json`.
|
|
14
|
+
2. **Same `@` import prefix as the final app.** Components import `@/components/ui/button`, `@/lib/utils`, etc. The build emits `@/…` verbatim (Bundler resolution). The app's bundler resolves `@` to its own shadcn copy. The package never ships its primitives as a public import.
|
|
15
|
+
3. **Local copy is dev/test-only.** `src/@/` exists so the package can build and test in isolation. Never expose `./@/*` in `package.json` exports.
|
|
16
|
+
|
|
17
|
+
## tsconfig — `@` alias setup
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"compilerOptions": {
|
|
22
|
+
"baseUrl": ".",
|
|
23
|
+
"paths": { "@/*": ["./src/@/*"] }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`moduleResolution: Bundler` (from `dep-config/tsconfig.base.json`) emits `@/…` verbatim — TypeScript resolves types via `paths` but does not rewrite the specifier.
|
|
29
|
+
|
|
30
|
+
## components.json
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
35
|
+
"style": "new-york",
|
|
36
|
+
"rsc": false,
|
|
37
|
+
"tsx": true,
|
|
38
|
+
"tailwind": { "config": "", "css": "src/@/globals.css", "baseColor": "neutral", "cssVariables": true },
|
|
39
|
+
"iconLibrary": "lucide",
|
|
40
|
+
"aliases": { "components": "@/components", "ui": "@/components/ui", "utils": "@/lib/utils", "lib": "@/lib", "hooks": "@/hooks" }
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`tailwind.config: ""` is required for Tailwind v4.
|
|
45
|
+
|
|
46
|
+
## Tailwind v4 — globals.css
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
@import "tailwindcss";
|
|
50
|
+
@source "../..";
|
|
51
|
+
@theme {
|
|
52
|
+
--color-primary: oklch(0.205 0 0);
|
|
53
|
+
--color-primary-foreground: oklch(0.985 0 0);
|
|
54
|
+
--color-destructive: oklch(0.577 0.245 27.325);
|
|
55
|
+
--color-border: oklch(0.922 0 0);
|
|
56
|
+
--radius: 0.625rem;
|
|
57
|
+
/* ... full token set in @owlmeans/shadcn-web reference.md ... */
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
In production, the **app owns its own `globals.css`**. The package's CSS is only for dev/test.
|
|
62
|
+
|
|
63
|
+
## Adding a primitive (no registry)
|
|
64
|
+
|
|
65
|
+
1. Copy `.tsx` source from shadcn GitHub into `src/@/components/ui/<name>.tsx`.
|
|
66
|
+
2. Repoint imports to `@/lib/utils` and `@/components/ui/…`.
|
|
67
|
+
3. Add any `@radix-ui/*` packages as **peerDependencies**.
|
|
68
|
+
4. Add comment: `// shadcn <name> — sourced from shadcn@<version> <date>`.
|
|
69
|
+
|
|
70
|
+
## Wrapping `@owlmeans/client-panel`
|
|
71
|
+
|
|
72
|
+
Replace MUI rendering in `web-panel` components with shadcn + Tailwind classes. The `FormProvider`, `useFormContext`, `Controller`, AJV resolver, and `useFormI18n` are unchanged — only JSX changes.
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
// MUI: <TextField {...field} label={label} error={...} />
|
|
76
|
+
// shadcn:
|
|
77
|
+
<div className="flex flex-col gap-1.5">
|
|
78
|
+
<Label htmlFor={field.name}>{label}</Label>
|
|
79
|
+
<Input id={field.name} {...field} aria-invalid={fieldState.error != null} />
|
|
80
|
+
{fieldState.error && <p className="text-sm text-destructive">{fieldState.error.message}</p>}
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## package.json peerDependencies
|
|
85
|
+
|
|
86
|
+
`class-variance-authority`, `clsx`, `tailwind-merge`, `lucide-react`, `react`, `react-dom`, `react-hook-form`, `tailwindcss`. Add `@radix-ui/*` per component copied.
|
|
87
|
+
|
|
88
|
+
## package.json exports — never expose `@/*`
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{ "exports": { ".": { "import": "./build/index.js", "types": "./build/index.d.ts" } } }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
See `.claude/skills/shadcn-web/SKILL.md` for the full pattern.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"package": "@owlmeans/agent-skills",
|
|
4
|
+
"version": "0.1.8",
|
|
5
|
+
"generatedAt": "2026-06-11T16:30:27.174Z",
|
|
6
|
+
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "skill",
|
|
10
|
+
"name": "shadcn-web",
|
|
11
|
+
"category": "multi-package",
|
|
12
|
+
"file": "skills/shadcn-web/SKILL.md",
|
|
13
|
+
"canonicalPath": ".claude/skills/shadcn-web/SKILL.md"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"kind": "skill",
|
|
17
|
+
"name": "shadcn-versions",
|
|
18
|
+
"category": "multi-package",
|
|
19
|
+
"file": "skills/shadcn-versions/SKILL.md",
|
|
20
|
+
"canonicalPath": ".claude/skills/shadcn-versions/SKILL.md"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"kind": "instruction",
|
|
24
|
+
"name": "shadcn-versions",
|
|
25
|
+
"category": "multi-package",
|
|
26
|
+
"file": "instructions/shadcn-versions.instructions.md",
|
|
27
|
+
"canonicalPath": ".github/instructions/shadcn-versions.instructions.md"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"kind": "instruction",
|
|
31
|
+
"name": "shadcn-web",
|
|
32
|
+
"category": "multi-package",
|
|
33
|
+
"file": "instructions/shadcn-web.instructions.md",
|
|
34
|
+
"canonicalPath": ".github/instructions/shadcn-web.instructions.md"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shadcn-versions
|
|
3
|
+
description: How to update versions of shadcn UI primitives, Tailwind CSS v4, and related UI libs across all shadcn-based OwlMeans web packages. Distinct from the @owlmeans/* package version sync (see [[versions]] skill). Use when bumping tailwind, shadcn components, or utility libs.
|
|
4
|
+
allowed-tools: Bash(grep *), Bash(sed *), Bash(bun install)
|
|
5
|
+
---
|
|
6
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
|
+
|
|
8
|
+
# shadcn + Tailwind version management — OwlMeans Common
|
|
9
|
+
|
|
10
|
+
This skill handles **external UI dependency versions** for the shadcn-based web packages. It is **distinct** from the `[[versions]]` skill, which manages the synchronized `@owlmeans/*` package version (`0.1.x` etc.).
|
|
11
|
+
|
|
12
|
+
## What this covers
|
|
13
|
+
|
|
14
|
+
| Package | Location | Notes |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `tailwindcss` | peerDependency + devDependency | core engine |
|
|
17
|
+
| `@tailwindcss/vite` | devDependency | Vite plugin for dev/test harness |
|
|
18
|
+
| `@tailwindcss/postcss` | devDependency | PostCSS fallback (if used) |
|
|
19
|
+
| `class-variance-authority` | peerDependency | `cva()` for component variants |
|
|
20
|
+
| `clsx` | peerDependency | conditional class names |
|
|
21
|
+
| `tailwind-merge` | peerDependency | merge Tailwind classes without conflicts |
|
|
22
|
+
| `lucide-react` | peerDependency | icon library |
|
|
23
|
+
| `@radix-ui/*` | peerDependency | per-component Radix UI primitives |
|
|
24
|
+
| shadcn primitives (copied) | source in `src/@/components/ui/` | hand-copied `.tsx` files — not npm |
|
|
25
|
+
|
|
26
|
+
Shadcn primitive `.tsx` files inside each package are **not** npm dependencies — they are copied source files. Updating them is a separate step (see below).
|
|
27
|
+
|
|
28
|
+
## Checking current versions
|
|
29
|
+
|
|
30
|
+
To see what versions installed `@owlmeans/*` shadcn packages declare:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Which tailwind version do installed OwlMeans shadcn packages use?
|
|
34
|
+
grep -r '"tailwindcss"' node_modules/@owlmeans/*/package.json
|
|
35
|
+
|
|
36
|
+
# Which tailwind-merge / clsx version?
|
|
37
|
+
grep -r '"tailwind-merge"\|"clsx"\|"class-variance-authority"' node_modules/@owlmeans/*/package.json
|
|
38
|
+
|
|
39
|
+
# Which @radix-ui/* versions?
|
|
40
|
+
grep -r '"@radix-ui/' node_modules/@owlmeans/*/package.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Bumping external UI lib versions
|
|
44
|
+
|
|
45
|
+
Shadcn packages use caret ranges in peerDependencies (e.g. `"tailwindcss": "*"` or `"tailwindcss": "^4.x"`). To pin to a specific version across all shadcn packages in the `@owlmeans/common` source repo, run these in the monorepo root (OwlMeans framework contributors):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Example: pin tailwindcss to ^4.1.0 across all shadcn packages
|
|
49
|
+
OLD_TW='\*' # or whatever the current range is
|
|
50
|
+
NEW_TW='^4.1.0'
|
|
51
|
+
|
|
52
|
+
# Update each shadcn package's package.json (run per package)
|
|
53
|
+
sed -i "s/\"tailwindcss\": \"$OLD_TW\"/\"tailwindcss\": \"$NEW_TW\"/g" <shadcn-package>/package.json
|
|
54
|
+
|
|
55
|
+
# Same pattern for other UI libs
|
|
56
|
+
sed -i 's/"tailwind-merge": "\*"/"tailwind-merge": "^2.5.0"/g' <shadcn-package>/package.json
|
|
57
|
+
sed -i 's/"clsx": "\*"/"clsx": "^2.1.0"/g' <shadcn-package>/package.json
|
|
58
|
+
|
|
59
|
+
bun install
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Always run `bun run build` and the category-D UI tests after bumping to catch breaking changes.
|
|
63
|
+
|
|
64
|
+
## Bumping the Vite plugin / PostCSS plugin
|
|
65
|
+
|
|
66
|
+
These are devDependencies only (used in the test harness, not production). Update them separately:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
sed -i 's/"@tailwindcss\/vite": "\*"/"@tailwindcss\/vite": "^4.1.0"/g' <shadcn-package>/package.json
|
|
70
|
+
bun install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Tailwind major version upgrades (v4 → v5, etc.)
|
|
74
|
+
|
|
75
|
+
1. Read the [Tailwind upgrade guide](https://tailwindcss.com/docs/upgrade-guide) for breaking changes.
|
|
76
|
+
2. Check `@theme` token compatibility — token names may change between major versions.
|
|
77
|
+
3. Check `@source` directive syntax changes.
|
|
78
|
+
4. Update `@tailwindcss/vite` and `@tailwindcss/postcss` to matching major versions.
|
|
79
|
+
5. Rebuild (`bun run build`) and run all category-D UI tests.
|
|
80
|
+
6. Update this skill and `[[shadcn-web]]` with the new conventions.
|
|
81
|
+
|
|
82
|
+
## Re-syncing copied shadcn primitives
|
|
83
|
+
|
|
84
|
+
When shadcn upstream releases a new version, manually update the hand-copied primitives:
|
|
85
|
+
|
|
86
|
+
1. **Find the changed component source** — check the shadcn GitHub diff or changelog.
|
|
87
|
+
2. **Get the new source** — copy from `https://ui.shadcn.com/r/<name>.json` (the raw file URL) or from the [shadcn GitHub](https://github.com/shadcn-ui/ui) (`registry/new-york/ui/<name>.tsx`).
|
|
88
|
+
3. **Diff against the local copy** to identify any project-local modifications (custom classes, extra props, i18n tweaks) that must be preserved.
|
|
89
|
+
4. **Apply changes**, preserving local modifications.
|
|
90
|
+
5. **Update the version comment** at the top of the file: `// shadcn <name> — sourced from shadcn@<version> <date>`.
|
|
91
|
+
6. **Check `components.json` schema** — if the shadcn schema version changed, update `"$schema"` URLs.
|
|
92
|
+
7. Run `bun run build` and UI tests.
|
|
93
|
+
|
|
94
|
+
## Keeping `@radix-ui/*` versions consistent
|
|
95
|
+
|
|
96
|
+
Radix UI packages are added as peerDependencies when primitives are copied in. Keep them consistent across packages:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Check radix versions in installed OwlMeans shadcn packages
|
|
100
|
+
grep -r '"@radix-ui/' node_modules/@owlmeans/*/package.json | grep -v node_modules
|
|
101
|
+
|
|
102
|
+
# Bump a specific radix package (run per shadcn package in the source repo)
|
|
103
|
+
sed -i 's/"@radix-ui\/react-slot": "[^"]*"/"@radix-ui\/react-slot": "^1.1.0"/g' <shadcn-package>/package.json
|
|
104
|
+
bun install
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Verification
|
|
108
|
+
|
|
109
|
+
After any version change:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Build all packages
|
|
113
|
+
bun run build
|
|
114
|
+
|
|
115
|
+
# Run category-D UI tests for shadcn packages
|
|
116
|
+
bun test --filter <shadcn-pkg-name> ./tests
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If category-D tests don't exist yet, at minimum load the harness URL manually to confirm components render without JS errors.
|
|
120
|
+
|
|
121
|
+
## Cross-references
|
|
122
|
+
|
|
123
|
+
- `[[versions]]` — synchronized `@owlmeans/*` package version (separate concern)
|
|
124
|
+
- `[[shadcn-web]]` — how to build/maintain shadcn-based OwlMeans packages
|
|
125
|
+
- `[[testing-ui]]` — category-D Playwright tests that verify UI after version bumps
|
|
126
|
+
- `[[bun]]` — bun install, workspace filter, build commands
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: shadcn-web
|
|
3
|
+
description: How to build and maintain shadcn UI + Tailwind v4 web packages in the OwlMeans framework. Auto-invoked when editing components.json, tailwind.config.*, globals.css, or files under components/ui/. Use when creating a new shadcn-based web package or adding shadcn components.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
|
+
|
|
8
|
+
# shadcn UI + Tailwind v4 web packages — OwlMeans pattern
|
|
9
|
+
|
|
10
|
+
Shadcn-based web packages are the **next-generation Web layer**, replacing MUI `web-panel` over time. They sit at the same architecture layer (Web), wrap the same headless `@owlmeans/client-panel` logic, and follow the same `web-panel` package shape — swapping MUI + Emotion for shadcn UI + Tailwind CSS v4.
|
|
11
|
+
|
|
12
|
+
See `reference.md` in this skill folder for full code examples (components.json, tsconfig, globals.css @theme tokens, peerDeps, cn(), MUI→shadcn mapping table).
|
|
13
|
+
|
|
14
|
+
## The `@` contract — core rule
|
|
15
|
+
|
|
16
|
+
Three invariants govern every shadcn-based OwlMeans package:
|
|
17
|
+
|
|
18
|
+
1. **No shadcn registries.** Primitives (Button, Input, Card, …) are **hand-copied** into `src/@/components/ui/` and committed. The `registries` field in `components.json` is always empty/absent.
|
|
19
|
+
|
|
20
|
+
2. **Same `@` import prefix as the final app.** Components inside the package import shadcn primitives as `@/components/ui/button`, `@/lib/utils`, etc. The build leaves `@/…` specifiers **verbatim** (TypeScript Bundler resolution never rewrites them). The downstream app's bundler resolves `@` to **its own** shadcn copy + theme. The package never ships its primitives as a public import.
|
|
21
|
+
|
|
22
|
+
3. **Local copy is dev/test-only.** Each package keeps its own copy under `src/@/` so it can build and test in isolation. The `package.json` `exports` map must **not** expose `./@/*` — consumers never accidentally import the package's copy.
|
|
23
|
+
|
|
24
|
+
## Package skeleton (mirrors `web-panel`)
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
<your-package>/
|
|
28
|
+
├── src/
|
|
29
|
+
│ ├── @/ # dev/test-only primitives — NOT a public export
|
|
30
|
+
│ │ ├── components/ui/ # hand-copied shadcn primitives
|
|
31
|
+
│ │ │ ├── button.tsx
|
|
32
|
+
│ │ │ └── input.tsx
|
|
33
|
+
│ │ ├── lib/
|
|
34
|
+
│ │ │ └── utils.ts # cn() utility
|
|
35
|
+
│ │ └── globals.css # Tailwind v4 entry (app provides its own in prod)
|
|
36
|
+
│ ├── components/ # OwlMeans framework components (wrap client-panel)
|
|
37
|
+
│ │ ├── form/
|
|
38
|
+
│ │ │ ├── component.tsx
|
|
39
|
+
│ │ │ ├── text/component.tsx
|
|
40
|
+
│ │ │ ├── button/component.tsx
|
|
41
|
+
│ │ │ ├── types.ts
|
|
42
|
+
│ │ │ └── index.ts
|
|
43
|
+
│ │ ├── layout/component.tsx
|
|
44
|
+
│ │ ├── panel-app/component.tsx
|
|
45
|
+
│ │ └── index.ts # barrel; re-exports @owlmeans/client-panel
|
|
46
|
+
│ ├── context.ts # makeContext wrapping web-client's makeContext
|
|
47
|
+
│ ├── main.tsx # render() — no theme arg (theme is pure CSS)
|
|
48
|
+
│ ├── types.ts
|
|
49
|
+
│ ├── modules.ts
|
|
50
|
+
│ └── index.ts
|
|
51
|
+
├── tests/
|
|
52
|
+
│ ├── harness/
|
|
53
|
+
│ │ ├── index.html # copy from @owlmeans/test-ui harness/index.html
|
|
54
|
+
│ │ └── mount.tsx # per-package: imports globals.css, registers components
|
|
55
|
+
│ ├── context.ts # boots Vite with @tailwindcss/vite + @ alias
|
|
56
|
+
│ └── *.spec.ts
|
|
57
|
+
├── components.json
|
|
58
|
+
├── package.json
|
|
59
|
+
└── tsconfig.json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## tsconfig setup
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"extends": [
|
|
67
|
+
"@owlmeans/dep-config/tsconfig.base.json",
|
|
68
|
+
"@owlmeans/dep-config/tsconfig.react.json"
|
|
69
|
+
],
|
|
70
|
+
"compilerOptions": {
|
|
71
|
+
"baseUrl": ".",
|
|
72
|
+
"paths": { "@/*": ["./src/@/*"] },
|
|
73
|
+
"rootDir": "./src/",
|
|
74
|
+
"outDir": "./build/"
|
|
75
|
+
},
|
|
76
|
+
"exclude": ["./dist/**/*", "./build/**/*", "./tests/**/*", "./*.ts"]
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`moduleResolution: Bundler` (from `tsconfig.base.json`) causes `tsc` to emit `@/…` verbatim. `paths` is used only for **type-checking** during build — it finds types for `@/components/ui/button` in `src/@/components/ui/button.tsx` without rewriting the emitted specifier.
|
|
81
|
+
|
|
82
|
+
## components.json
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
87
|
+
"style": "new-york",
|
|
88
|
+
"rsc": false,
|
|
89
|
+
"tsx": true,
|
|
90
|
+
"tailwind": {
|
|
91
|
+
"config": "",
|
|
92
|
+
"css": "src/@/globals.css",
|
|
93
|
+
"baseColor": "neutral",
|
|
94
|
+
"cssVariables": true,
|
|
95
|
+
"prefix": ""
|
|
96
|
+
},
|
|
97
|
+
"iconLibrary": "lucide",
|
|
98
|
+
"aliases": {
|
|
99
|
+
"components": "@/components",
|
|
100
|
+
"ui": "@/components/ui",
|
|
101
|
+
"utils": "@/lib/utils",
|
|
102
|
+
"lib": "@/lib",
|
|
103
|
+
"hooks": "@/hooks"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`tailwind.config: ""` is required for Tailwind v4 (no separate config file). Do not add a `registries` field.
|
|
109
|
+
|
|
110
|
+
## Tailwind v4 wiring
|
|
111
|
+
|
|
112
|
+
`src/@/globals.css` — the Tailwind entry used in dev/test only:
|
|
113
|
+
|
|
114
|
+
```css
|
|
115
|
+
@import "tailwindcss";
|
|
116
|
+
|
|
117
|
+
@source "../..";
|
|
118
|
+
|
|
119
|
+
@theme {
|
|
120
|
+
--color-background: oklch(1 0 0);
|
|
121
|
+
--color-foreground: oklch(0.145 0 0);
|
|
122
|
+
--color-primary: oklch(0.205 0 0);
|
|
123
|
+
--color-primary-foreground: oklch(0.985 0 0);
|
|
124
|
+
--color-destructive: oklch(0.577 0.245 27.325);
|
|
125
|
+
--color-border: oklch(0.922 0 0);
|
|
126
|
+
--color-input: oklch(0.922 0 0);
|
|
127
|
+
--color-ring: oklch(0.708 0 0);
|
|
128
|
+
--radius: 0.625rem;
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`@source "../.."` scans the package root. In the Vite dev/test harness, `@tailwindcss/vite` processes this CSS. The **production app owns its own `globals.css`** with its own `@theme` tokens — the package's CSS is only for tests.
|
|
133
|
+
|
|
134
|
+
## Adding a primitive without a registry
|
|
135
|
+
|
|
136
|
+
1. Find the component source on the [shadcn GitHub](https://github.com/shadcn-ui/ui) (e.g. `registry/new-york/ui/<name>.tsx`) or via `npx shadcn@latest add <name> --cwd <your-package-dir>` in a throwaway branch.
|
|
137
|
+
2. Copy the `.tsx` source into `src/@/components/ui/<name>.tsx`.
|
|
138
|
+
3. Repoint all imports to `@/lib/utils` and `@/components/ui/…` for sub-primitives.
|
|
139
|
+
4. Add any `@radix-ui/*` packages the file imports as **peerDependencies** in `package.json`.
|
|
140
|
+
5. Add a comment at the top: `// shadcn <name> — sourced from shadcn@<version> <date>`.
|
|
141
|
+
6. Run `bun install` and `bun run build` to verify.
|
|
142
|
+
|
|
143
|
+
## Wrapping `@owlmeans/client-panel`
|
|
144
|
+
|
|
145
|
+
Shadcn form/field components are the rendering layer over the framework-agnostic headless logic from `@owlmeans/client-panel`. Mirror the MUI pattern from `@owlmeans/web-panel` (form text component):
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
// MUI version (web-panel) — for reference
|
|
149
|
+
import { TextField } from '@mui/material'
|
|
150
|
+
// ...
|
|
151
|
+
<TextField {...field} label={label} error={fieldState.error != null} />
|
|
152
|
+
|
|
153
|
+
// shadcn version
|
|
154
|
+
import { Input } from '@/components/ui/input'
|
|
155
|
+
import { Label } from '@/components/ui/label'
|
|
156
|
+
// ...
|
|
157
|
+
<div className="flex flex-col gap-1.5">
|
|
158
|
+
<Label htmlFor={field.name}>{label}</Label>
|
|
159
|
+
<Input id={field.name} {...field} aria-invalid={fieldState.error != null} />
|
|
160
|
+
{fieldState.error && (
|
|
161
|
+
<p className="text-sm text-destructive">{fieldState.error.message}</p>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`FormProvider`, `useFormContext`, `Controller`, the AJV validation resolver, and `useFormI18n` from `@owlmeans/client-i18n` are unchanged — only the rendered JSX changes.
|
|
167
|
+
|
|
168
|
+
`panel-app/component.tsx` no longer needs MUI `ThemeProvider` or `CssBaseline`. It simply renders children. Theme is provided via the app's `globals.css` Tailwind entry.
|
|
169
|
+
|
|
170
|
+
## package.json exports
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"exports": {
|
|
175
|
+
".": {
|
|
176
|
+
"import": "./build/index.js",
|
|
177
|
+
"types": "./build/index.d.ts"
|
|
178
|
+
},
|
|
179
|
+
"./auth": {
|
|
180
|
+
"import": "./build/auth/index.js",
|
|
181
|
+
"types": "./build/auth/index.d.ts"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Do **not** add `./@/*` or `./src/@/*` to exports.
|
|
188
|
+
|
|
189
|
+
## Dev/test harness (Vite + @tailwindcss/vite)
|
|
190
|
+
|
|
191
|
+
See `[[testing-ui]]` for the full Playwright harness pattern. For shadcn packages the `tests/context.ts` Vite config adds the Tailwind plugin and the `@` alias:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
195
|
+
import { resolve } from 'node:path'
|
|
196
|
+
|
|
197
|
+
const server = await createServer({
|
|
198
|
+
configFile: false,
|
|
199
|
+
root: resolve(here, './harness'),
|
|
200
|
+
plugins: [react(), tailwindcss()],
|
|
201
|
+
resolve: {
|
|
202
|
+
alias: { '@': resolve(here, '../src/@') },
|
|
203
|
+
},
|
|
204
|
+
server: { port: 0 },
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`tests/harness/mount.tsx` imports the package globals.css so components render with Tailwind styles:
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
import '../../src/@/globals.css'
|
|
212
|
+
// ... dynamic component mounting ...
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Cross-references
|
|
216
|
+
|
|
217
|
+
- `[[client-panel]]` — headless form/layout logic being wrapped
|
|
218
|
+
- `[[web-panel]]` — MUI counterpart; the structural and API reference
|
|
219
|
+
- `[[testing-ui]]` — Playwright harness for component acceptance tests
|
|
220
|
+
- `[[shadcn-versions]]` — bumping tailwind/shadcn external deps across packages
|
|
221
|
+
- `[[tsconfig]]` — OwlMeans TypeScript config conventions
|
|
222
|
+
- `[[bun]]` — build, install, workspace filter scripts
|
package/build/apply.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { InstallItem } from './plan.js';
|
|
2
|
+
export interface ApplyResult {
|
|
3
|
+
installed: number;
|
|
4
|
+
updated: number;
|
|
5
|
+
skipped: number;
|
|
6
|
+
conflicts: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Execute an install plan. Items with action 'conflict' or 'skip-uptodate'
|
|
10
|
+
* are not written. Only 'install' and 'update' items are written.
|
|
11
|
+
*/
|
|
12
|
+
export declare const applyInstall: (items: InstallItem[]) => ApplyResult;
|
|
13
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,WAAW,EAAE,KAAG,WAsBnD,CAAA"}
|
package/build/apply.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Execute an install plan. Items with action 'conflict' or 'skip-uptodate'
|
|
5
|
+
* are not written. Only 'install' and 'update' items are written.
|
|
6
|
+
*/
|
|
7
|
+
export const applyInstall = (items) => {
|
|
8
|
+
const result = { installed: 0, updated: 0, skipped: 0, conflicts: 0 };
|
|
9
|
+
for (const item of items) {
|
|
10
|
+
if (item.action === 'skip-uptodate') {
|
|
11
|
+
result.skipped++;
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (item.action === 'conflict') {
|
|
15
|
+
result.conflicts++;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const content = readFileSync(item.entry.sourcePath, 'utf8');
|
|
19
|
+
mkdirSync(dirname(item.targetPath), { recursive: true });
|
|
20
|
+
writeFileSync(item.targetPath, content, 'utf8');
|
|
21
|
+
if (item.action === 'install')
|
|
22
|
+
result.installed++;
|
|
23
|
+
else
|
|
24
|
+
result.updated++;
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAUnC;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAe,EAAE;IAChE,MAAM,MAAM,GAAgB,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;IAElF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACpC,MAAM,CAAC,OAAO,EAAE,CAAA;YAChB,SAAQ;QACV,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC/B,MAAM,CAAC,SAAS,EAAE,CAAA;YAClB,SAAQ;QACV,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;QAC3D,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACxD,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QAE/C,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,SAAS,EAAE,CAAA;;YAC5C,MAAM,CAAC,OAAO,EAAE,CAAA;IACvB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
|