love-ui 1.2.15 → 1.2.17
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 +14 -6
- package/dist/index.js +149 -0
- package/dist/mcp-server.js +2 -0
- package/package.json +28 -4
- package/registry/default/examples/code-block-shared.tsx +8 -1
- package/registry/default/ui/form.tsx +6 -1
- package/registry/default/ui/toast-gooey-icons.tsx +68 -0
- package/registry/default/ui/toast-gooey-renderer.tsx +614 -0
- package/registry/default/ui/toast-gooey-types.ts +45 -0
- package/registry/default/ui/toast-gooey.css +511 -0
- package/registry/default/ui/toast-gooey.tsx +445 -0
- package/registry/default/ui/toast.tsx +1 -1
- package/skills/loveui-skills/SKILL.md +170 -0
- package/skills/loveui-skills/references/accessibility-baseline.md +32 -0
- package/skills/loveui-skills/references/component-api-and-naming.md +30 -0
- package/skills/loveui-skills/references/content-ux-writing.md +33 -0
- package/skills/loveui-skills/references/design-directions.md +60 -0
- package/skills/loveui-skills/references/forms-and-validation.md +30 -0
- package/skills/loveui-skills/references/frontend-architecture.md +30 -0
- package/skills/loveui-skills/references/interaction-heuristics.md +45 -0
- package/skills/loveui-skills/references/mcp-catalog-workflow.md +68 -0
- package/skills/loveui-skills/references/motion-and-feedback.md +31 -0
- package/skills/loveui-skills/references/navigation-and-information-architecture.md +30 -0
- package/skills/loveui-skills/references/page-blueprints.md +76 -0
- package/skills/loveui-skills/references/quality-gates.md +51 -0
- package/skills/loveui-skills/references/screenshot-translation-protocol.md +52 -0
- package/skills/loveui-skills/references/structural-cleanliness.md +37 -0
- package/skills/loveui-skills/references/testing-and-quality-strategy.md +33 -0
- package/skills/loveui-skills/references/visual-primitives.md +42 -0
- package/skills/loveui-skills/skills/adapt/SKILL.md +199 -0
- package/skills/loveui-skills/skills/animate/SKILL.md +190 -0
- package/skills/loveui-skills/skills/audit/SKILL.md +127 -0
- package/skills/loveui-skills/skills/bolder/SKILL.md +132 -0
- package/skills/loveui-skills/skills/clarify/SKILL.md +180 -0
- package/skills/loveui-skills/skills/colorize/SKILL.md +158 -0
- package/skills/loveui-skills/skills/critique/SKILL.md +118 -0
- package/skills/loveui-skills/skills/delight/SKILL.md +317 -0
- package/skills/loveui-skills/skills/distill/SKILL.md +137 -0
- package/skills/loveui-skills/skills/extract/SKILL.md +95 -0
- package/skills/loveui-skills/skills/frontend-design/SKILL.md +127 -0
- package/skills/loveui-skills/skills/frontend-design/reference/color-and-contrast.md +132 -0
- package/skills/loveui-skills/skills/frontend-design/reference/interaction-design.md +123 -0
- package/skills/loveui-skills/skills/frontend-design/reference/motion-design.md +99 -0
- package/skills/loveui-skills/skills/frontend-design/reference/responsive-design.md +114 -0
- package/skills/loveui-skills/skills/frontend-design/reference/spatial-design.md +100 -0
- package/skills/loveui-skills/skills/frontend-design/reference/typography.md +131 -0
- package/skills/loveui-skills/skills/frontend-design/reference/ux-writing.md +107 -0
- package/skills/loveui-skills/skills/harden/SKILL.md +358 -0
- package/skills/loveui-skills/skills/normalize/SKILL.md +67 -0
- package/skills/loveui-skills/skills/onboard/SKILL.md +243 -0
- package/skills/loveui-skills/skills/optimize/SKILL.md +269 -0
- package/skills/loveui-skills/skills/polish/SKILL.md +202 -0
- package/skills/loveui-skills/skills/quieter/SKILL.md +118 -0
- package/skills/loveui-skills/skills/teach-loveui/SKILL.md +69 -0
package/README.md
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
# love-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Command line utility and component registry source for LoveUI.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
|
-
Install
|
|
7
|
+
Install a component with `npx`:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
npx love-ui@latest add alert
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Install LoveUI Skills for an AI coding tool:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx love-ui@latest add loveui-skills
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The CLI will ask which target to install. You can also pass a target directly: `codex`, `claude`, `cursor`, `github`, or `all`.
|
|
20
|
+
|
|
21
|
+
The package ships the CLI and the repository-level `registry/` tree used by the CLI.
|
|
14
22
|
|
|
15
23
|
## Development
|
|
16
24
|
|
|
17
25
|
```bash
|
|
18
26
|
bun install
|
|
19
|
-
bun run
|
|
27
|
+
bun run build
|
|
20
28
|
```
|
|
21
29
|
|
|
22
|
-
The
|
|
30
|
+
The build script bundles the CLI into `dist/` and copies the repository-level `registry/` directory into this package before npm creates the release tarball.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{spawnSync as ct}from"child_process";import{existsSync as d}from"fs";import{cp as ut,mkdir as F,readdir as dt,readFile as m,writeFile as T}from"fs/promises";import et from"os";import o from"path";import{createInterface as gt}from"readline/promises";import{pathToFileURL as ft,fileURLToPath as pt}from"url";var ht=o.dirname(pt(import.meta.url)),J=o.resolve(ht,".."),G=o.join(J,"packages"),M=o.join(J,"registry"),mt=o.join(J,"skills"),yt=new Set([".ts",".tsx",".cts",".mts",".js",".jsx",".css",".scss",".sass",".mdx",".md"]),nt=new Set(["node_modules","dist",".turbo",".next","build",".cache"]),st=new Set(["accordion","alert","alert-dialog","autocomplete","avatar","badge","breadcrumb","button","card","checkbox","checkbox-group","collapsible","combobox","command","dialog","empty","field","fieldset","form","frame","group","input","label","menu","meter","number-field","pagination","popover","preview-card","progress","radio-group","scroll-area","select","separator","sheet","skeleton","slider","switch","table","tabs","textarea","toast","toggle","toggle-group","toolbar","tooltip"]),bt=[".ts",".tsx",".js",".jsx"],rt=/(^|\/)lib\/utils(?:\.[a-z]+)?$/i,kt=/@loveui\/ui\/lib\/utils|@loveui\/shadcn-ui\/lib\/utils|@love-ui\/shadcn-ui\/lib\/utils|@\/lib\/utils|~\/lib\/utils|(?:\.\.\/)+ui\/src\/lib\/utils/,wt=`import { clsx, type ClassValue } from "clsx"
|
|
3
|
+
import { twMerge } from "tailwind-merge"
|
|
4
|
+
|
|
5
|
+
export function cn(...inputs: ClassValue[]) {
|
|
6
|
+
return twMerge(clsx(inputs))
|
|
7
|
+
}
|
|
8
|
+
`,vt="love-ui globals",$t=`/* love-ui globals */
|
|
9
|
+
@custom-variant dark (&:is(.dark *));
|
|
10
|
+
|
|
11
|
+
@theme inline {
|
|
12
|
+
--color-background: var(--background);
|
|
13
|
+
--color-foreground: var(--foreground);
|
|
14
|
+
--color-card: var(--card);
|
|
15
|
+
--color-card-foreground: var(--card-foreground);
|
|
16
|
+
--color-popover: var(--popover);
|
|
17
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
18
|
+
--color-primary: var(--primary);
|
|
19
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
20
|
+
--color-secondary: var(--secondary);
|
|
21
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
22
|
+
--color-muted: var(--muted);
|
|
23
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
24
|
+
--color-accent: var(--accent);
|
|
25
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
26
|
+
--color-destructive: var(--destructive);
|
|
27
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
28
|
+
--color-info: var(--info);
|
|
29
|
+
--color-info-foreground: var(--info-foreground);
|
|
30
|
+
--color-success: var(--success);
|
|
31
|
+
--color-success-foreground: var(--success-foreground);
|
|
32
|
+
--color-warning: var(--warning);
|
|
33
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
34
|
+
--color-border: var(--border);
|
|
35
|
+
--color-input: var(--input);
|
|
36
|
+
--color-ring: var(--ring);
|
|
37
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
38
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
39
|
+
--radius-lg: var(--radius);
|
|
40
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:root {
|
|
44
|
+
--radius: 0.625rem;
|
|
45
|
+
--background: oklch(1 0 0);
|
|
46
|
+
--foreground: oklch(0.21 0.006 285.885);
|
|
47
|
+
--card: oklch(1 0 0);
|
|
48
|
+
--card-foreground: oklch(0.21 0.006 285.885);
|
|
49
|
+
--popover: oklch(1 0 0);
|
|
50
|
+
--popover-foreground: oklch(0.21 0.006 285.885);
|
|
51
|
+
--primary: oklch(0.274 0.006 286.033);
|
|
52
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
53
|
+
--secondary: oklch(0 0 0 / 4%);
|
|
54
|
+
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
55
|
+
--muted: oklch(0 0 0 / 4%);
|
|
56
|
+
--muted-foreground: oklch(0.442 0.017 285.786);
|
|
57
|
+
--accent: oklch(0 0 0 / 4%);
|
|
58
|
+
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
59
|
+
--destructive: oklch(0.637 0.237 25.331);
|
|
60
|
+
--destructive-foreground: oklch(0.505 0.213 27.518);
|
|
61
|
+
--info: oklch(0.623 0.214 259.815);
|
|
62
|
+
--info-foreground: oklch(0.488 0.243 264.376);
|
|
63
|
+
--success: oklch(0.696 0.17 162.48);
|
|
64
|
+
--success-foreground: oklch(0.508 0.118 165.612);
|
|
65
|
+
--warning: oklch(0.769 0.188 70.08);
|
|
66
|
+
--warning-foreground: oklch(0.555 0.163 48.998);
|
|
67
|
+
--border: oklch(0 0 0 / 10%);
|
|
68
|
+
--input: oklch(0 0 0 / 10%);
|
|
69
|
+
--ring: oklch(0.705 0.015 286.067);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.dark {
|
|
73
|
+
--background: oklch(0.141 0.005 285.823);
|
|
74
|
+
--foreground: oklch(0.967 0.001 286.375);
|
|
75
|
+
--card: color-mix(in srgb, oklch(0.21 0.006 285.885) 80%, oklch(0.141 0.005 285.823));
|
|
76
|
+
--card-foreground: oklch(0.967 0.001 286.375);
|
|
77
|
+
--popover: oklch(0.21 0.006 285.885);
|
|
78
|
+
--popover-foreground: oklch(0.967 0.001 286.375);
|
|
79
|
+
--primary: oklch(0.967 0.001 286.375);
|
|
80
|
+
--primary-foreground: oklch(0.21 0.006 285.885);
|
|
81
|
+
--secondary: oklch(1 0 0 / 6%);
|
|
82
|
+
--secondary-foreground: oklch(0.967 0.001 286.375);
|
|
83
|
+
--muted: oklch(1 0 0 / 6%);
|
|
84
|
+
--muted-foreground: oklch(0.705 0.015 286.067);
|
|
85
|
+
--accent: oklch(1 0 0 / 6%);
|
|
86
|
+
--accent-foreground: oklch(0.967 0.001 286.375);
|
|
87
|
+
--destructive: oklch(0.637 0.237 25.331);
|
|
88
|
+
--destructive-foreground: oklch(0.704 0.191 22.216);
|
|
89
|
+
--info: oklch(0.623 0.214 259.815);
|
|
90
|
+
--info-foreground: oklch(0.707 0.165 254.624);
|
|
91
|
+
--success: oklch(0.696 0.17 162.48);
|
|
92
|
+
--success-foreground: oklch(0.765 0.177 163.223);
|
|
93
|
+
--warning: oklch(0.769 0.188 70.08);
|
|
94
|
+
--warning-foreground: oklch(0.828 0.189 84.429);
|
|
95
|
+
--border: oklch(1 0 0 / 12%);
|
|
96
|
+
--input: oklch(1 0 0 / 12%);
|
|
97
|
+
--ring: oklch(0.552 0.016 285.938);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@layer base {
|
|
101
|
+
* {
|
|
102
|
+
@apply border-border outline-ring/50;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
`;function L(t){if(!t)return t;let n=t.split("/");return n[n.length-1]||t}function ot(t){let n=t.trim();return n&&((n.startsWith("@/")||n.startsWith("~/"))&&(n=`src/${n.slice(2)}`),n.startsWith("/")&&(n=n.slice(1)),n=n.replace(/^\.\//,""),n=n.replace(/\/+$/,""),n)}function xt(t){return t.trim().replace(/\/+$/,"")}function S(t){return t.replace(/\.(?:ts|tsx|js|jsx)$/i,"")}function Y(t){let n=S(t);return bt.map(s=>`${n}${s}`)}function jt(t){let n=t.replace(/\/+$/,"");return n==="src"||n.startsWith("src/")?"src":n==="app"||n.startsWith("app/")?"app":null}function it(t){let n=L(t);return n==="ui"?"love-ui":n}function Pt(t){let n=t.loveui??{},s=typeof n.target=="string"?n.target.trim():"",e=n.category;if(s){let i=typeof n.includePackageName=="boolean"?n.includePackageName:!1;return{base:s.replace(/\/+$/,""),includePackageName:i}}return e==="feature"?{base:"components",includePackageName:!0}:e==="block"?{base:"components/blocks",includePackageName:!0}:{base:"components/ui",includePackageName:!0}}function St(t,n,s){let e=t.startsWith("src/")?t.slice(4):t;if(!n.includePackageName){let u=n.base.split("/").filter(Boolean),c=u[u.length-1];c&&e.startsWith(`${c}/`)&&(e=e.slice(c.length+1))}let l=`${(n.includePackageName?`${n.base}/${s}`:n.base).replace(/\/+/g,"/")}/${e}`.replace(/\/+/g,"/");return{cleanedPath:e,target:l}}async function Tt(t){let n=o.join(t,"components.json");try{let s=await m(n,"utf8");return JSON.parse(s).aliases??null}catch{return null}}async function Rt(t){let n=["tsconfig.json","jsconfig.json"].map(s=>o.join(t,s)).find(s=>d(s));if(!n)return null;try{let s=await m(n,"utf8"),i=JSON.parse(s).compilerOptions?.paths;return!i||typeof i!="object"?null:i}catch{return null}}function Ft(t,n){if(typeof t=="string"){if(t.trim().startsWith("~/"))return"~/";if(t.trim().startsWith("@/"))return"@/"}if(n){if(Object.prototype.hasOwnProperty.call(n,"~/*"))return"~/";if(Object.prototype.hasOwnProperty.call(n,"@/*"))return"@/"}return"@/"}async function Ut(t,n,s){if(n&&n.length>0)return n;let e=["src/components/ui","app/components/ui","components/ui"];for(let r of e)if(d(o.join(t,r)))return r.replace(/\/ui$/,"");let i=["src/components","app/components","components"];for(let r of i)if(d(o.join(t,r)))return r;if(s){let r=s["@/*"]??s["~/*"]??[];if(Array.isArray(r)&&r.some(l=>/^\.?\/?src\//.test(l)))return"src/components";if(Array.isArray(r)&&r.some(l=>/^\.?\/?app\//.test(l)))return"app/components"}return d(o.join(t,"src"))?"src/components":d(o.join(t,"app"))?"app/components":"components"}async function Lt(t,n,s,e){let i=e?.utils??(e?.lib?`${e.lib.replace(/\/+$/,"")}/utils`:void 0);if(i&&i.trim().length>0){let c=S(xt(i)),f=S(ot(i));for(let w of Y(f))if(d(o.join(t,w)))return{utilsImportPath:c,utilsFilePath:w};return{utilsImportPath:c,utilsFilePath:`${f}.ts`}}let r=jt(n),l=r?`${r}/lib/utils`:"lib/utils",u=Array.from(new Set([l,"src/lib/utils","app/lib/utils","lib/utils"]));for(let c of u)for(let f of Y(c))if(d(o.join(t,f)))return{utilsImportPath:`${s}lib/utils`,utilsFilePath:f};return{utilsImportPath:`${s}lib/utils`,utilsFilePath:`${l}.ts`}}function q(t,n,s){let e=l=>{let u=l.startsWith("/"),c=l.endsWith("/"),f=l.split("/").filter(Boolean),w=[];for(let x of f)w[w.length-1]!==x&&w.push(x);let $=w.join("/");return`${u?"/":""}${$}${c?"/":""}`},i=n.replace(/\/+$/,""),r=t.replace(/^\.?\//,"");if(rt.test(r))return e(s);if(r.startsWith("components/")){let l=r.slice(10);return e(`${i}${l}`.replace(/^\//,""))}if(r.startsWith("lib/")){if(i.startsWith("src/"))return e(`src/${r}`);if(i.startsWith("app/"))return e(`app/${r}`)}if(r.startsWith("hooks/")){if(i.startsWith("src/"))return e(`src/${r}`);if(i.startsWith("app/"))return e(`app/${r}`)}return r.startsWith("ui/")?e(`${i}/${r}`):e(r)}function U(t,n){let s=n.startsWith("~/")?"~/":"@/",e=t;return e=e.replace(/@\/registry\/default\/components\//g,`${s}components/`),e=e.replace(/@\/registry\/default\/ui\//g,`${s}components/ui/`),e=e.replace(/@\/registry\/default\/hooks\//g,`${s}hooks/`),e=e.replace(/@\/registry\/default\/lib\//g,`${s}lib/`),e=e.replace(/@loveui\/ui\/ui\//g,`${s}components/ui/`),e=e.replace(/@loveui\/ui\/lib\//g,`${s}lib/`),e=e.replace(/@\/ui\//g,`${s}components/ui/`),e=e.replace(/@\/registry\/building-blocks\/default\/components\//g,`${s}components/`),e=e.replace(/@\/registry\/building-blocks\/default\/ui\//g,`${s}components/ui/`),e=e.replace(/@\/registry\/building-blocks\/default\/lib\//g,`${s}lib/`),e=e.replace(/@\/registry\/building-blocks\/default\/hooks\//g,`${s}hooks/`),e=e.replace(/@\/registry\/default\/components\//g,`${s}components/`),e=e.replace(/@\/registry\/default\/ui\//g,`${s}components/ui/`),e=e.replace(/@\/registry\/default\/lib\//g,`${s}lib/`),e=e.replace(/@\/registry\/default\/hooks\//g,`${s}hooks/`),e=e.replace(/from\s+["']@loveui\/ui\/lib\/utils["']/g,`from "${n}"`),e=e.replace(/from\s+["']@loveui\/shadcn-ui\/lib\/utils["']/g,`from "${n}"`),e=e.replace(/from\s+["']@love-ui\/shadcn-ui\/lib\/utils["']/g,`from "${n}"`),e=e.replace(/from\s+["']@\/lib\/utils["']/g,`from "${n}"`),e=e.replace(/from\s+["']~\/lib\/utils["']/g,`from "${n}"`),e=e.replace(/from\s+["'](?:\.\.\/)+ui\/src\/lib\/utils["']/g,`from "${n}"`),e}async function Ct(t,n){if(d(o.join(t,n)))return!1;let s=wt,e=o.join(G,"love-ui","src","lib","utils.ts");if(d(e))try{s=await m(e,"utf8")}catch{}return await z(n,t),await T(o.join(t,n),s,"utf8"),!0}async function Et(t){let s=["app/globals.css","app/global.css","src/app/globals.css","src/app/global.css","styles/globals.css","src/styles/globals.css","globals.css","global.css"].find(c=>d(o.join(t,c)));s||(d(o.join(t,"src","app"))?s="src/app/globals.css":d(o.join(t,"app"))?s="app/globals.css":d(o.join(t,"src"))?s="src/styles/globals.css":s="globals.css");let e=o.join(t,s),i=d(e),r=i?await m(e,"utf8"):"",l=!1;/@import\s+["']tailwindcss["']/.test(r)||(r=`@import "tailwindcss";
|
|
106
|
+
${r?`
|
|
107
|
+
${r}`:""}`,l=!0),r.includes(vt)||(r=`${r.trimEnd()}
|
|
108
|
+
|
|
109
|
+
${$t}`,l=!0),(!i||l)&&(await z(s,t),await T(e,r,"utf8"));let u=await Dt(t,s);return{path:s,created:!i,updated:l,imported:u}}async function Dt(t,n){let e=["app/layout.tsx","app/layout.jsx","src/app/layout.tsx","src/app/layout.jsx"].find(c=>d(o.join(t,c)));if(!e)return!1;let i=o.join(t,e),r=await m(i,"utf8"),l=It(o.dirname(e),n);if(r.includes(`"${l}"`)||r.includes(`'${l}'`))return!1;let u=`import "${l}";
|
|
110
|
+
${r}`;return await T(i,u,"utf8"),!0}function It(t,n){let s=o.posix.relative(t||".",n);return s.startsWith(".")||(s=`./${s}`),s}async function z(t,n){let s=o.dirname(o.join(n,t));await F(s,{recursive:!0})}async function At(t,n){let s=o.join(t,"package.json"),e={};try{let c=await m(s,"utf8");e=JSON.parse(c)}catch{}let i=Pt(e),r=L(n),l=[];async function u(c,f){let w=await dt(c,{withFileTypes:!0});for(let $ of w){if(nt.has($.name))continue;let x=o.join(c,$.name);if($.isDirectory()){await u(x,f);continue}let C=o.extname($.name);if(!yt.has(C)||$.name==="package.json")continue;let R=o.relative(f,x).split(o.sep).join("/"),{target:j}=St(R,i,r),v=await m(x,"utf8");l.push({path:R,target:j,content:v})}}return await u(t,t),l}async function Q(t,n){let s=o.join(M,"default","ui",`${t}.tsx`);if(d(s))try{let r=U(await m(s,"utf8"),n),l=[{path:`default/ui/${t}.tsx`,target:`components/ui/${t}.tsx`,content:r}];if(t==="toast"){let u=["toast-gooey.tsx","toast-gooey-renderer.tsx","toast-gooey-icons.tsx","toast-gooey-types.ts","toast-gooey.css"];for(let c of u){let f=o.join(M,"default","ui",c);d(f)&&l.push({path:`default/ui/${c}`,target:`components/ui/${c}`,content:await m(f,"utf8")})}}return l}catch(r){console.warn(`Warning: unable to read ${t} from bundled registry`,r)}let e=o.join(G,"love-ui"),i=o.join(e,"src","ui",`${t}.tsx`);if(!d(i))return null;try{let r=[],l=await m(i,"utf8");l=U(l,n),r.push({path:`src/ui/${t}.tsx`,target:`components/ui/${t}.tsx`,content:l});let u=o.join(e,"src","lib","utils.ts");if(d(u)){let c=await m(u,"utf8");r.push({path:"src/lib/utils.ts",target:"lib/utils.ts",content:c})}return r}catch(r){return console.warn(`Warning: unable to read ${t} component`,r),null}}async function Ot(t,n){if(st.has(t))return await Q(t,n);let s=o.join(M,"default","examples",`${t}.tsx`);if(d(s))try{let r=await m(s,"utf8"),l=[],u=Array.from(new Set([...r.matchAll(/@\/registry\/default\/ui\/([^"']+)/g)].map(c=>c[1]).filter(Boolean)));for(let c of u){let f=await Q(c,n);f&&l.push(...f)}return l.push({path:`default/examples/${t}.tsx`,target:`components/${t}.tsx`,content:U(r,n)}),l}catch(r){return console.warn(`Warning: unable to read ${t} from bundled registry examples`,r),null}let e=it(t),i=o.join(G,e);if(!d(i))return null;try{return await At(i,t)}catch(r){return console.warn(`Warning: unable to read bundled sources for ${t}`,r),null}}async function lt(t){let n=o.join(mt,L(t));return!d(n)||!d(o.join(n,"SKILL.md"))?null:n}var B=["codex","claude","cursor","github"],Z=new Set(B);function _t(){let t=process.env.CODEX_HOME?.trim();return t||o.join(et.homedir(),".codex")}function Wt(){let t=process.env.CLAUDE_HOME?.trim();return t||o.join(et.homedir(),".claude")}async function _(t,n){let s=await lt(t);if(!s)throw new Error(`Bundled skill "${t}" was not found in this love-ui package.`);return await F(o.dirname(n),{recursive:!0}),d(n)?"exists":(await ut(s,n,{recursive:!0,force:!1,filter:e=>{let i=o.basename(e);return!nt.has(i)}}),"installed")}async function tt(t,n){return await F(o.dirname(t),{recursive:!0}),d(t)?"exists":(await T(t,n,"utf8"),"installed")}function Bt(t){return`---
|
|
111
|
+
description: Use LoveUI Skills when building, reviewing, or polishing LoveUI interfaces.
|
|
112
|
+
globs: "**/*.{ts,tsx,js,jsx,css,md,mdx}"
|
|
113
|
+
alwaysApply: false
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
Use the LoveUI skill pack in \`.cursor/loveui-skills\` for LoveUI UI work.
|
|
117
|
+
|
|
118
|
+
Start with \`.cursor/loveui-skills/SKILL.md\`, then read the matching files in \`.cursor/loveui-skills/references\` and \`.cursor/loveui-skills/skills\`.
|
|
119
|
+
|
|
120
|
+
For component installs, use \`npx love-ui add <component>\`. Do not install internal \`@loveui/*\`, \`@love-ui/*\`, or \`@repo/*\` packages directly.
|
|
121
|
+
|
|
122
|
+
Installed skill pack: ${t}
|
|
123
|
+
`}function Mt(t){return`---
|
|
124
|
+
applyTo: "**/*.{ts,tsx,js,jsx,css,md,mdx}"
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
# LoveUI Skills
|
|
128
|
+
|
|
129
|
+
Use the LoveUI skill pack in \`.github/loveui-skills\` when building, reviewing, or polishing LoveUI interfaces.
|
|
130
|
+
|
|
131
|
+
Start with \`.github/loveui-skills/SKILL.md\`, then read the matching files in \`.github/loveui-skills/references\` and \`.github/loveui-skills/skills\`.
|
|
132
|
+
|
|
133
|
+
For component installs, use \`npx love-ui add <component>\`. Do not install internal \`@loveui/*\`, \`@love-ui/*\`, or \`@repo/*\` packages directly.
|
|
134
|
+
|
|
135
|
+
Installed skill pack: ${t}
|
|
136
|
+
`}async function zt(t,n,s){let e=L(t);if(n==="codex"){let l=o.join(_t(),"skills",e);return[{label:"Codex skill",path:l,status:await _(t,l)}]}if(n==="claude"){let l=o.join(Wt(),"skills",e);return[{label:"Claude skill",path:l,status:await _(t,l)}]}if(n==="cursor"){let l=o.join(s,".cursor","loveui-skills"),u=o.join(s,".cursor","rules","loveui-skills.mdc");return[{label:"Cursor skill files",path:l,status:await _(t,l)},{label:"Cursor rule",path:u,status:await tt(u,Bt(t))}]}let i=o.join(s,".github","loveui-skills"),r=o.join(s,".github","instructions","loveui-skills.instructions.md");return[{label:"GitHub skill files",path:i,status:await _(t,i)},{label:"GitHub Copilot instructions",path:r,status:await tt(r,Mt(t))}]}function Gt(t){let n=new Set;for(let s=0;s<t.length;s++){let e=t[s];if(e){if(e==="--target"||e==="--agent"||e==="-t"){let i=t[s+1];if(s++,!i)throw new Error(`Missing value for ${e}. Use one of: codex, claude, cursor, github, all.`);W(i,n);continue}if(e.startsWith("--target=")){W(e.slice(9),n);continue}if(e.startsWith("--agent=")){W(e.slice(8),n);continue}W(e,n)}}return[...n]}function W(t,n){let s=t.trim().toLowerCase();if(s==="all"){for(let e of Z)n.add(e);return}if(!Z.has(s))throw new Error(`Unknown skill target "${t}". Use one of: codex, claude, cursor, github, all.`);n.add(s)}async function Ht(){if(!process.stdin.isTTY||!process.stdout.isTTY)throw new Error("Missing skill target. Use one of: codex, claude, cursor, github, all.");let t=[...B.map((s,e)=>({label:s,number:String(e+1),targets:[s]})),{label:"all",number:String(B.length+1),targets:[...B]}];console.log(`
|
|
137
|
+
Which AI tool should LoveUI Skills target?
|
|
138
|
+
`);for(let s of t)console.log(` ${s.number}. ${s.label}`);let n=gt({input:process.stdin,output:process.stdout});try{for(;;){let s=(await n.question(`
|
|
139
|
+
Select a target: `)).trim().toLowerCase(),e=t.find(i=>i.number===s||i.label===s);if(e)return e.targets;console.log("Please choose codex, claude, cursor, github, all, or a number from the list.")}}finally{n.close()}}async function Kt(t,n){let s="loveui-skills",e=Gt(t),i=e.length>0?e:await Ht();if(!await lt(s))throw new Error("The loveui-skills pack is missing from this love-ui package. Try updating to the latest version.");console.log(`
|
|
140
|
+
Adding ${s} for ${i.join(", ")}...`);for(let r of i){let l=await zt(s,r,n);for(let u of l){let c=u.status==="installed"?"Installed":"Already exists";console.log(`\u2713 ${c}: ${u.label} at ${u.path}`)}}console.log(`
|
|
141
|
+
\u2713 Done! Restart or reload your AI tool so it can pick up the new instructions.`)}var Jt={"@base-ui-components/react":"1.0.0-beta.4","class-variance-authority":"^0.7.1",clsx:"^2.1.1","lucide-react":"^1.16.0","tailwind-merge":"^3.3.1"};async function Vt(t){if(st.has(t)||d(o.join(M,"default","examples",`${t}.tsx`)))return{...Jt};let n=it(t),s=o.join(G,n,"package.json");try{let e=await m(s,"utf8");return JSON.parse(e).dependencies??{}}catch{return{}}}async function Nt(t){return d(o.join(t,"bun.lockb"))?"bun":d(o.join(t,"pnpm-lock.yaml"))?"pnpm":d(o.join(t,"yarn.lock"))?"yarn":"npm"}async function Xt(t,n,s){let e=Object.entries(t);if(e.length===0)return!0;console.log(`
|
|
142
|
+
Installing dependencies...`);let i=e.map(([u,c])=>`${u}@${c}`),r;switch(n){case"bun":r=`bun add ${i.join(" ")}`;break;case"pnpm":r=`pnpm add ${i.join(" ")}`;break;case"yarn":r=`yarn add ${i.join(" ")}`;break;default:r=`npm install ${i.join(" ")}`}let l=ct(r,{stdio:"inherit",shell:!0,cwd:s});return l.error||l.status!==0?(console.warn(`
|
|
143
|
+
Failed to install dependencies. You may need to install them manually:`),console.warn(` ${i.join(`
|
|
144
|
+
`)}`),!1):(console.log(`Dependencies installed successfully!
|
|
145
|
+
`),!0)}async function Yt(t=process.argv.slice(2)){if((t.length===0||t.length===1&&(t[0]==="--version"||t[0]==="-v"))&&(console.log("love-ui version 1.1.9"),process.exit(0)),(t.length<2||t[0]!=="add")&&(console.log("Usage: npx love-ui add [...packages]"),console.log(" npx love-ui add loveui-skills [codex|claude|cursor|github|all]"),console.log(" npx love-ui add loveui-skills --agent codex"),console.log(" npx love-ui --version"),process.exit(1)),L(t[1]??"")==="loveui-skills"){await Kt(t.slice(2),process.cwd());return}let n=t.slice(1),s=process.cwd(),e=await Tt(s),i=await Rt(s),r=e?.components?ot(e.components):null,l=await Ut(s,r,i),u=Ft(e?.components,i),{utilsImportPath:c,utilsFilePath:f}=await Lt(s,l,u,e),w=await Nt(s),$=l.endsWith("/ui")?l:`${l}/ui`,x=!1,C=!1,R=!1,j={};for(let v of n){if(!v.trim())continue;if(console.log(`
|
|
146
|
+
Adding ${v}...`),x||(await F(o.join(s,l),{recursive:!0}),await F(o.join(s,$),{recursive:!0}),x=!0),!R){let a=await Et(s);a.created?console.log(`\u2713 Created ${a.path}`):a.updated&&console.log(`\u2713 Updated ${a.path}`),a.imported&&console.log(`\u2713 Imported ${a.path} from app layout`),R=!0}C=!0;let p=null,V=null;if(v.startsWith("http://")||v.startsWith("https://")){let a=v;a.includes("/building-blocks/r/")&&(a=a.replace("/building-blocks/r/","/building-blocks/"),console.log(`Auto-corrected URL to: ${a}`));try{let g=await fetch(a);g.ok?p=await g.json():console.warn(`Failed to fetch ${a}: HTTP ${g.status}`)}catch(g){console.warn(`Failed to fetch from ${a}:`,g)}}else{let a=new URL(`r/${v}.json`,"https://www.loveui.dev/");try{let g=await fetch(a);g.ok&&(p=await g.json())}catch{}V=await Ot(v,c)}let P=V??p?.files??[];P=P.map(a=>{let g=a.target||a.path;return g.startsWith("registry/default/")&&(g=g.replace("registry/default/","")),{...a,target:g}});let E=P.find(a=>a.target.match(/^components\/comp-\d+\.tsx$/));if(E){let a=P.filter(g=>g.target.match(/^components\/[^/]+\//)&&g.target!==E.target);if(a.length>0&&a[0]){let g=a[0].target.match(/^components\/([^/]+)\//);if(g&&g[1]){let h=g[1];E.target=`components/${h}-demo.tsx`}}else if(p?.meta?.tags&&Array.isArray(p.meta.tags)&&p.meta.tags.length>0){let h=p.meta.tags.slice(0,2).filter(b=>b.length>0);if(h.length>0){let b=h.join("-").toLowerCase().replace(/\s+/g,"-");E.target=`components/${b}.tsx`}}}if(!P.length){console.warn(`Component "${v}" not found. Available components can be found at https://loveui.dev`);continue}P.some(a=>rt.test(a.target)||typeof a.content=="string"&&kt.test(a.content))&&await Ct(s,f);let D=0,I=0;for(let a of P){if(!a.content)continue;let g=q(a.target,l,f),h=o.join(s,g),b=d(h);if(S(g)===S(f)&&b)continue;let O=U(a.content,c);if(b)try{if(await m(h,"utf8")===O)continue}catch{}await z(g,s),await T(h,O,"utf8"),b?I++:D++}if(D>0&&console.log(`\u2713 Created ${D} file${D>1?"s":""}`),I>0&&console.log(`\u2713 Updated ${I} file${I>1?"s":""}`),p?.registryDependencies&&p.registryDependencies.length>0){console.log(`
|
|
147
|
+
Installing ${p.registryDependencies.length} required component${p.registryDependencies.length>1?"s":""}...`);for(let a of p.registryDependencies){let g=a;a.startsWith("https://loveui.dev/building-blocks/r/")&&(g=`https://ui.loveui.dev/ui/r/${a.split("/").pop()}`);try{let h=await fetch(g);if(h.ok){let b=await h.json(),O=(b?.files??[]).map(y=>{let k=y.target||y.path;return k.startsWith("registry/default/")&&(k=k.replace("registry/default/","")),{...y,target:k}});for(let y of O){if(!y.content)continue;let k=q(y.target,l,f),K=o.join(s,k),N=d(K);if(S(k)===S(f)&&N)continue;let X=U(y.content,c);if(N)try{if(await m(K,"utf8")===X)continue}catch{}await z(k,s),await T(K,X,"utf8")}let H=["@loveui/shadcn-ui","jotai","lucide-react","react","react-dom"];if(b?.dependencies)if(Array.isArray(b.dependencies))b.dependencies.forEach(y=>{H.includes(y)||(j[y]="latest")});else{let y=b.dependencies;Object.keys(y).forEach(k=>{!H.includes(k)&&y[k]&&(j[k]=y[k])})}}else console.warn(` \u2717 Failed to fetch ${g}: HTTP ${h.status}`)}catch(h){console.warn(` \u2717 Failed to install ${g}:`,h.message)}}console.log("\u2713 Installed registry dependencies")}let A={};p?.dependencies?Array.isArray(p.dependencies)?p.dependencies.forEach(a=>{A[a]="latest"}):A=p.dependencies:A=await Vt(v),Object.assign(j,A)}Object.keys(j).length>0&&await Xt(j,w,s),console.log(C?`
|
|
148
|
+
\u2713 Done! You can now import and use the components in your app.`:`
|
|
149
|
+
\u2713 Done! Skill installation complete.`)}var qt=process.argv[1]&&(import.meta.url===ft(process.argv[1]).href||process.argv[1].includes("love-ui")||process.argv[1].includes("loveui"));qt&&Yt().catch(t=>{console.error(t),process.exit(1)});export{Yt as run};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{constants as Te}from"fs";import{access as _e,readFile as Q}from"fs/promises";import p from"path";import{fileURLToPath as xe}from"url";import{Server as Ne}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Oe}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Ae,ErrorCode as d,ListResourceTemplatesRequestSchema as Ce,ListResourcesRequestSchema as Le,ListToolsRequestSchema as $e,McpError as l,ReadResourceRequestSchema as Fe}from"@modelcontextprotocol/sdk/types.js";var F={name:"love-ui",version:"1.2.17",private:!1,license:"MIT",type:"module",bin:{loveui:"dist/index.js","love-ui":"dist/index.js","loveui-mcp":"dist/mcp-server.js"},files:["dist","registry","skills"],main:"dist/index.js",exports:{".":{import:"./dist/index.js",require:"./dist/index.js"},"./registry/*":"./registry/*","./package.json":"./package.json"},dependencies:{"@modelcontextprotocol/sdk":"^1.18.1",postcss:"^8.5.6","postcss-nested":"^7.0.2"},scripts:{build:"tsup",postbuild:"node ./scripts/copy-registry.mjs",prepack:"npm run build","verify:registry":"node ./scripts/copy-registry.mjs",clean:"rimraf dist registry"},devDependencies:{"@types/node":"^20.14.10",rimraf:"^6.0.1",tsup:"^8.5.0"}};import{constants as me}from"fs";import{access as ue,readFile as U,readdir as W}from"fs/promises";import T,{extname as q,join as j,relative as ge}from"path";import{fileURLToPath as ye}from"url";import z from"postcss";import fe from"postcss-nested";var he=T.dirname(ye(import.meta.url)),ve=T.resolve(he,".."),M=T.join(ve,"packages"),we=new Set([".turbo",".next",".git","dist","build","storybook-static","node_modules","__tests__","__mocks__","coverage"]),Re=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".css",".scss",".sass",".mdx"]),Se=new Set(["package.json","tsconfig.json","tsconfig.build.json","tsconfig.test.json","README.md",".DS_Store"]),ke=new Set(["shadcn-ui","typescript-config","patterns","loveui","love-ui"]),Ee=e=>e.replace(/\\/g,"/"),G=async(e,n,t)=>{let s=await W(e,{withFileTypes:!0});for(let r of s){let o=j(e,r.name);if(r.isDirectory()){if(we.has(r.name))continue;await G(o,n,t);continue}let a=q(r.name);!Re.has(a)||Se.has(r.name)||r.name.endsWith(".d.ts")||r.name.endsWith(".test.ts")||r.name.endsWith(".test.tsx")||r.name.endsWith(".stories.tsx")||t.push({absolute:o,relative:Ee(ge(n,o))})}},Ie=(e,n)=>{let t=e.loveui??{},s=typeof t.target=="string"?t.target.trim():"",r=t.category;if(s.length>0){let o=typeof t.includePackageName=="boolean"?t.includePackageName:!1;return{base:s.replace(/\/+$/,""),includePackageName:o}}return r==="feature"?{base:"components",includePackageName:!0}:r==="block"?{base:"components/blocks",includePackageName:!0}:{base:"components/ui",includePackageName:!0}},De=e=>{let t=(e.loveui??{}).type;return typeof t=="string"&&t.trim().length>0?t:"registry:ui"},Pe=async e=>{try{return await ue(e,me.F_OK),!0}catch{return!1}},b=e=>e.startsWith("@loveui/")||e.startsWith("@love-ui/")||e.startsWith("@repo/"),be=e=>e.replace(/^@repo\//,"").replace(/^@loveui\//,"").replace(/^@love-ui\//,""),je=new Set(["@loveui/shadcn-ui","@love-ui/shadcn-ui"]),H=async()=>(await W(M,{withFileTypes:!0})).filter(n=>n.isDirectory()).map(n=>n.name).filter(n=>!ke.has(n)).sort((n,t)=>n.localeCompare(t)),J=async e=>{let n=j(M,e),t=j(n,"package.json");if(!await Pe(t))throw new Error(`Missing package.json for ${e}`);let s=JSON.parse(await U(t,"utf8")),r=De(s),o=Object.keys(s.dependencies??{}),a=Object.keys(s.peerDependencies??{}),N=Object.keys(s.devDependencies??{}),oe=new Set([...o,...a,...N].filter(b).filter(i=>!je.has(i))),O=[...new Set([...o,...a].filter(i=>!b(i)))],A=[...new Set(N.filter(i=>!b(i)&&!["@loveui/typescript-config","@types/react","@types/react-dom","typescript"].includes(i)))],k=[];for(let i of oe){let h=be(i);k.push(`https://www.loveui.dev/r/${h}.json`)}let C=[];await G(n,n,C);let f=[],m={},g=Ie(s,e);for(let i of C){let h=await U(i.absolute,"utf8"),E=q(i.absolute);if(E===".css"||E===".scss"||E===".sass"){let v=await z([fe]).process(h,{from:void 0});z.parse(v.css).walkAtRules("layer",I=>{let D=`@layer ${I.params}`;m[D]??={},I.walkRules(c=>{if(c.parent&&c.parent.type==="atrule"&&c.parent.name==="media")return;let R=c.selector,u={};c.walkDecls(S=>{u[S.prop]=S.value}),Object.keys(u).length>0&&(m[D][R]=u)}),I.walkAtRules("media",c=>{let R=`@media ${c.params}`,u=m[D];u[R]??={};let S=u[R];c.walkRules(L=>{let pe=L.selector,P={};L.walkDecls($=>{P[$.prop]=$.value}),Object.keys(P).length>0&&(S[pe]=P)})})});continue}let y=i.relative.startsWith("src/")?i.relative.slice(4):i.relative;if(!g.includePackageName){let v=g.base.split("/").filter(Boolean),w=v[v.length-1];w&&y.startsWith(`${w}/`)&&(y=y.slice(w.length+1))}let ce=e.includes("/")?e.split("/").pop()??e:e,le=(g.includePackageName?`${g.base}/${ce}`:g.base).replace(/\/+$/,"");f.push({type:r,path:y,target:`${le}/${y}`.replace(/\/+/g,"/"),content:h})}let ae=!f.length&&Object.keys(m).length>0?"registry:style":r;return{$schema:"https://ui.shadcn.com/schema/registry-item.json",name:e,type:ae,title:s.title??e,description:s.description,author:s.author??"Connor Love <hello@loveconnor.com>",dependencies:O.length?O:void 0,devDependencies:A.length?A:void 0,registryDependencies:k.length?Array.from(new Set(k)):void 0,files:f.length?f:void 0,css:Object.keys(m).length?m:void 0}};var x="loveui://registry/",Ue="loveui://registry/{package}",K="get-loveui-package",Z=new Set(["shadcn-ui","typescript-config","eslint-config","patterns","loveui","love-ui"]),ze=["@loveui/","@love-ui/","@repo/"],ee=new Set(["@loveui/shadcn-ui","@love-ui/shadcn-ui"]),We=e=>`${x}${e}`,qe=p.dirname(xe(import.meta.url)),X=p.resolve(qe,".."),Me=[p.join(X,"public","r"),p.resolve(X,"..","..","apps","ui","public","r"),p.resolve(process.cwd(),"apps","ui","public","r")],te=async e=>{try{return await _e(e,Te.R_OK),!0}catch{return!1}},ne=e=>ze.some(n=>e.startsWith(n)),Ge=e=>e.replace(/^@repo\//,"").replace(/^@loveui\//,"").replace(/^@love-ui\//,""),se=e=>Array.isArray(e)?e.filter(n=>typeof n=="string"):e&&typeof e=="object"?Object.keys(e):[],B=e=>{let n=Array.from(new Set(se(e).filter(t=>!ne(t)&&!ee.has(t))));return n.length>0?n:void 0},He=e=>{let n=Array.from(new Set(se(e).map(t=>t.trim()).filter(Boolean).filter(t=>!ee.has(t)).map(t=>ne(t)?`https://www.loveui.dev/r/${Ge(t)}.json`:t)));return n.length>0?n:void 0},re=e=>e.trim().replace(/^@repo\//,"").replace(/^@loveui\//,"").replace(/^@love-ui\//,""),Je=e=>{let n=re(e);if(Z.has(n))throw new l(d.InvalidParams,`${n} is an internal package and should not be used directly. Use \`npx love-ui add <component>\` with a public component name.`);return n},Y=e=>{if(!e||typeof e!="object")return{mcpHints:{installPattern:"npx love-ui add <component>",neverInstall:["@loveui/*","@love-ui/*","@repo/*"]}};let n={...e},t=B(n.dependencies),s=B(n.devDependencies),r=He(n.registryDependencies),o=typeof n.name=="string"&&n.name.trim().length>0?n.name.trim():"<component>",a={...n,mcpHints:{installPattern:"npx love-ui add <component>",installCommand:`npx love-ui add ${o}`,neverInstall:["@loveui/*","@love-ui/*","@repo/*","@loveui/shadcn-ui"]}};return t?a.dependencies=t:delete a.dependencies,s?a.devDependencies=s:delete a.devDependencies,r?a.registryDependencies=r:delete a.registryDependencies,a},_=null,ie=async()=>(_||(_=(async()=>{for(let e of Me){let n=p.join(e,"registry.json");if(await te(n))try{let t=JSON.parse(await Q(n,"utf8")),s=Array.from(new Set((t.items??[]).map(r=>r.name?.trim()).filter(r=>!!r))).sort((r,o)=>r.localeCompare(o));if(s.length===0)continue;return{dir:e,names:s,nameSet:new Set(s)}}catch{continue}}return null})()),_),Ke=async()=>{let[e,n]=await Promise.all([ie(),H()]),t=new Set(n);for(let s of e?.names??[])t.add(s);return Array.from(t).map(s=>re(s)).filter(s=>!Z.has(s)).sort((s,r)=>s.localeCompare(r))},Xe=async e=>{let n=await ie();if(!n||!n.nameSet.has(e))return null;let t=p.join(n.dir,`${e}.json`);return await te(t)?JSON.parse(await Q(t,"utf8")):null},Be=e=>{if(!e.startsWith(x))throw new l(d.InvalidParams,`Unsupported resource URI: ${e}`);let n=decodeURIComponent(e.slice(x.length)).trim();if(!n)throw new l(d.InvalidParams,"Package name is required.");return n},V=async e=>{let n=Je(e);try{let t=await Xe(n);return Y(t||await J(n))}catch(t){throw t instanceof l?t:t instanceof Error&&t.message.startsWith(`Missing package.json for ${n}`)?new l(d.InvalidParams,`Registry item "${n}" was not found. Call resources/list and use an exact item name from the registry.`):new l(d.InvalidParams,t instanceof Error?t.message:String(t))}};async function Ye(){let e=new Ne({name:"loveui-mcp",version:F.version??"0.0.0"},{capabilities:{resources:{listChanged:!0},tools:{listChanged:!0}}});e.setRequestHandler(Le,async()=>({resources:(await Ke()).map(s=>({uri:We(s),name:s,description:`loveui registry definition for ${s}`,mimeType:"application/json"}))})),e.setRequestHandler(Ce,async()=>({resourceTemplates:[{name:"loveui-registry",uriTemplate:Ue,description:"loveui registry definitions by package name",mimeType:"application/json"}]})),e.setRequestHandler(Fe,async t=>{let s=Be(t.params.uri),r=await V(s);return{contents:[{uri:t.params.uri,mimeType:"application/json",text:JSON.stringify(r,null,2)}]}}),e.setRequestHandler($e,async()=>({tools:[{name:K,description:"Fetch a loveui registry definition by package name. Always install with `npx love-ui add <component>` and never install @loveui/* packages directly.",inputSchema:{type:"object",additionalProperties:!1,properties:{name:{type:"string",description:"Package name, e.g. badge"}},required:["name"]}}]})),e.setRequestHandler(Ae,async t=>{if(t.params.name!==K)throw new l(d.InvalidParams,`Tool ${t.params.name} not found`);let s=t.params.arguments?.name;if(typeof s!="string"||s.trim()==="")throw new l(d.InvalidParams,"Package name is required.");let r=await V(s.trim());return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}});let n=new Oe;await e.connect(n)}Ye().catch(e=>{console.error(e),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,19 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "love-ui",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"loveui": "dist/index.js",
|
|
9
|
+
"love-ui": "dist/index.js",
|
|
10
|
+
"loveui-mcp": "dist/mcp-server.js"
|
|
11
|
+
},
|
|
7
12
|
"files": [
|
|
8
|
-
"
|
|
13
|
+
"dist",
|
|
14
|
+
"registry",
|
|
15
|
+
"skills"
|
|
9
16
|
],
|
|
17
|
+
"main": "dist/index.js",
|
|
10
18
|
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.js"
|
|
22
|
+
},
|
|
11
23
|
"./registry/*": "./registry/*",
|
|
12
24
|
"./package.json": "./package.json"
|
|
13
25
|
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.18.1",
|
|
28
|
+
"postcss": "^8.5.6",
|
|
29
|
+
"postcss-nested": "^7.0.2"
|
|
30
|
+
},
|
|
14
31
|
"scripts": {
|
|
15
|
-
"
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"postbuild": "node ./scripts/copy-registry.mjs",
|
|
34
|
+
"prepack": "npm run build",
|
|
16
35
|
"verify:registry": "node ./scripts/copy-registry.mjs",
|
|
17
|
-
"clean": "rimraf registry"
|
|
36
|
+
"clean": "rimraf dist registry"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^20.14.10",
|
|
40
|
+
"rimraf": "^6.0.1",
|
|
41
|
+
"tsup": "^8.5.0"
|
|
18
42
|
}
|
|
19
43
|
}
|
|
@@ -6,7 +6,14 @@ export type CodeSample = {
|
|
|
6
6
|
language?: string
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export function CodeBlockShowcase({
|
|
9
|
+
export function CodeBlockShowcase({
|
|
10
|
+
files,
|
|
11
|
+
}: {
|
|
12
|
+
files: CodeSample[]
|
|
13
|
+
lineNumbers?: boolean
|
|
14
|
+
highlighter?: "plain" | "shiki" | "sugar-high"
|
|
15
|
+
hideHeader?: boolean
|
|
16
|
+
}) {
|
|
10
17
|
return (
|
|
11
18
|
<div className="w-full max-w-2xl rounded-lg border bg-background">
|
|
12
19
|
{files.map((file) => (
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type FormProps = React.ComponentProps<"form"> & {
|
|
6
|
+
errors?: Record<string, string | string[]>
|
|
7
|
+
onClearErrors?: (errors: Record<string, string | string[]>) => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Form({ errors, onClearErrors, ...props }: FormProps) {
|
|
6
11
|
return <form {...props} />
|
|
7
12
|
}
|
|
8
13
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ReactNode, SVGProps } from "react";
|
|
2
|
+
|
|
3
|
+
const Icon = ({
|
|
4
|
+
title,
|
|
5
|
+
children,
|
|
6
|
+
...props
|
|
7
|
+
}: SVGProps<SVGSVGElement> & { title: string; children: ReactNode }) => (
|
|
8
|
+
<svg
|
|
9
|
+
{...props}
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
width="16"
|
|
12
|
+
height="16"
|
|
13
|
+
viewBox="0 0 24 24"
|
|
14
|
+
fill="none"
|
|
15
|
+
stroke="currentColor"
|
|
16
|
+
strokeWidth="2"
|
|
17
|
+
strokeLinecap="round"
|
|
18
|
+
strokeLinejoin="round"
|
|
19
|
+
>
|
|
20
|
+
<title>{title}</title>
|
|
21
|
+
{children}
|
|
22
|
+
</svg>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export const ArrowRight = () => (
|
|
26
|
+
<Icon title="Arrow Right">
|
|
27
|
+
<path d="M5 12h14" />
|
|
28
|
+
<path d="m12 5 7 7-7 7" />
|
|
29
|
+
</Icon>
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const LifeBuoy = () => (
|
|
33
|
+
<Icon title="Life Buoy">
|
|
34
|
+
<circle cx="12" cy="12" r="10" />
|
|
35
|
+
<path d="m4.93 4.93 4.24 4.24" />
|
|
36
|
+
<path d="m14.83 9.17 4.24-4.24" />
|
|
37
|
+
<path d="m14.83 14.83 4.24 4.24" />
|
|
38
|
+
<path d="m9.17 14.83-4.24 4.24" />
|
|
39
|
+
<circle cx="12" cy="12" r="4" />
|
|
40
|
+
</Icon>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export const LoaderCircle = (props: SVGProps<SVGSVGElement>) => (
|
|
44
|
+
<Icon title="Loader Circle" {...props}>
|
|
45
|
+
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
46
|
+
</Icon>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export const X = () => (
|
|
50
|
+
<Icon title="X">
|
|
51
|
+
<path d="M18 6 6 18" />
|
|
52
|
+
<path d="m6 6 12 12" />
|
|
53
|
+
</Icon>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export const CircleAlert = () => (
|
|
57
|
+
<Icon title="Circle Alert">
|
|
58
|
+
<circle cx="12" cy="12" r="10" />
|
|
59
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
60
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
61
|
+
</Icon>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export const Check = () => (
|
|
65
|
+
<Icon title="Check">
|
|
66
|
+
<path d="M20 6 9 17l-5-5" />
|
|
67
|
+
</Icon>
|
|
68
|
+
);
|