Sign In

smoothui-cli

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

smoothui-cli - npm Package Compare versions

Comparing version
1.1.0
to
1.1.1
+3
-1
dist/index.js
#!/usr/bin/env node
import{confirm as Le,isCancel as ae,select as Ne,spinner as De}from"@clack/prompts";var _="https://smoothui.dev",O={"Basic UI":["accordion","animated-input","animated-progress-bar","animated-tabs","animated-toggle","basic-dropdown","basic-modal","basic-toast","notification-badge","searchable-dropdown","skeleton-loader","tweet-card"],Buttons:["button-copy","clip-corners-button","dot-morph-button","magnetic-button"],"Text Effects":["wave-text","reveal-text","typewriter-text","scramble-hover","scroll-reveal-paragraph"],AI:["ai-branch","ai-input"],"Cards & Layouts":["expandable-cards","glow-hover-card","scrollable-card-stack","switchboard-card","phototab","job-listing-component"],"Loaders & Effects":["grid-loader","siri-orb","cursor-follow","github-stars-animation"],Interactive:["animated-o-t-p-input","animated-tags","app-download-stack","apple-invites","contribution-graph","dynamic-island","figma-comment","image-metadata-preview","infinite-slider","interactive-image-selector","number-flow","power-off-slide","price-flow","rich-popover","reviews-carousel","social-selector","user-account-avatar"]},Y=["src/components/ui","components/ui","src/components","components","app/components/ui"],H=[{file:"bun.lockb",cmd:"bun"},{file:"pnpm-lock.yaml",cmd:"pnpm"},{file:"yarn.lock",cmd:"yarn"},{file:"package-lock.json",cmd:"npm"}],J={active:"\u25C6",done:"\u25C7",selected:"\u25CF",unselected:"\u25CB",cursor:"\u276F",success:"\u2713",error:"\u2717",bar:"\u2502"};import{createInterface as ge,emitKeypressEvents as fe}from"readline";import a from"picocolors";var h={active:"\u25C6",done:"\u25C7",selected:"\u25CF",unselected:"\u25CB",pointer:"\u276F",bar:"\u2502"},Q=(e,t)=>{if(!t)return e;let o=t.toLowerCase();return e.filter(s=>s.label.toLowerCase().includes(o)||s.value.toLowerCase().includes(o)||s.category?.toLowerCase().includes(o))},ue=(e,t=3)=>{let o=[...e];return o.length===0?"":o.length<=t?o.join(", "):`${o.slice(0,t).join(", ")} +${o.length-t} more`},he=(e,t,o,s)=>{let r=Q(t,o.searchQuery),n=r.length;process.stdout.write("\x1B[2J\x1B[H"),console.log(`${a.green(h.active)} ${e} ${a.dim("(space to toggle)")}`),console.log(`${a.dim(h.bar)}`);let i=o.searchQuery||a.dim("Type to search...");console.log(`${a.dim(h.bar)} ${a.cyan("Search:")} ${i}${a.inverse(" ")}`),console.log(`${a.dim(h.bar)}`);let l=Math.floor(s/2),p=Math.max(0,o.cursorIndex-l),c=Math.min(n,p+s);c-p<s&&p>0&&(p=Math.max(0,c-s)),p>0&&console.log(`${a.dim(h.bar)} ${a.dim(`\u2191 ${p} more`)}`);for(let m=p;m<c;m++){let g=r[m],f=o.selected.has(g.value),b=m===o.cursorIndex,x=b?a.cyan(h.pointer):" ",u=f?a.green(h.selected):a.dim(h.unselected),v=b?a.cyan(g.label):g.label,N=g.category?a.dim(` (${g.category})`):"";console.log(`${a.dim(h.bar)} ${x} ${u} ${v}${N}`)}let d=n-c;d>0&&console.log(`${a.dim(h.bar)} ${a.dim(`\u2193 ${d} more`)}`),n===0&&console.log(`${a.dim(h.bar)} ${a.dim("No components found")}`),console.log(`${a.dim(h.bar)}`);let $=ue(o.selected);$&&(console.log(`${a.dim(h.bar)} ${a.green("Selected:")} ${$}`),console.log(`${a.dim(h.bar)}`)),console.log(`${a.dim(h.bar)} ${a.dim("\u2191\u2193 navigate \u2022 space select \u2022 enter confirm \u2022 esc cancel")}`)},K=(e,t)=>{t&&process.stdin.removeListener("keypress",t),process.stdin.isTTY&&process.stdin.setRawMode(!1),e.close(),process.stdout.write("\x1B[?25h")},W=e=>{let{message:t,items:o,maxVisible:s=8}=e;return new Promise(r=>{let n={selected:new Set,searchQuery:"",cursorIndex:0},i=ge({input:process.stdin,output:process.stdout});process.stdin.isTTY&&(process.stdin.setRawMode(!0),process.stdout.write("\x1B[?25l")),fe(process.stdin,i);let l=()=>he(t,o,n,s),p=(c,d)=>{let $=Q(o,n.searchQuery),m=$.length;if(d.name==="escape"||d.ctrl&&d.name==="c"){K(i,p),process.stdout.write("\x1B[2J\x1B[H"),r(null);return}if(d.name==="return"){K(i,p),process.stdout.write("\x1B[2J\x1B[H"),r([...n.selected]);return}if(d.name==="up")n.cursorIndex=Math.max(0,n.cursorIndex-1);else if(d.name==="down")n.cursorIndex=Math.min(m-1,n.cursorIndex+1);else if(d.name==="space"){let g=$[n.cursorIndex];g&&(n.selected.has(g.value)?n.selected.delete(g.value):n.selected.add(g.value))}else d.name==="backspace"?(n.searchQuery=n.searchQuery.slice(0,-1),n.cursorIndex=0):c&&c.length===1&&!d.ctrl&&!d.meta&&(n.searchQuery+=c,n.cursorIndex=0);m===0?n.cursorIndex=0:n.cursorIndex>=m&&(n.cursorIndex=m-1),l()};process.stdin.on("keypress",p),l()})};import S from"picocolors";var k=J,R=S.dim,ye=S.cyan,be=S.green,xe=S.red,Ke=S.yellow,q=S.bold,D=S.gray,$e=["\x1B[38;5;252m","\x1B[38;5;249m","\x1B[38;5;246m","\x1B[38;5;243m","\x1B[38;5;240m","\x1B[38;5;237m"],we="\x1B[0m",B=["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551","\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551","\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D"],ve="1.1.0";function T(e,t){console.log(`${e} ${t}`)}function E(e){T(ye(k.active),e)}function w(e){T(R(k.done),e)}function V(e){T(be(k.success),e)}function P(e){T(xe(k.error),e)}function y(e=""){console.log(`${R(k.bar)} ${e}`)}function j(){console.log();for(let e=0;e<B.length;e++)console.log(`${$e[e]}${B[e]}${we}`);console.log(),console.log(` ${R(`v${ve}`)}`),console.log()}import{existsSync as M,readFileSync as X}from"fs";import{join as A}from"path";var Se=/^(npm|pnpm|yarn|bun)@/,Ie=()=>{let e=process.cwd();for(let{file:o,cmd:s}of H)if(M(A(e,o)))return s;let t=A(e,"package.json");if(M(t))try{let o=JSON.parse(X(t,"utf-8"));if(o.packageManager){let s=o.packageManager.match(Se);if(s)return s[1]}}catch{}return"npm"},Re=()=>{let e=process.cwd();for(let t of Y)if(M(A(e,t)))return t;return null},je=()=>{let e=process.cwd(),t=["tsconfig.json","jsconfig.json"];for(let o of t){let s=A(e,o);if(M(s))try{let n=X(s,"utf-8").replace(/\/\*[\s\S]*?\*\/|\/\/.*/g,""),l=JSON.parse(n).compilerOptions?.paths;if(l){for(let[p,c]of Object.entries(l))if(p.endsWith("/*")&&Array.isArray(c))return p.slice(0,-2)}}catch{}}return"@"},z=()=>({componentPath:Re()||"components/ui",alias:je(),packageManager:Ie()});import{spawnSync as Z}from"child_process";import{existsSync as ee,mkdirSync as Ce,readFileSync as Ze,writeFileSync as ke}from"fs";import{dirname as Pe,isAbsolute as Oe,relative as Te,resolve as te}from"path";var Ee=(e,t)=>t==="@"?e:e.replace(/@\/components\//g,`${t}/components/`);var oe=async(e,t,o,s)=>{let r=[],n=[],i=o,l=te(process.cwd(),t.componentPath);for(let p of e.files){let c=p.target||p.path;c.startsWith("components/")&&(c=c.slice(11));let d=te(l,c),$=Te(l,d);if($.startsWith("..")||Oe($))throw new Error(`Invalid registry file path: ${c}`);let m=Pe(d);if(ee(m)||Ce(m,{recursive:!0}),ee(d)&&!i){let f=await s(c);if(f==="skip"){n.push(c);continue}f==="all"&&(i=!0)}let g=Ee(p.content,t.alias);ke(d,g,"utf-8"),r.push(c)}return{written:r,skipped:n}},ne=(e,t,o)=>{let s=!0;if(e.length>0){let r={npm:["npm","install",...e],pnpm:["pnpm","add",...e],yarn:["yarn","add",...e],bun:["bun","add",...e]},[n,...i]=r[o];Z(n,i,{stdio:"pipe"}).status!==0&&(s=!1)}if(t.length>0){let r={npm:["npm","install","-D",...t],pnpm:["pnpm","add","-D",...t],yarn:["yarn","add","-D",...t],bun:["bun","add","-d",...t]},[n,...i]=r[o];Z(n,i,{stdio:"pipe"}).status!==0&&(s=!1)}return s};var se=process.env.SMOOTHUI_REGISTRY_URL||_,Me=/\/r\/([^/]+)\.json$/;async function Ae(){let e=`${se}/r/registry.json`,t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch registry: ${t.status}`);return t.json()}async function re(e){let t=`${se}/r/${e}.json`,o=await fetch(t);if(!o.ok)throw new Error(`Component "${e}" not found`);return o.json()}function ie(e){let t=e.match(Me);return t?t[1]:e}async function L(){return(await Ae()).items.map(t=>t.name)}async function F(e,t=new Set){let o=await re(e);t.add(e);let s=[];if(o.registryDependencies)for(let r of o.registryDependencies){let n=ie(r);if(t.has(n)||!r.includes("smoothui.dev"))continue;let i=await F(n,t);s.push(i)}return{component:o,children:s}}function U(e){let t=[e.component];for(let o of e.children)t.push(...U(o));return t}function ce(e){let t=new Set,o=new Set,s=new Set(["react","react-dom","next","tailwindcss","@types/react","@types/react-dom","@types/node","typescript"]);for(let r of e){for(let n of r.dependencies||[])s.has(n)||t.add(n);for(let n of r.devDependencies||[])s.has(n)||o.add(n)}return{dependencies:[...t],devDependencies:[...o]}}function G(e,t="",o=!0){y(`${t}${o?"\u2514\u2500":"\u251C\u2500"} ${e.component.name}`);let r=t+(o?" ":"\u2502 "),n=[...e.component.dependencies||[]].filter(i=>!["react","react-dom","next"].includes(i));n.length>0&&e.children.length===0&&y(`${r}\u2514\u2500 ${D(`npm: ${n.join(", ")}`)}`);for(let i=0;i<e.children.length;i++){let l=e.children[i],p=i===e.children.length-1&&n.length===0;G(l,r,p)}n.length>0&&e.children.length>0&&y(`${r}\u2514\u2500 ${D(`npm: ${n.join(", ")}`)}`)}async function le(e,t){j();let o=z();t.path&&(o.componentPath=t.path),w(`Detected: ${o.componentPath}/ (${o.packageManager})`),console.log();let s=e;if(s.length===0){let b=(await L()).map(u=>{let v="Other";for(let[N,me]of Object.entries(O))if(me.includes(u)){v=N;break}return{value:u,label:u,category:v}}),x=await W({message:"Select components to install:",items:b});if(!x||x.length===0){console.log(),w("No components selected.");return}s=x,w(`Selected: ${s.join(", ")}`),console.log()}E("Resolving dependencies..."),y();let r=[],n=new Set;for(let f of s)if(!n.has(f))try{let b=await F(f),x=U(b);for(let u of x)n.has(u.name)||(n.add(u.name),r.push(u));G(b)}catch(b){P(`Failed to resolve ${f}: ${b.message}`);return}y();let{dependencies:i,devDependencies:l}=ce(r),p=[...i,...l],c=r.length,d=i.length+l.length,$=d>0?`Install ${c} component${c>1?"s":""} + ${d} npm package${d>1?"s":""}?`:`Install ${c} component${c>1?"s":""}?`,m=await Le({message:$});if(ae(m)||!m){w("Installation cancelled.");return}console.log();let g=t.force??!1;for(let f of r){let{written:b,skipped:x}=await oe(f,o,g,async u=>{let v=await Ne({message:`File exists: ${u}`,options:[{value:"overwrite",label:"Overwrite"},{value:"skip",label:"Skip"},{value:"all",label:"Overwrite all"}]});return ae(v)?"skip":(v==="all"&&(g=!0),v)});for(let u of b)w(`Written: ${o.componentPath}/${u}`);for(let u of x)w(`Skipped: ${u}`)}if(i.length>0||l.length>0){let f=De();if(f.start(`Installing ${p.join(", ")}`),ne(i,l,o.packageManager))f.stop(`Installed: ${p.join(", ")}`);else if(f.stop("Failed to install dependencies"),i.length>0&&y(`Run manually: ${o.packageManager} add ${i.join(" ")}`),l.length>0){let x=o.packageManager==="bun"?"-d":"-D";y(`Run manually: ${o.packageManager} add ${x} ${l.join(" ")}`)}}console.log(),V(`Done! ${c} component${c>1?"s":""} installed.`)}async function pe(e){let t=await L();if(e.json){console.log(JSON.stringify(t,null,2));return}j(),E(`Available components (${t.length})`),y();let o=new Map;for(let s of t){let r="Other";for(let[i,l]of Object.entries(O))if(l.includes(s)){r=i;break}let n=o.get(r);n?n.push(s):o.set(r,[s])}for(let[s,r]of o){y(q(R(s)));for(let n of r.sort())y(` ${n}`);y()}w(`Use ${R("npx smoothui add <component>")} to install`)}var C=process.argv.slice(2),I=C[0];function de(){j(),console.log("Usage: npx smoothui <command> [options]"),console.log(),console.log("Commands:"),console.log(" add [components...] Add components to your project"),console.log(" list List available components"),console.log(),console.log("Options:"),console.log(" --path <path> Custom component install path"),console.log(" --force Overwrite existing files without asking"),console.log(" --json Output as JSON (list command)"),console.log(" --help Show this help message"),console.log(),console.log("Examples:"),console.log(" npx smoothui add siri-orb"),console.log(" npx smoothui add siri-orb grid-loader"),console.log(" npx smoothui add # Interactive mode"),console.log(" npx smoothui list")}async function Fe(){try{if(!I||I==="--help"||I==="-h"){de();return}if(I==="add"){let e=[],t,o=!1;for(let s=1;s<C.length;s++){let r=C[s];r==="--path"&&C[s+1]?(t=C[s+1],s++):r==="--force"||r==="-f"?o=!0:r.startsWith("-")||e.push(r)}await le(e,{path:t,force:o});return}if(I==="list"||I==="ls"){let e=C.includes("--json");await pe({json:e});return}P(`Unknown command: ${I}`),de(),process.exit(1)}catch(e){let t=e instanceof Error?e.message:String(e);P(t||"An unknown error occurred"),process.exit(1)}}Fe();
import{confirm as et,isCancel as be,select as tt,spinner as nt}from"@clack/prompts";var X="https://smoothui.dev",D={"Basic UI":["accordion","animated-input","animated-progress-bar","animated-tabs","animated-toggle","basic-dropdown","basic-modal","basic-toast","notification-badge","searchable-dropdown","skeleton-loader","tweet-card"],Buttons:["button-copy","clip-corners-button","dot-morph-button","magnetic-button"],"Text Effects":["wave-text","reveal-text","typewriter-text","scramble-hover","scroll-reveal-paragraph"],AI:["ai-branch","ai-input"],"Cards & Layouts":["expandable-cards","glow-hover-card","scrollable-card-stack","switchboard-card","phototab","job-listing-component"],"Loaders & Effects":["grid-loader","siri-orb","cursor-follow","github-stars-animation"],Interactive:["animated-o-t-p-input","animated-tags","app-download-stack","apple-invites","contribution-graph","dynamic-island","figma-comment","image-metadata-preview","infinite-slider","interactive-image-selector","number-flow","power-off-slide","price-flow","rich-popover","reviews-carousel","social-selector","user-account-avatar"]},Z=["src/components/ui","components/ui","src/components","components","app/components/ui"],ee=[{file:"bun.lockb",cmd:"bun"},{file:"pnpm-lock.yaml",cmd:"pnpm"},{file:"yarn.lock",cmd:"yarn"},{file:"package-lock.json",cmd:"npm"}],te={active:"\u25C6",done:"\u25C7",selected:"\u25CF",unselected:"\u25CB",cursor:"\u276F",success:"\u2713",error:"\u2717",bar:"\u2502"};import{createInterface as je,emitKeypressEvents as Ee}from"readline";import{Writable as Te}from"stream";import m from"picocolors";var Ae=new Te({write(e,t,n){n()}}),Pe=m.green("\u25C6"),ke=m.red("\u25A0"),Oe=m.green("\u25C7"),Me=m.green("\u25CF"),Le=m.dim("\u25CB"),x=m.dim("\u2502"),ne=e=>{let{message:t,items:n,maxVisible:o=8}=e;return new Promise(s=>{let r=je({input:process.stdin,output:Ae,terminal:!1});process.stdin.isTTY&&process.stdin.setRawMode(!0),Ee(process.stdin,r);let c="",a=0,d=new Set,l=0,y=(p,i)=>{if(!i)return!0;let b=i.toLowerCase();return p.label.toLowerCase().includes(b)||p.value.toLowerCase().includes(b)},I=()=>n.filter(p=>y(p,c)),j=()=>{if(l>0){process.stdout.write(`\x1B[${l}A`);for(let p=0;p<l;p++)process.stdout.write("\x1B[2K\x1B[1B");process.stdout.write(`\x1B[${l}A`)}},h=(p="active")=>{j();let i=[],b=I(),A=p==="active"?Pe:p==="cancel"?ke:Oe;if(i.push(`${A} ${m.bold(t)}`),p==="active"){let K=`${x} ${m.dim("Search:")} ${c}${m.inverse(" ")}`;i.push(K),i.push(`${x} ${m.dim("\u2191\u2193 move, space select, enter confirm")}`),i.push(`${x}`);let R=Math.max(0,Math.min(a-Math.floor(o/2),b.length-o)),q=Math.min(b.length,R+o),z=b.slice(R,q);if(b.length===0)i.push(`${x} ${m.dim("No matches found")}`);else{for(let $=0;$<z.length;$++){let L=z[$],xe=R+$,ye=d.has(L.value),Q=xe===a,Se=ye?Me:Le,Re=Q?m.underline(L.label):L.label,Ce=L.hint?m.dim(` (${L.hint})`):"",Ie=Q?m.cyan("\u276F"):" ";i.push(`${x} ${Ie} ${Se} ${Re}${Ce}`)}let C=R,M=b.length-q;if(C>0||M>0){let $=[];C>0&&$.push(`\u2191 ${C} more`),M>0&&$.push(`\u2193 ${M} more`),i.push(`${x} ${m.dim($.join(" "))}`)}}if(i.push(`${x}`),d.size===0)i.push(`${x} ${m.dim("Selected: (none)")}`);else{let C=n.filter($=>d.has($.value)).map($=>$.label),M=C.length<=3?C.join(", "):`${C.slice(0,3).join(", ")} +${C.length-3} more`;i.push(`${x} ${m.green("Selected:")} ${M}`)}i.push(`${m.dim("\u2514")}`)}else if(p==="submit"){let K=n.filter(R=>d.has(R.value)).map(R=>R.label);i.push(`${x} ${m.dim(K.join(", "))}`)}else p==="cancel"&&i.push(`${x} ${m.strikethrough(m.dim("Cancelled"))}`);process.stdout.write(`${i.join(`
`)}
`),l=i.length},f=()=>{process.stdin.removeListener("keypress",g),process.stdin.isTTY&&process.stdin.setRawMode(!1),r.close()},v=()=>{h("submit"),f(),s([...d])},w=()=>{h("cancel"),f(),s(null)},g=(p,i)=>{if(!i)return;let b=I();if(i.name==="return"){v();return}if(i.name==="escape"||i.ctrl&&i.name==="c"){w();return}if(i.name==="up"){a=Math.max(0,a-1),h();return}if(i.name==="down"){a=Math.min(b.length-1,a+1),h();return}if(i.name==="space"){let A=b[a];A&&(d.has(A.value)?d.delete(A.value):d.add(A.value)),h();return}if(i.name==="backspace"){c=c.slice(0,-1),a=0,h();return}i.sequence&&!i.ctrl&&!i.meta&&i.sequence.length===1&&(c+=i.sequence,a=0,h())};process.stdin.on("keypress",g),h()})};import E from"picocolors";var N=te,P=E.dim,Ne=E.cyan,_e=E.green,De=E.red,mt=E.yellow,se=E.bold,H=E.gray,Fe=["\x1B[38;5;252m","\x1B[38;5;249m","\x1B[38;5;246m","\x1B[38;5;243m","\x1B[38;5;240m","\x1B[38;5;237m"],Ue="\x1B[0m",oe=["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551","\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551","\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D"],Ge="1.1.1";function F(e,t){console.log(`${e} ${t}`)}function U(e){F(Ne(N.active),e)}function S(e){F(P(N.done),e)}function re(e){F(_e(N.success),e)}function _(e){F(De(N.error),e)}function u(e=""){console.log(`${P(N.bar)} ${e}`)}function k(){console.log();for(let e=0;e<oe.length;e++)console.log(`${Fe[e]}${oe[e]}${Ue}`);console.log(),console.log(` ${P(`v${Ge}`)}`),console.log()}import{existsSync as G,readFileSync as ie}from"fs";import{join as Y}from"path";var Ye=/^(npm|pnpm|yarn|bun)@/,Be=()=>{let e=process.cwd();for(let{file:n,cmd:o}of ee)if(G(Y(e,n)))return o;let t=Y(e,"package.json");if(G(t))try{let n=JSON.parse(ie(t,"utf-8"));if(n.packageManager){let o=n.packageManager.match(Ye);if(o)return o[1]}}catch{}return"npm"},Ke=()=>{let e=process.cwd();for(let t of Z)if(G(Y(e,t)))return t;return null},He=()=>{let e=process.cwd(),t=["tsconfig.json","jsconfig.json"];for(let n of t){let o=Y(e,n);if(G(o))try{let r=ie(o,"utf-8").replace(/\/\*[\s\S]*?\*\/|\/\/.*/g,""),a=JSON.parse(r).compilerOptions?.paths;if(a){for(let[d,l]of Object.entries(a))if(d.endsWith("/*")&&Array.isArray(l))return d.slice(0,-2)}}catch{}}return"@"},ce=()=>({componentPath:Ke()||"components/ui",alias:He(),packageManager:Be()});import{spawnSync as ae}from"child_process";import{existsSync as le,mkdirSync as Ve,readFileSync as vt,writeFileSync as We}from"fs";import{dirname as Je,isAbsolute as qe,relative as ze,resolve as pe}from"path";var Qe=(e,t)=>t==="@"?e:e.replace(/@\/components\//g,`${t}/components/`);var me=async(e,t,n,o)=>{let s=[],r=[],c=n,a=pe(process.cwd(),t.componentPath);for(let d of e.files){let l=d.target||d.path;l.startsWith("components/")&&(l=l.slice(11));let y=pe(a,l),I=ze(a,y);if(I.startsWith("..")||qe(I))throw new Error(`Invalid registry file path: ${l}`);let j=Je(y);if(le(j)||Ve(j,{recursive:!0}),le(y)&&!c){let f=await o(l);if(f==="skip"){r.push(l);continue}f==="all"&&(c=!0)}let h=Qe(d.content,t.alias);We(y,h,"utf-8"),s.push(l)}return{written:s,skipped:r}},de=(e,t,n)=>{let o=!0;if(e.length>0){let s={npm:["npm","install",...e],pnpm:["pnpm","add",...e],yarn:["yarn","add",...e],bun:["bun","add",...e]},[r,...c]=s[n];ae(r,c,{stdio:"pipe"}).status!==0&&(o=!1)}if(t.length>0){let s={npm:["npm","install","-D",...t],pnpm:["pnpm","add","-D",...t],yarn:["yarn","add","-D",...t],bun:["bun","add","-d",...t]},[r,...c]=s[n];ae(r,c,{stdio:"pipe"}).status!==0&&(o=!1)}return o};var fe=process.env.SMOOTHUI_REGISTRY_URL||X,Xe=/\/r\/([^/]+)\.json$/;async function Ze(){let e=`${fe}/r/registry.json`,t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch registry: ${t.status}`);return t.json()}async function ge(e){let t=`${fe}/r/${e}.json`,n=await fetch(t);if(!n.ok)throw new Error(`Component "${e}" not found`);return n.json()}function ue(e){let t=e.match(Xe);return t?t[1]:e}async function B(){return(await Ze()).items.map(t=>t.name)}async function V(e,t=new Set){let n=await ge(e);t.add(e);let o=[];if(n.registryDependencies)for(let s of n.registryDependencies){let r=ue(s);if(t.has(r)||!s.includes("smoothui.dev"))continue;let c=await V(r,t);o.push(c)}return{component:n,children:o}}function W(e){let t=[e.component];for(let n of e.children)t.push(...W(n));return t}function he(e){let t=new Set,n=new Set,o=new Set(["react","react-dom","next","tailwindcss","@types/react","@types/react-dom","@types/node","typescript"]);for(let s of e){for(let r of s.dependencies||[])o.has(r)||t.add(r);for(let r of s.devDependencies||[])o.has(r)||n.add(r)}return{dependencies:[...t],devDependencies:[...n]}}function J(e,t="",n=!0){u(`${t}${n?"\u2514\u2500":"\u251C\u2500"} ${e.component.name}`);let s=t+(n?" ":"\u2502 "),r=[...e.component.dependencies||[]].filter(c=>!["react","react-dom","next"].includes(c));r.length>0&&e.children.length===0&&u(`${s}\u2514\u2500 ${H(`npm: ${r.join(", ")}`)}`);for(let c=0;c<e.children.length;c++){let a=e.children[c],d=c===e.children.length-1&&r.length===0;J(a,s,d)}r.length>0&&e.children.length>0&&u(`${s}\u2514\u2500 ${H(`npm: ${r.join(", ")}`)}`)}async function $e(e,t){k();let n=ce();t.path&&(n.componentPath=t.path),S(`Detected: ${n.componentPath}/ (${n.packageManager})`),console.log();let o=e;if(o.length===0){let v=(await B()).map(g=>{let p="Other";for(let[i,b]of Object.entries(D))if(b.includes(g)){p=i;break}return{value:g,label:g,category:p}}),w=await ne({message:"Select components to install:",items:v});if(!w||w.length===0){console.log(),S("No components selected.");return}o=w,S(`Selected: ${o.join(", ")}`),console.log()}U("Resolving dependencies..."),u();let s=[],r=new Set;for(let f of o)if(!r.has(f))try{let v=await V(f),w=W(v);for(let g of w)r.has(g.name)||(r.add(g.name),s.push(g));J(v)}catch(v){_(`Failed to resolve ${f}: ${v.message}`);return}u();let{dependencies:c,devDependencies:a}=he(s),d=[...c,...a],l=s.length,y=c.length+a.length,I=y>0?`Install ${l} component${l>1?"s":""} + ${y} npm package${y>1?"s":""}?`:`Install ${l} component${l>1?"s":""}?`,j=await et({message:I});if(be(j)||!j){S("Installation cancelled.");return}console.log();let h=t.force??!1;for(let f of s){let{written:v,skipped:w}=await me(f,n,h,async g=>{let p=await tt({message:`File exists: ${g}`,options:[{value:"overwrite",label:"Overwrite"},{value:"skip",label:"Skip"},{value:"all",label:"Overwrite all"}]});return be(p)?"skip":(p==="all"&&(h=!0),p)});for(let g of v)S(`Written: ${n.componentPath}/${g}`);for(let g of w)S(`Skipped: ${g}`)}if(c.length>0||a.length>0){let f=nt();if(f.start(`Installing ${d.join(", ")}`),de(c,a,n.packageManager))f.stop(`Installed: ${d.join(", ")}`);else if(f.stop("Failed to install dependencies"),c.length>0&&u(`Run manually: ${n.packageManager} add ${c.join(" ")}`),a.length>0){let w=n.packageManager==="bun"?"-d":"-D";u(`Run manually: ${n.packageManager} add ${w} ${a.join(" ")}`)}}console.log(),re(`Done! ${l} component${l>1?"s":""} installed.`)}async function ve(e){let t=await B();if(e.json){console.log(JSON.stringify(t,null,2));return}k(),U(`Available components (${t.length})`),u();let n=new Map;for(let o of t){let s="Other";for(let[c,a]of Object.entries(D))if(a.includes(o)){s=c;break}let r=n.get(s);r?r.push(o):n.set(s,[o])}for(let[o,s]of n){u(se(P(o)));for(let r of s.sort())u(` ${r}`);u()}S(`Use ${P("npx smoothui add <component>")} to install`)}var O=process.argv.slice(2),T=O[0];function we(){k(),console.log("Usage: npx smoothui <command> [options]"),console.log(),console.log("Commands:"),console.log(" add [components...] Add components to your project"),console.log(" list List available components"),console.log(),console.log("Options:"),console.log(" --path <path> Custom component install path"),console.log(" --force Overwrite existing files without asking"),console.log(" --json Output as JSON (list command)"),console.log(" --help Show this help message"),console.log(),console.log("Examples:"),console.log(" npx smoothui add siri-orb"),console.log(" npx smoothui add siri-orb grid-loader"),console.log(" npx smoothui add # Interactive mode"),console.log(" npx smoothui list")}async function ot(){try{if(!T||T==="--help"||T==="-h"){we();return}if(T==="add"){let e=[],t,n=!1;for(let o=1;o<O.length;o++){let s=O[o];s==="--path"&&O[o+1]?(t=O[o+1],o++):s==="--force"||s==="-f"?n=!0:s.startsWith("-")||e.push(s)}await $e(e,{path:t,force:n});return}if(T==="list"||T==="ls"){let e=O.includes("--json");await ve({json:e});return}_(`Unknown command: ${T}`),we(),process.exit(1)}catch(e){let t=e instanceof Error?e.message:String(e);_(t||"An unknown error occurred"),process.exit(1)}}ot();
{
"name": "smoothui-cli",
"version": "1.1.0",
"version": "1.1.1",
"author": "educalvolpz",

@@ -5,0 +5,0 @@ "description": "CLI to install SmoothUI components - beautifully designed React components with smooth animations",

@@ -1,99 +0,15 @@

# SmoothUI
# smoothui-cli
![Screenshot of SmoothUI](/apps/docs/public/readme.png)
CLI to install [SmoothUI](https://smoothui.dev) components - beautifully designed React components with smooth animations.
<div align="center">
## Installation
![Next.js Badge](https://img.shields.io/badge/Next.js-000?logo=nextdotjs&logoColor=fff&style=flat)
![Tailwind CSS Badge](https://img.shields.io/badge/Tailwind%20CSS-06B6D4?logo=tailwindcss&logoColor=fff&style=flat)
![Motion Badge](https://img.shields.io/badge/Motion-ECD53F?style=flat)
[![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fpheralb%2Fsvgl%2Fbadge%3Fref%3Dmain&style=flat)](https://actions-badge.atrox.dev/educlopez/smoothui/goto?ref=main)
![GitHub stars](https://img.shields.io/github/stars/educlopez/smoothui)
![GitHub issues](https://img.shields.io/github/issues/educlopez/smoothui)
![GitHub forks](https://img.shields.io/github/forks/educlopez/smoothui)
![GitHub PRs](https://img.shields.io/github/issues-pr/educlopez/smoothui)
[![Website](https://img.shields.io/badge/website-smoothui.dev-blue)](https://smoothui.dev)
</div>
SmoothUI is a collection of beautifully designed components with smooth animations built with React, Tailwind CSS, and Motion. This project aims to provide developers with a set of reusable UI components that enhance user experience through delightful animations and modern design patterns.
## Table of Contents
- [SmoothUI](#smoothui)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Quick Start](#quick-start)
- [Installation](#installation)
- [Using SmoothUI CLI](#using-smoothui-cli)
- [Using shadcn CLI](#using-shadcn-cli)
- [Manual Installation](#manual-installation)
- [Usage](#usage)
- [Basic Usage](#basic-usage)
- [Advanced Usage](#advanced-usage)
- [Available Components](#available-components)
- [UI Components](#ui-components)
- [Interactive Components](#interactive-components)
- [Layout Components](#layout-components)
- [Utility Components](#utility-components)
- [MCP Support](#mcp-support)
- [🤖 AI Assistant Integration](#-ai-assistant-integration)
- [Quick MCP Setup](#quick-mcp-setup)
- [Registry System](#registry-system)
- [Automatic Dependencies](#automatic-dependencies)
- [Component Structure](#component-structure)
- [Registry Features](#registry-features)
- [Troubleshooting](#troubleshooting)
- [Common Issues](#common-issues)
- [1. Authentication Error (401)](#1-authentication-error-401)
- [2. Registry Not Found](#2-registry-not-found)
- [3. Import Path Issues](#3-import-path-issues)
- [4. Missing Dependencies](#4-missing-dependencies)
- [Getting Help](#getting-help)
- [Contributing](#contributing)
- [Development Setup](#development-setup)
- [License](#license)
## Features
- **Modern Design System**: A cohesive and contemporary design language with a new mascot called Smoothy
- **Smooth Animations**: Built-in animations powered by Motion for delightful user experiences
- **Responsive Design**: Fully responsive components designed with Tailwind CSS
- **Dark Mode Support**: Components support both light and dark themes out of the box
- **Color Customization**: Dynamic color switcher for easy theme customization
- **Documentation**: Comprehensive documentation with props, examples, and usage guidelines
- **Accessibility**: Enhanced accessibility features across all components
- **TypeScript Support**: Full TypeScript support with type definitions
- **Easy Integration**: Simple API for integrating components into your projects
- **CLI Tools**: Dedicated SmoothUI CLI and shadcn registry support for easy component installation
## Quick Start
Get started with SmoothUI in just one command:
```bash
# Using SmoothUI CLI (recommended)
npx smoothui-cli add siri-orb
# Or using shadcn CLI
npx shadcn@latest add @smoothui/siri-orb
```
Then use the component:
## Usage
```tsx
import { SiriOrb } from "@/components/smoothui/ui/SiriOrb";
### Add components
export default function App() {
return <SiriOrb size="200px" />;
}
```
## Installation
### Using SmoothUI CLI
The SmoothUI CLI provides an interactive way to browse and install components with automatic dependency resolution.
```bash

@@ -104,311 +20,53 @@ # Add a single component

# Add multiple components
npx smoothui-cli add siri-orb rich-popover animated-input
npx smoothui-cli add siri-orb grid-loader animated-tabs
# Interactive mode - browse and select components
# Interactive mode - browse and select
npx smoothui-cli add
# List all available components
npx smoothui-cli list
```
**Features:**
### List components
- Interactive component picker with search and categories
- Auto-detects package manager (npm, pnpm, yarn, bun)
- Auto-detects component paths and tsconfig aliases
- Shows dependency tree before installation
- Handles file conflicts with overwrite prompts
- Auto-installs npm dependencies
### Using shadcn CLI
SmoothUI is an official shadcn registry, so you can install components directly using the `@smoothui` namespace:
```bash
# Install a single component
npx shadcn@latest add @smoothui/siri-orb
# Show all available components
npx smoothui-cli list
# Install multiple components
npx shadcn@latest add @smoothui/rich-popover @smoothui/animated-input
# JSON output
npx smoothui-cli list --json
```
### Manual Installation
### Options
If you prefer to install components manually, you can copy the component files directly:
1. **Install dependencies**:
```bash
pnpm add motion tailwindcss lucide-react clsx tailwind-merge
```
# Custom install path
npx smoothui-cli add siri-orb --path src/components/ui
2. **Copy component files** from the [components directory](src/components/smoothui/ui/)
3. **Set up utilities**:
```bash
# Create lib/utils/cn.ts
mkdir -p lib/utils
# Force overwrite existing files
npx smoothui-cli add siri-orb --force
```
```tsx
// lib/utils/cn.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
## Features
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
```
- Interactive component picker with search and categories
- Auto-detects package manager (npm, pnpm, yarn, bun)
- Auto-detects component paths and tsconfig aliases
- Shows dependency tree before installation
- Handles file conflicts with overwrite prompts
- Auto-installs npm dependencies
## Usage
## Alternative: shadcn CLI
### Basic Usage
You can also use the shadcn CLI with the `@smoothui` registry:
```tsx
import { SiriOrb } from "@/components/smoothui/ui/SiriOrb";
export default function App() {
return (
<div className="flex min-h-screen items-center justify-center">
<SiriOrb
size="200px"
colors={{
bg: "oklch(95% 0.02 264.695)",
c1: "oklch(75% 0.15 350)",
c2: "oklch(80% 0.12 200)",
c3: "oklch(78% 0.14 280)",
}}
animationDuration={20}
/>
</div>
);
}
```
### Advanced Usage
```tsx
import { RichPopover } from "@/components/smoothui/ui/RichPopover";
import { ScrollableCardStack } from "@/components/smoothui/ui/ScrollableCardStack";
export default function Dashboard() {
const cards = [
{
id: "1",
name: "John Doe",
handle: "@johndoe",
avatar: "/avatars/john.jpg",
video: "/videos/john.mp4",
href: "https://twitter.com/johndoe",
},
// ... more cards
];
return (
<div className="space-y-8">
<RichPopover />
<ScrollableCardStack items={cards} />
</div>
);
}
```
## Available Components
SmoothUI includes a wide variety of components:
### UI Components
- **SiriOrb** - Animated orb with smooth color transitions
- **RichPopover** - Advanced popover with rich content
- **ScrollableCardStack** - Interactive card stack with smooth scrolling
- **AnimatedInput** - Input field with smooth animations
- **DynamicIsland** - iOS-style dynamic island component
- **FluidMorph** - Fluid morphing animations
- **MatrixCard** - Matrix-style card with particle effects
### Interactive Components
- **CursorFollow** - Custom cursor following component
- **ScrambleHover** - Text scramble effect on hover
- **WaveText** - Animated wave text effect
- **TypewriterText** - Typewriter text animation
### Layout Components
- **ExpandableCards** - Expandable card layout
- **ScrollableCardStack** - Stack of scrollable cards
- **AppDownloadStack** - App download showcase
### Utility Components
- **ButtonCopy** - Copy button with feedback
- **ClipCornersButton** - Button with clipped corners
- **DotMorphButton** - Button with morphing dot animation
[View all components →](https://smoothui.dev)
## MCP Support
SmoothUI is fully compatible with the **shadcn MCP server**, enabling AI assistants to discover and install components automatically.
### 🤖 AI Assistant Integration
With MCP support, AI assistants like **Claude**, **Cursor**, and **GitHub Copilot** can:
- **Discover Components**: Browse all available SmoothUI components
- **Install Components**: Automatically install components with dependencies
- **Provide Usage Examples**: Get code examples and integration help
- **Smart Suggestions**: Receive intelligent component recommendations
### Quick MCP Setup
1. **Configure your registry** in `components.json`:
```json
{
"registries": {
"@smoothui": "https://smoothui.dev/r/{name}.json"
}
}
```
2. **Install MCP server**:
```bash
npx shadcn@latest mcp init --client claude
# or for Cursor: npx shadcn@latest mcp init --client cursor
# or for VS Code: npx shadcn@latest mcp init --client vscode
```
3. **Try these prompts**:
- "Show me the components in the smoothui registry"
- "Install the SiriOrb component from smoothui"
- "Create a landing page using smoothui components"
[Learn more about MCP support →](https://smoothui.dev/doc/mcp)
## Registry System
SmoothUI uses a custom registry system compatible with shadcn CLI v3. Each component includes:
### Automatic Dependencies
- **Package Dependencies**: Required npm packages are automatically included
- **Utility Files**: Shared utilities like `cn` are automatically bundled
- **Import Paths**: All import paths are automatically resolved
### Component Structure
When you install a component, you get:
```
components/smoothui/ui/
├── ComponentName.tsx # Main component file
lib/utils/
└── cn.ts # Utility functions (if needed)
```
### Registry Features
- **Self-contained**: Each component includes all necessary dependencies
- **Type-safe**: Full TypeScript support with proper types
- **Optimized**: Components are optimized for performance
- **Accessible**: Built-in accessibility features
## Troubleshooting
### Common Issues
#### 1. Authentication Error (401)
**Error**: `You are not authorized to access the item`
**Solution**: This usually happens with Vercel preview deployments. Use the production URL:
```json
{
"registries": {
"@smoothui": "https://smoothui.dev/r/{name}.json"
}
}
```
#### 2. Registry Not Found
**Error**: `The item at https://smoothui.dev/r/registry.json was not found`
**Solution**: The search command might not work as expected. Install components directly:
```bash
npx shadcn@latest add @smoothui/siri-orb
```
#### 3. Import Path Issues
## Links
**Error**: `Cannot find module '@/lib/utils/cn'`
- [Documentation](https://smoothui.dev)
- [Components](https://smoothui.dev/docs/components)
- [GitHub](https://github.com/educlopez/smoothui)
**Solution**: Make sure your `tsconfig.json` includes the path alias:
```json
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
```
#### 4. Missing Dependencies
**Error**: `Cannot find module 'clsx'`
**Solution**: Install missing dependencies:
```bash
pnpm add clsx tailwind-merge motion
```
### Getting Help
- **Documentation**: Visit [smoothui.dev](https://smoothui.dev) for detailed documentation
- **Issues**: Report bugs on [GitHub Issues](https://github.com/educlopez/smoothui/issues)
- **Discussions**: Join discussions on [GitHub Discussions](https://github.com/educlopez/smoothui/discussions)
## Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
### Development Setup
1. **Clone the repository**:
```bash
git clone https://github.com/educlopez/smoothui.git
cd smoothui
```
2. **Install dependencies**:
```bash
pnpm install
```
3. **Start development server**:
```bash
pnpm dev
```
4. **Build registry**:
```bash
pnpm run build:registry
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
MIT