velyx 1.0.2 → 2.0.0

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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Velyx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -44,7 +44,7 @@ Velyx can be executed without installation.
44
44
  ### Initialize Velyx in a project
45
45
 
46
46
  ```bash
47
- npx velyx init
47
+ npx velyx@latest init
48
48
  ```
49
49
 
50
50
  This command:
@@ -57,7 +57,7 @@ This command:
57
57
  ### Add a component
58
58
 
59
59
  ```bash
60
- npx velyx add button
60
+ npx velyx@latest add button
61
61
  ```
62
62
 
63
63
  Velyx will:
@@ -77,7 +77,31 @@ resources/views/components/ui
77
77
  ### List available components
78
78
 
79
79
  ```bash
80
- npx velyx list
80
+ npx velyx@latest list
81
+ ```
82
+
83
+ ### Search for a component
84
+
85
+ ```bash
86
+ npx velyx@latest search
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Installation
92
+
93
+ Velyx can be used without installation via `npx`, but you can also install it globally for frequent use:
94
+
95
+ ```bash
96
+ npm install -g velyx@latest
97
+ # or
98
+ pnpm add -g velyx@latest
99
+ ```
100
+
101
+ For development releases (beta/next tags):
102
+
103
+ ```bash
104
+ npx velyx@latest
81
105
  ```
82
106
 
83
107
  ---
@@ -88,7 +112,7 @@ Velyx does **not** update your code automatically.
88
112
 
89
113
  If a component changes in the registry and you want the new version:
90
114
 
91
- - run `velyx add <component>` again
115
+ - run `npx velyx@latest add <component>` again
92
116
  - review the changes
93
117
  - decide what to keep
94
118
 
@@ -107,15 +131,29 @@ Velyx exists to help you move faster, not to take control away from you.
107
131
 
108
132
  ---
109
133
 
134
+ ## Configuration
135
+
136
+ After running `npx velyx@latest init`, a `velyx.json` file is created in your project root. This file stores your Velyx configuration and can be customized to your needs.
137
+
110
138
  ## Documentation
111
139
 
112
- Full documentation lives in the `docs` repository:
140
+ Full documentation is available at [velyx.dev](https://velyx.dev):
113
141
 
114
142
  - Introduction
115
143
  - Getting started
116
144
  - Component reference
117
145
  - Project philosophy
118
146
 
147
+ Technical documentation for testing architecture:
148
+
149
+ - [docs/TESTING.md](docs/TESTING.md)
150
+
151
+ ## Links
152
+
153
+ - **Registry**: [registry.velyx.dev](https://registry.velyx.dev)
154
+ - **Documentation**: [velyx.dev](https://velyx.dev)
155
+ - **GitHub**: [github.com/velyx-labs/cli](https://github.com/velyx-labs/cli)
156
+
119
157
  ---
120
158
 
121
159
  ## License
package/dist/index.js CHANGED
@@ -1,23 +1,23 @@
1
- import v from'chalk';import {Command}from'commander';import b from'path';import w from'fs-extra';import Se from'prompts';import R,{promises}from'fs';import {cyan,green,yellow,red}from'kleur/colors';import {exec}from'child_process';import {promisify}from'util';import Ze from'ora';import {z as z$1}from'zod';import bt from'cli-table3';var H=".bak";function ae(r){if(!w.existsSync(r))return null;let e=`${r}${H}`;try{return w.renameSync(r,e),e}catch(t){return console.error(`Failed to create backup of ${r}: ${t}`),null}}function N(r){let e=`${r}${H}`;if(!w.existsSync(e))return false;try{return w.renameSync(e,r),!0}catch(t){return console.error(`Warning: Could not restore backup file ${e}: ${t}`),false}}function T(r){let e=`${r}${H}`;if(!w.existsSync(e))return false;try{return w.unlinkSync(e),!0}catch{return false}}var u=class{async fileExists(e){try{return await promises.access(e),!0}catch{return false}}async writeFile(e,t){await promises.mkdir(b.dirname(e),{recursive:true}),await promises.writeFile(e,t,"utf-8");}async readFile(e){return await promises.readFile(e,"utf-8")}async ensureDir(e){await promises.mkdir(e,{recursive:true});}};function le(){return R.existsSync("composer.json")&&R.existsSync("artisan")}function pe(){try{return JSON.parse(R.readFileSync("package.json","utf8"))}catch{return null}}function me(r){let e={...r.dependencies,...r.devDependencies};if(e["@tailwindcss/vite"]||e["@tailwindcss/postcss"])return true;if(e.tailwindcss){let n=String(e.tailwindcss).match(/(\d+)/);return n?Number(n[1])>=4:false}return false}function Ae(){try{let r=JSON.parse(R.readFileSync("package.json","utf8")),e=r.dependencies&&Object.keys(r.dependencies).some(n=>n.toLowerCase().includes("alpine")),t=r.devDependencies&&Object.keys(r.devDependencies).some(n=>n.toLowerCase().includes("alpine"));return !!(e||t)}catch{return false}}function Le(){let r="resources/views/layouts";if(!R.existsSync(r))return false;try{let e=R.readdirSync(r,{recursive:!0});for(let t of e)if(t.endsWith(".blade.php")&&R.readFileSync(b.join(r,t),"utf8").toLowerCase().includes("alpine"))return !0}catch{return false}return false}function de(){return Ae()||Le()}function D(){return R.existsSync("pnpm-lock.yaml")||R.existsSync("pnpm-lock.yml")?"pnpm":R.existsSync("yarn.lock")?"yarn":R.existsSync("package-lock.json")?"npm":R.existsSync("bun.lock")?"bun":"npm"}var Ue=["resources/css/app.css","resources/css/app.scss","resources/css/main.css","resources/css/style.css","resources/css/styles.css"];function fe(){for(let r of Ue)if(R.existsSync(r))return {path:r,content:R.readFileSync(r,"utf8")};return null}function K(r){return /@import\s+["']tailwindcss["']/.test(r)}function ue(r){let e=R.readFileSync(r,"utf8");e.includes('@import "./velyx.css"')||(K(e)?e=e.replace(/@import\s+["']tailwindcss["'];?/,t=>`${t}
1
+ import v from'chalk';import {Command}from'commander';import w from'path';import h from'fs-extra';import be from'prompts';import S,{promises,readFileSync}from'fs';import {cyan,green,yellow,red}from'kleur/colors';import {exec}from'child_process';import {promisify}from'util';import tt from'ora';import {z as z$1}from'zod';import It from'cli-table3';var Y=".bak";function ie(r){if(!h.existsSync(r))return null;let e=`${r}${Y}`;try{return h.renameSync(r,e),e}catch(t){return console.error(`Failed to create backup of ${r}: ${t}`),null}}function N(r){let e=`${r}${Y}`;if(!h.existsSync(e))return false;try{return h.renameSync(e,r),!0}catch(t){return console.error(`Warning: Could not restore backup file ${e}: ${t}`),false}}function T(r){let e=`${r}${Y}`;if(!h.existsSync(e))return false;try{return h.unlinkSync(e),!0}catch{return false}}var f=class{async fileExists(e){try{return await promises.access(e),!0}catch{return false}}async writeFile(e,t){await promises.mkdir(w.dirname(e),{recursive:true}),await promises.writeFile(e,t,"utf-8");}async readFile(e){return await promises.readFile(e,"utf-8")}async ensureDir(e){await promises.mkdir(e,{recursive:true});}};function ce(){return S.existsSync("composer.json")&&S.existsSync("artisan")}function le(){try{return JSON.parse(S.readFileSync("package.json","utf8"))}catch{return null}}function pe(r){let e={...r.dependencies,...r.devDependencies};if(e["@tailwindcss/vite"]||e["@tailwindcss/postcss"])return true;if(e.tailwindcss){let n=String(e.tailwindcss).match(/(\d+)/);return n?Number(n[1])>=4:false}return false}function Ue(){try{let r=JSON.parse(S.readFileSync("package.json","utf8")),e=r.dependencies&&Object.keys(r.dependencies).some(n=>n.toLowerCase().includes("alpine")),t=r.devDependencies&&Object.keys(r.devDependencies).some(n=>n.toLowerCase().includes("alpine"));return !!(e||t)}catch{return false}}function Je(){let r="resources/views/layouts";if(!S.existsSync(r))return false;try{let e=S.readdirSync(r,{recursive:!0});for(let t of e)if(t.endsWith(".blade.php")&&S.readFileSync(w.join(r,t),"utf8").toLowerCase().includes("alpine"))return !0}catch{return false}return false}function me(){return Ue()||Je()}function V(){return S.existsSync("pnpm-lock.yaml")||S.existsSync("pnpm-lock.yml")?"pnpm":S.existsSync("yarn.lock")?"yarn":S.existsSync("package-lock.json")?"npm":S.existsSync("bun.lock")?"bun":"npm"}var qe=["resources/css/app.css","resources/css/app.scss","resources/css/main.css","resources/css/style.css","resources/css/styles.css"];function de(){for(let r of qe)if(S.existsSync(r))return {path:r,content:S.readFileSync(r,"utf8")};return null}function H(r){return /@import\s+["']tailwindcss["']/.test(r)}function fe(r){let e=S.readFileSync(r,"utf8");e.includes('@import "./velyx.css"')||(H(e)?e=e.replace(/@import\s+["']tailwindcss["'];?/,t=>`${t}
2
2
  @import "./velyx.css";`):e+=`
3
3
  @import "./velyx.css";
4
- `,R.writeFileSync(r,e,"utf8"));}var Je=["resources/js/app.js","resources/js/main.js","resources/js/index.js"];function ge(){for(let r of Je)if(R.existsSync(r))return {path:r,content:R.readFileSync(r,"utf8")};return null}function ye(r,e,t){let n=R.readFileSync(r,"utf8"),o=`import ${e} from '${t}'`;if(n.includes(o)||n.includes(`import ${e} from "${t}"`))return;let i=n.split(`
5
- `),a=-1;for(let c=0;c<i.length;c++)i[c]?.startsWith("import ")&&(a=c);i.splice(a+1,0,o),n=i.join(`
6
- `);let l=`Alpine.data('${e}', ${e});`;n.includes("document.addEventListener('alpine:init'")?n.includes(l)||(n=n.replace(/document\.addEventListener\('alpine:init',\s*\(\)\s*=>\s*\{/,c=>`${c}
4
+ `,S.writeFileSync(r,e,"utf8"));}function Be(r){return r.replace(/^[^a-zA-Z_$]+/,"").replace(/[-_]+([a-zA-Z0-9])/g,(e,t)=>t.toUpperCase())}var We=["resources/js/app.js","resources/js/main.js","resources/js/index.js"];function ue(){for(let r of We)if(S.existsSync(r))return {path:r,content:S.readFileSync(r,"utf8")};return null}function ge(r,e,t){let n=S.readFileSync(r,"utf8"),s=Be(e),i=`import ${s} from '${t}'`;if(n.includes(i)||n.includes(`import ${s} from "${t}"`))return;let a=n.split(`
5
+ `),c=-1;for(let m=0;m<a.length;m++)a[m]?.startsWith("import ")&&(c=m);a.splice(c+1,0,i),n=a.join(`
6
+ `);let l=`Alpine.data('${s}', ${s});`;n.includes("document.addEventListener('alpine:init'")?n.includes(l)||(n=n.replace(/document\.addEventListener\('alpine:init',\s*\(\)\s*=>\s*\{/,m=>`${m}
7
7
  ${l}`)):n+=`
8
8
 
9
9
  document.addEventListener('alpine:init', () => {
10
10
  ${l}
11
11
  });
12
- `,R.writeFileSync(r,n,"utf8");}function qe(r){let e=r;for(let t=0;t<4;t+=1){let n=b.join(e,"colors");if(R.existsSync(n))return n;let o=b.join(e,"src/colors");if(R.existsSync(o))return o;let i=b.dirname(e);if(i===e)break;e=i;}return b.join(r,"colors")}var Be=process.argv[1]?b.dirname(b.resolve(process.argv[1])):process.cwd(),X=qe(Be);function we(){return R.existsSync(X)?R.readdirSync(X).filter(e=>e.endsWith(".json")).map(e=>{let t=b.join(X,e),n=R.readFileSync(t,"utf-8");return JSON.parse(n)}).filter(e=>!!e?.name).sort((e,t)=>e.name.localeCompare(t.name)):[]}function A(){return we()}function We(r){return we().find(e=>e.name===r)}function he(r){return Object.entries(r).map(([e,t])=>` --${e}: ${t};`)}function xe(r,e){let t=We(r);if(!t)throw new Error(`Theme "${r}" not found in colors registry.`);let n=he(t.cssVars.light),o=he(t.cssVars.dark),i=[":root {",...n,"}","",".dark {",...o,"}",""].join(`
13
- `);R.writeFileSync(e,i,{encoding:"utf-8",flag:"wx"});}var m={error:red,warn:yellow,info:cyan,success:green};var s={error(...r){console.log(m.error(r.join(" ")));},warn(...r){console.log(m.warn(r.join(" ")));},info(...r){console.log(m.info(r.join(" ")));},success(...r){console.log(m.success(r.join(" ")));},log(...r){console.log(r.join(" "));},break(){console.log("");}};function ve(r){R.writeFileSync("velyx.json",JSON.stringify(r,null,2)+`
14
- `,"utf8");}function be(){return R.existsSync("velyx.json")||(s.error("Velyx configuration not found."),process.exit(1)),JSON.parse(R.readFileSync("velyx.json","utf8"))}var P={version:"1.0.2"};var L=class{constructor(e){this.fileSystem=e;}validateEnvironment(){if(!le())throw new Error("No Laravel project detected");let e=pe();if(!e||!me(e))throw new Error("Tailwind CSS v4 was not detected");let t=de(),n=D(),o=fe(),i=ge(),a=o?K(o.content):false;return {isLaravel:true,hasTailwindV4:true,hasAlpine:t,detectedPackageManager:n,cssFile:o,jsFile:i,canInjectCss:a}}displayEnvironmentInfo(e){e.hasAlpine?s.success("Alpine.js detected - components will be fully interactive"):(s.warn("Alpine.js not detected"),s.log(`Install Alpine.js: ${e.detectedPackageManager} install alpinejs`)),e.cssFile?e.canInjectCss||(s.warn("Tailwind import not found in CSS"),s.log("Velyx styles will not be auto-imported")):(s.warn("No main CSS file found"),s.log("Styles will be created but not auto-imported")),e.jsFile||(s.warn("No main JS file found"),s.log("Component scripts will not be auto-imported"));}async createComponentsDirectory(e="resources/views/components/ui"){await this.fileSystem.ensureDir(e);}async createThemeFile(e,t="resources/css/velyx.css"){let n=t.split("/").slice(0,-1).join("/");if(await this.fileSystem.ensureDir(n),R.existsSync(t))s.info("velyx.css already exists");else try{xe(e,t),s.success("Velyx theme created"),s.info(t);}catch(o){throw new Error(`Failed to create theme file: ${o.message}`)}}async injectStylesImport(e){ue(e),s.success("Velyx styles imported"),s.info(e);}async generateConfig(e,t){let n={version:P.version,theme:e.theme,packageManager:e.packageManager,css:{entry:t.cssFile?.path??"",velyx:"resources/css/velyx.css"},js:{entry:t.jsFile?.path??""},components:{path:"resources/views/components/ui"}};ve(n),s.success("velyx.json config generated");}displaySummary(e,t,n){console.log(`
15
- ---`),s.success("Laravel project detected"),s.success("Tailwind CSS v4 detected"),s.success(`Theme selected: ${e.theme}`),s.success(`Package manager: ${e.packageManager}`),s.success("UI components directory ready"),t.jsFile&&s.success("Main JS file detected"),s.success(n?"Styles import complete":"Styles import pending"),s.success("velyx.json created"),console.log(`
12
+ `,S.writeFileSync(r,n,"utf8");}function Ge(r){let e=r;for(let t=0;t<4;t+=1){let n=w.join(e,"colors");if(S.existsSync(n))return n;let s=w.join(e,"src/colors");if(S.existsSync(s))return s;let i=w.dirname(e);if(i===e)break;e=i;}return w.join(r,"colors")}var ze=process.argv[1]?w.dirname(w.resolve(process.argv[1])):process.cwd(),Z=Ge(ze);function he(){return S.existsSync(Z)?S.readdirSync(Z).filter(e=>e.endsWith(".json")).map(e=>{let t=w.join(Z,e),n=S.readFileSync(t,"utf-8");return JSON.parse(n)}).filter(e=>!!e?.name).sort((e,t)=>e.name.localeCompare(t.name)):[]}function A(){return he()}function Ye(r){return he().find(e=>e.name===r)}function ye(r){return Object.entries(r).map(([e,t])=>` --${e}: ${t};`)}function xe(r,e){let t=Ye(r);if(!t)throw new Error(`Theme "${r}" not found in colors registry.`);let n=ye(t.cssVars.light),s=ye(t.cssVars.dark),i=[":root {",...n,"}","",".dark {",...s,"}",""].join(`
13
+ `);S.writeFileSync(e,i,{encoding:"utf-8",flag:"wx"});}var d={error:red,warn:yellow,info:cyan,success:green};var o={error(...r){console.log(d.error(r.join(" ")));},warn(...r){console.log(d.warn(r.join(" ")));},info(...r){console.log(d.info(r.join(" ")));},success(...r){console.log(d.success(r.join(" ")));},log(...r){console.log(r.join(" "));},break(){console.log("");}};function ve(r){S.writeFileSync("velyx.json",JSON.stringify(r,null,2)+`
14
+ `,"utf8");}function we(){return S.existsSync("velyx.json")||(o.error("Velyx configuration not found."),process.exit(1)),JSON.parse(S.readFileSync("velyx.json","utf8"))}var $={version:"2.0.0"};var L=class{constructor(e){this.fileSystem=e;}validateEnvironment(){if(!ce())throw new Error("No Laravel project detected");let e=le();if(!e||!pe(e))throw new Error("Tailwind CSS v4 was not detected");let t=me(),n=V(),s=de(),i=ue(),a=s?H(s.content):false;return {isLaravel:true,hasTailwindV4:true,hasAlpine:t,detectedPackageManager:n,cssFile:s,jsFile:i,canInjectCss:a}}displayEnvironmentInfo(e){e.hasAlpine?o.success("Alpine.js detected - components will be fully interactive"):(o.warn("Alpine.js not detected"),o.log(`Install Alpine.js: ${e.detectedPackageManager} install alpinejs`)),e.cssFile?e.canInjectCss||(o.warn("Tailwind import not found in CSS"),o.log("Velyx styles will not be auto-imported")):(o.warn("No main CSS file found"),o.log("Styles will be created but not auto-imported")),e.jsFile||(o.warn("No main JS file found"),o.log("Component scripts will not be auto-imported"));}async createComponentsDirectory(e="resources/views/components/ui"){await this.fileSystem.ensureDir(e);}async createThemeFile(e,t="resources/css/velyx.css"){let n=t.split("/").slice(0,-1).join("/");if(await this.fileSystem.ensureDir(n),S.existsSync(t))o.info("velyx.css already exists");else try{xe(e,t),o.success("Velyx theme created"),o.info(t);}catch(s){throw new Error(`Failed to create theme file: ${s.message}`)}}async injectStylesImport(e){fe(e),o.success("Velyx styles imported"),o.info(e);}async generateConfig(e,t){let n={version:$.version,theme:e.theme,packageManager:e.packageManager,css:{entry:t.cssFile?.path??"",velyx:"resources/css/velyx.css"},js:{entry:t.jsFile?.path??""},components:{path:"resources/views/components/ui"}};ve(n),o.success("velyx.json config generated");}displaySummary(e,t,n){console.log(`
15
+ ---`),o.success("Laravel project detected"),o.success("Tailwind CSS v4 detected"),o.success(`Theme selected: ${e.theme}`),o.success(`Package manager: ${e.packageManager}`),o.success("UI components directory ready"),t.jsFile&&o.success("Main JS file detected"),o.success(n?"Styles import complete":"Styles import pending"),o.success("velyx.json created"),console.log(`
16
16
  Next steps:`),console.log(" velyx add button"),console.log(`
17
- \u{1F4A1} Want to customize your Tailwind palette? Try https://tweakcn.com/ \u2014 a visual generator for Tailwind-compatible color scales.`);}};var y={start(r){return Ze(r).start()},async withTask(r,e,t,n){let o=this.start(r);try{let i=await e();return t?o.succeed(t):o.stop(),i}catch(i){throw o.fail(n||"Operation failed"),i}}};var tt=promisify(exec);async function rt(r){try{let e=b.resolve(r,"composer.json"),t=b.resolve(r,"package.json");if(!w.existsSync(e))return null;let n=await w.readJson(e);if(!(n.require?.["laravel/framework"]||n.require?.["illuminate/foundation"]))return null;let i=process.cwd();process.chdir(r);let a=D();console.log(`Detected package manager: ${a}`),process.chdir(i);let l={name:n.name||b.basename(r),framework:{name:"laravel",label:"Laravel",version:n.require?.["laravel/framework"]||"unknown"},hasAlpine:!1,hasVite:!1,packageManager:a,paths:{views:"resources/views",assets:"resources/js",public:"public",config:"config"}};if(w.existsSync(t)){let g=await w.readJson(t);l.hasAlpine=!!(g.dependencies?.alpinejs||g.devDependencies?.alpinejs),l.hasVite=!!g.devDependencies?.vite;}let c=b.resolve(r,"resources/views"),d=b.resolve(r,"resources/js");return w.existsSync(c)&&(l.paths.views="resources/views"),w.existsSync(d)&&(l.paths.assets="resources/js"),l}catch{return null}}async function Ce(r){let e={};if(!w.existsSync(r.cwd))return e.MISSING_DIR=true,{errors:e,projectInfo:null};let t=y.start("Checking project environment..."),n=b.resolve(r.cwd,"velyx.json");if(w.existsSync(n)&&!r.force){t.fail(),s.break();let{action:l}=await Se({type:"select",name:"action",message:`A ${m.info("velyx.json")} file already exists. What would you like to do?`,choices:[{title:"Re-initialize Velyx configuration",value:"reinit"},{title:"Keep existing configuration",value:"keep"},{title:"Exit",value:"exit"}],initial:0});l==="exit"&&(s.log("Operation cancelled."),process.exit(0)),l==="keep"&&(s.log("Keeping existing configuration."),process.exit(0)),s.log("Re-initializing Velyx configuration...");}let o=await rt(r.cwd);(!o||o.framework.name!=="laravel")&&(e.UNSUPPORTED_PROJECT=true,t.fail(),s.break(),s.error(`We could not detect a supported Laravel project at ${m.info(r.cwd)}.
18
- Velyx is designed to work with Laravel projects.`),s.break(),process.exit(1)),t.succeed(`Found ${m.info(o.framework.label)} project`);let i=y.start("Checking Alpine.js...");if(o.hasAlpine)i.succeed("Alpine.js found");else {i.fail(),s.break(),s.warn("Alpine.js is required but not found in your project.");let{installAlpine:l}=await Se({type:"confirm",name:"installAlpine",message:"Would you like to install Alpine.js now?",initial:true});if(l){let c=o.packageManager,d=y.start(`Installing Alpine.js with ${c}...`);try{await tt(`${c} install alpinejs`,{cwd:r.cwd}),d.succeed("Alpine.js installed successfully"),o.hasAlpine=!0;}catch(g){d.fail(`Failed to install Alpine.js: ${g.message}`),s.error(`Please install Alpine.js manually: ${m.info(`${c} install alpinejs`)}`),s.break(),process.exit(1);}}else {let c=o.packageManager;s.error(`Alpine.js is required. Install it with: ${m.info(`${c} install alpinejs`)}`),s.break(),process.exit(1);}}let a=y.start("Checking build tools...");return o.hasVite?a.succeed("Vite found"):(s.warn("Vite not found. Using Vite is recommended for better development experience."),a.warn("Vite not found (but optional)")),Object.keys(e).length>0&&(s.break(),process.exit(1)),{errors:e,projectInfo:o}}var ke=z$1.object({baseColor:z$1.string().optional(),yes:z$1.boolean(),defaults:z$1.boolean(),force:z$1.boolean(),cwd:z$1.string(),silent:z$1.boolean()});async function nt(){let r=A();r.length===0&&(s.error("No base colors available."),process.exit(1));let{theme:e}=await Se({type:"select",name:"theme",message:"Choose a base color theme",choices:r.map(t=>({title:t.label,value:t.name}))},{onCancel:()=>{s.error("Theme selection aborted"),process.exit(1);}});return e}async function ot(){let{shouldImport:r}=await Se({type:"confirm",name:"shouldImport",message:"Import Velyx styles into your main CSS file?",initial:true},{onCancel:()=>false});return !!r}function st(r){if(!r.baseColor)return;let t=A().find(n=>n.name===r.baseColor);if(t)return t.name;s.warn(`Unknown base color "${r.baseColor}".`);}async function Ee(r,e){e||(e=(await Ce(r)).projectInfo),process.chdir(r.cwd);let t=new u,n=new L(t);try{let o=n.validateEnvironment();n.displayEnvironmentInfo(o);let i=e.packageManager,a=A(),l=a.find(g=>g.name==="neutral")?.name??a[0]?.name,c=st(r);c||(c=r.defaults&&l?l:await nt()),c||(s.error("No base color available."),process.exit(1)),await n.createComponentsDirectory(),await n.createThemeFile(c);let d=!1;o.cssFile&&o.canInjectCss&&(r.defaults||await ot())&&(await n.injectStylesImport(o.cssFile.path),d=!0),await n.generateConfig({packageManager:i,theme:c,importStyles:d},o),n.displaySummary({packageManager:i,theme:c,importStyles:d},o,d);}catch(o){s.error(o.message),o instanceof Error&&(o.message.includes("Laravel project")?s.log("Run velyx init at the root of a Laravel project"):o.message.includes("Tailwind")&&s.log(`Velyx requires ${m.info("Tailwind CSS v4+")}`)),process.exit(1);}}process.on("exit",r=>{let e=b.resolve(process.cwd(),"velyx.json");return r===0?T(e):N(e)});var Fe=new Command().name("init").description("initialize your project and install dependencies").option("-b, --base-color <base-color>","the base color to use. (neutral, gray, zinc, stone, slate)",void 0).option("-y, --yes","skip confirmation prompt.",true).option("-d, --defaults","use default configuration.",false).option("-f, --force","force overwrite of existing configuration.",false).option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("-s, --silent","mute output.",false).action(async r=>{let e=ke.parse({baseColor:r.baseColor,yes:!!r.yes,defaults:!!r.defaults,force:!!r.force,cwd:b.resolve(r.cwd),silent:!!r.silent});await Ee(e);});var Q=class extends Error{constructor(t,n,o){super(t);this.code=n;this.context=o;this.name="VelyxError";}},E=class{handle(e,t){e instanceof Q?(console.error(`[${e.code}] ${e.message}`),e.context&&console.error("Context:",e.context)):console.error(`Unexpected error in ${t}: ${e.message}`);}};var at={UNKNOWN_ERROR:"UNKNOWN_ERROR"},U=class extends Error{code;statusCode;context;suggestion;timestamp;cause;constructor(e,t={}){super(e),this.name="RegistryError",this.code=t.code||at.UNKNOWN_ERROR,this.statusCode=t.statusCode,this.cause=t.cause,this.context=t.context,this.suggestion=t.suggestion,this.timestamp=new Date,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}toJSON(){return {name:this.name,message:this.message,code:this.code,statusCode:this.statusCode,context:this.context,suggestion:this.suggestion,timestamp:this.timestamp,stack:this.stack}}};function ee(r){if(s.break(),s.error("Something went wrong. Please check the error below for more details."),s.error("If the problem persists, please open an issue on GitHub."),s.error(""),typeof r=="string"&&(s.error(r),s.break(),process.exit(1)),r instanceof U&&(r.message&&(s.error(r.cause?"Error:":"Message:"),s.error(r.message)),r.cause&&(s.error(`
19
- Message:`),s.error(r.cause)),r.suggestion&&(s.error(`
20
- Suggestion:`),s.error(r.suggestion)),s.break(),process.exit(1)),r instanceof z$1.ZodError){s.error("Validation failed:");for(let[e,t]of Object.entries(r.flatten().fieldErrors))s.error(`- ${m.info(e)}: ${t}`);s.break(),process.exit(1);}r instanceof Error&&(s.error(r.message),s.break(),process.exit(1)),s.break(),process.exit(1);}var I=class{config;async load(){try{return this.config=be(),this.config||(s.error(""),ee(new Error("Configuration not found")),process.exit(1)),this.config}catch{s.error(""),ee(new Error("Something went wrong. Please try again.")),process.exit(1);}}getPackageManager(){if(!this.config)throw new Error("Configuration not loaded");return this.config.packageManager||"npm"}validate(){return !!this.config}getComponentsPath(){if(!this.config)throw new Error("Configuration not loaded");return this.config.components.path}getThemePath(){if(!this.config)throw new Error("Configuration not loaded");return this.config.css.velyx}getJsEntryPath(){if(!this.config)throw new Error("Configuration not loaded");return this.config.js?.entry??""}getTheme(){if(!this.config)throw new Error("Configuration not loaded");return this.config.theme}};var J=promisify(exec);function mt(r){return r.startsWith("@")?r:r.replace("@",":")}var q=class{fileSystem;constructor(e){this.fileSystem=e??new u;}async installDependencies(e,t){let n=[],o=[];e.npm&&e.npm.length>0&&n.push(this.installNpmDependencies(e.npm,t)),e.composer&&e.composer.length>0&&o.push(this.installComposerDependencies(e.composer)),await Promise.allSettled([...n,...o]);}async installNpmDependencies(e,t){if(!this.fileSystem.fileExists("package.json")){s.warn("No package.json found, skipping npm dependencies");return}let n=await this.filterMissingNpmDependencies(e);if(n.length===0){s.info("All npm dependencies already installed");return}let o=this.getNpmInstallCommand(t,n);try{s.info(`Installing npm dependencies: ${n.join(", ")}`);let{stdout:i,stderr:a}=await J(o,{cwd:process.cwd(),timeout:12e4});i&&process.env.NODE_ENV!=="test"&&console.log(i),a&&!a.includes("WARN")&&s.warn(`npm install warnings: ${a}`),s.success(`Installed ${n.length} npm dependencies`);}catch(i){throw s.error(`Failed to install npm dependencies: ${i.message}`),i}}async installComposerDependencies(e){if(!this.fileSystem.fileExists("composer.json")){s.warn("No composer.json found, skipping composer dependencies");return}let t=e.map(mt),n=await this.filterMissingComposerDependencies(t);if(n.length===0){s.info("All composer dependencies already installed");return}try{s.info(`Installing composer dependencies: ${n.join(", ")}`);let{stdout:o,stderr:i}=await J(`composer require ${n.join(" ")}`,{cwd:process.cwd(),timeout:3e5});o&&process.env.NODE_ENV!=="test"&&console.log(o),i&&s.warn(`composer require warnings: ${i}`),s.success(`Installed ${n.length} composer dependencies`);}catch(o){throw s.error(`Failed to install composer dependencies: ${o.message}`),o}}getNpmInstallCommand(e,t){switch(e){case "pnpm":return `pnpm add ${t.join(" ")}`;case "yarn":return `yarn add ${t.join(" ")}`;case "bun":return `bun add ${t.join(" ")}`;default:return `npm install ${t.join(" ")}`}}async filterMissingNpmDependencies(e){try{let{stdout:t}=await J("npm list --json --depth=0",{cwd:process.cwd(),timeout:3e4}),n=JSON.parse(t),o=Object.keys({...n.dependencies,...n.devDependencies});return e.filter(i=>{let a=i.split("@")[0];return !o.includes(a)})}catch{return e}}async filterMissingComposerDependencies(e){try{let{stdout:t}=await J("composer show --installed --format=json",{cwd:process.cwd(),timeout:3e4}),o=JSON.parse(t).installed.map(i=>i.name);return e.filter(i=>{let a=i.split(":")[0];return !o.includes(a)})}catch{return e}}};function ft(r){return r.endsWith(".blade.php")?"blade":r.endsWith(".js")?"js":r.endsWith(".css")?"css":null}var B=class{constructor(e,t,n){this.registryService=e;this.configManager=n;if(this.fileSystem=t??new u,this.dependencyService=new q(this.fileSystem),!this.configManager)throw new Error("ConfigManager is required")}fileSystem;dependencyService;async addComponents(e){let t={added:[],skipped:[],failed:[]};for(let n of e)try{let o=await this.addComponent(n);t.added.push(...o.added),t.skipped.push(...o.skipped),t.failed.push(...o.failed);}catch(o){t.failed.push({name:n,error:o.message});}return t}async addComponent(e){let t={added:[],skipped:[],failed:[]},n=await this.registryService.fetchComponent(e,{includeFiles:true});await this.registryService.resolveDependencies(n);let o=this.buildDependencies(n);if(o){let l=this.configManager.getPackageManager();try{await this.dependencyService.installDependencies(o,l);}catch(c){s.warn(`Failed to install dependencies for ${e}: ${c.message}`);}}let i=[],a=await this.fetchComponentWithFiles(e);for(let[l,c]of Object.entries(a.files)){let d=this.getDestinationPath(l),g=ft(l),se=await this.fileSystem.fileExists(d);if(se){let ie=await this.handleFileConflict(l);if(ie==="skip"){t.skipped.push(`${e}/${l}`);continue}else ie==="cancel"&&(s.error("Cancelled."),process.exit(0));}i.push({componentName:e,filePath:l,fileType:g,destPath:d,content:c,existedBefore:se});}if(i.length>0)try{await this.applyFileBatch(i),i.forEach(c=>t.added.push(`${c.componentName}/${c.filePath}`));let l=new Set(i.filter(c=>c.fileType==="js").map(c=>c.componentName));for(let c of Array.from(l))await this.autoImportJs(c);}catch(l){i.forEach(c=>t.failed.push({name:`${c.componentName}/${c.filePath}`,error:l.message}));}return t}buildDependencies(e){let t={};return e.requires&&e.requires.length>0&&(t.composer=[...e.requires]),e.requires_alpine&&(t.npm=["alpinejs"]),Object.keys(t).length>0?t:null}async fetchComponentWithFiles(e){let t=await this.registryService.fetchComponent(e,{includeFiles:true});return "files"in t?t:{files:{}}}async autoImportJs(e){try{let t=this.configManager?.getJsEntryPath();if(!t||!await this.fileSystem.fileExists(t))return;let n=`./ui/${e}`;ye(t,e,n),s.success(`Auto-imported ${e} into ${t}`);}catch(t){s.warn(`Failed to auto-import JS for ${e}: ${t.message}`);}}getDestinationPath(e){return e}async handleFileConflict(e){let{action:t}=await Se({type:"select",name:"action",message:`File "${e}" already exists. What do you want to do?`,choices:[{title:"Skip",value:"skip"},{title:"Overwrite",value:"overwrite"},{title:"Cancel",value:"cancel"}],initial:0},{onCancel:()=>{s.error("Cancelled."),process.exit(0);}});return t}async applyFileBatch(e){let t=[],n=[];try{for(let o of e){let i=`${o.destPath}.velyx-tmp`;await this.fileSystem.writeFile(i,o.content),t.push(i);}for(let o of e){if(!o.existedBefore)continue;if(!ae(o.destPath))throw new Error(`Failed to create backup for ${o.destPath}`);n.push(o.destPath);}for(let o of e){let i=`${o.destPath}.velyx-tmp`;await w.move(i,o.destPath,{overwrite:!0});}n.forEach(o=>T(o));}catch(o){for(let i of e)await this.fileSystem.fileExists(i.destPath)&&await w.remove(i.destPath),i.existedBefore&&N(i.destPath);for(let i of t)await this.fileSystem.fileExists(i)&&await w.remove(i);throw o}}};var W=class{constructor(e,t,n){this.registryService=e;this.configManager=t;this.componentService=n??new B(e,new u,t);}componentService;validateInitialization(){if(!this.configManager.validate())throw new Error("Velyx is not initialized")}validateComponents(e,t){for(let n of e)if(!t.components.find(i=>i.name===n))throw new Error(`Component "${n}" not found`)}async getAvailableComponents(){return await this.registryService.fetchRegistry()}async addComponents(e){return await this.componentService.addComponents(e)}displayResults(e){e.added.forEach(t=>s.success(`Added ${t}`)),e.skipped.forEach(t=>s.warn(`Skipped ${t}`)),e.failed.forEach(({name:t,error:n})=>s.error(`Failed to add ${t}: ${n}`));}displayNextSteps(e){e.added.length!==0&&console.log(`
21
- \u{1F389} Happy coding! Enjoy building beautiful components!`);}};var G=class extends Error{constructor(t,n){super(t);this.cause=n;this.name="RegistryError";}},p=class extends G{constructor(e,t){super(e,t),this.name="NetworkError";}},h=class extends G{constructor(e,t){super(`Component "${e}" not found`,t),this.name="ComponentNotFoundError";}};var x={maxRetries:3,initialDelay:1e3,backoffFactor:2,maxDelay:1e4,retryableStatusCodes:[408,429,500,502,503,504],timeout:3e4,headers:{}};function re(r){return new Promise(e=>setTimeout(e,r))}function ne(r,e,t,n){let o=e*Math.pow(t,r);return Math.min(o,n)}function ut(r,e){return e.includes(r)}async function gt(r,e){let{timeout:t=x.timeout,headers:n={}}=e,o=new AbortController,i=setTimeout(()=>o.abort(),t);try{return await fetch(r,{signal:o.signal,headers:{"User-Agent":"Velyx-CLI",...n}})}catch(a){throw a instanceof Error&&a.name==="AbortError"?new p(`Request timeout after ${t}ms for ${r}`,a):a}finally{clearTimeout(i);}}var z=class{async fetch(e,t={}){let n={maxRetries:t.maxRetries??x.maxRetries,initialDelay:t.initialDelay??x.initialDelay,backoffFactor:t.backoffFactor??x.backoffFactor,maxDelay:t.maxDelay??x.maxDelay,retryableStatusCodes:t.retryableStatusCodes??x.retryableStatusCodes,timeout:t.timeout??x.timeout,headers:t.headers??x.headers},o=null;for(let i=0;i<=n.maxRetries;i++)try{let a=await gt(e,{...t,timeout:n.timeout,headers:n.headers});if(a.ok||!ut(a.status,n.retryableStatusCodes))return a;if(console.log("Attempt: ",i),i===n.maxRetries)throw new p(`Request failed after ${n.maxRetries+1} attempts: ${a.status} ${a.statusText}`);let l=ne(i,n.initialDelay,n.backoffFactor,n.maxDelay);await re(l);}catch(a){if(o=a,a instanceof p&&a.message.includes("timeout")){if(i===n.maxRetries)throw a;let c=ne(i,n.initialDelay,n.backoffFactor,n.maxDelay);await re(c);continue}if(i===n.maxRetries)throw o instanceof p?o:new p(`Request failed after ${n.maxRetries+1} attempts: ${o.message}`,o);let l=ne(i,n.initialDelay,n.backoffFactor,n.maxDelay);await re(l);}throw new p(`Request failed after ${n.maxRetries+1} attempts: ${o?.message??"Unknown error"}`,o??void 0)}async fetchJson(e,t){let n=await this.fetch(e,t);if(!n.ok)throw new p(`Failed to fetch JSON from ${e}: ${n.status} ${n.statusText}`);try{return await n.json()}catch(o){throw new p(`Failed to parse JSON from ${e}: ${o.message}`,o)}}async fetchText(e,t){let n=await this.fetch(e,t);if(!n.ok)throw new p(`Failed to fetch text from ${e}: ${n.status} ${n.statusText}`);try{return await n.text()}catch(o){throw new p(`Failed to read text from ${e}: ${o.message}`,o)}}};var je=()=>process.env.VELYX_REGISTRY_URL?process.env.VELYX_REGISTRY_URL.replace(/\/$/,""):"http://velyx.test/api/v1";var Y=class{httpService;baseUrl;constructor(e){this.httpService=e??new z,this.baseUrl=je();}async fetchRegistry(){try{let e=await this.httpService.fetch(`${this.baseUrl}/components`);if(!e.ok)throw new p(`Failed to fetch registry: ${e.status} ${e.statusText}`);let t=await this.httpService.fetchJson(`${this.baseUrl}/components`);return {components:Object.values(t.data),count:t.count}}catch(e){throw e instanceof p?e:new p(`Failed to fetch registry: ${e.message}`)}}async fetchComponent(e,t){try{let n=this.buildComponentUrl(e,t),o=await this.httpService.fetch(n);if(o.status===404)throw new h(e);if(!o.ok)throw new p(`Failed to fetch component: ${o.status} ${o.statusText}`);let i=await this.httpService.fetchJson(n);return t?.includeFiles?i.data:this.convertRegistryComponentToMeta(i.data)}catch(n){throw n instanceof h||n instanceof p?n:new p(`Failed to fetch component "${e}": ${n.message}`)}}async fetchFile(e,t){try{let n=e.split("/").pop()||e,o=await this.httpService.fetch(`${this.baseUrl}/components/${n}`);if(o.status===404)throw new h(n);if(!o.ok)throw new p(`Failed to fetch component: ${o.status} ${o.statusText}`);let a=(await this.httpService.fetchJson(`${this.baseUrl}/components/${n}`)).files[t];if(a===void 0)throw new p(`File "${t}" not found in component "${n}"`);return a}catch(n){throw n instanceof h||n instanceof p?n:new p(`Failed to fetch file "${t}": ${n.message}`)}}async resolveDependencies(e){let t=new Set,n=[],o=async i=>{if(!t.has(i.name)&&(t.add(i.name),n.push(i),i.requires&&i.requires.length>0))for(let a of i.requires)try{let l=await this.fetchComponent(a);await o(l);}catch{}};return await o(e),n}convertRegistryComponentToMeta(e){return {name:e.name,description:e.description,latest:e.latest,versions:e.versions,requires_alpine:e.requires_alpine,requires:e.requires,categories:e.categories,laravel:e.laravel}}buildComponentUrl(e,t){let n=new URLSearchParams;t?.version&&n.append("version",t.version),t?.includeFiles&&n.append("include","files");let o=n.toString();return `${this.baseUrl}/components/${e}${o?`?${o}`:""}`}async getComponentVersions(e){try{let t=await this.httpService.fetch(`${this.baseUrl}/components/${e}/versions`);if(t.status===404)throw new h(e);if(!t.ok)throw new p(`Failed to fetch component versions: ${t.status} ${t.statusText}`);return await this.httpService.fetchJson(`${this.baseUrl}/components/${e}/versions`)}catch(t){throw t instanceof h||t instanceof p?t:new p(`Failed to fetch versions for "${e}": ${t.message}`)}}};var F=class{velyxService;constructor(){this.velyxService=new Y;}async fetchRegistry(){return await y.withTask("Fetching registry...",()=>this.velyxService.fetchRegistry(),void 0,"Failed to fetch registry")}async fetchComponent(e,t){let n=t?.includeFiles?`Fetching component "${e}" with files...`:`Fetching component "${e}" metadata...`;return await y.withTask(n,()=>this.velyxService.fetchComponent(e,t),void 0,`Failed to fetch component "${e}"`)}async resolveDependencies(e){return await y.withTask("Resolving dependencies...",()=>this.velyxService.resolveDependencies(e),void 0,"Failed to resolve dependencies")}};async function ht(r,e){if(r.all)return [...e];if(r.components?.length)return r.components;s.info("Use arrow keys and space to select, then press enter.");let{components:t}=await Se({type:"multiselect",name:"components",message:"Which components would you like to add?",hint:"Space to select. A to toggle all. Enter to submit.",instructions:false,choices:e.map(o=>({title:o,value:o,selected:r.all?true:r.components?.includes(o)}))});t?.length||(s.warn("No components selected. Exiting."),s.info(""),process.exit(1));let n=z$1.array(z$1.string()).safeParse(t);return n.success||(s.error("Something went wrong. Please try again."),process.exit(1)),n.data}async function Oe(r){let e=new I;await e.load();let t=new F,n=new W(t,e);try{n.validateInitialization();}catch{s.error("Velyx is not initialized"),s.log("Run velyx init first"),process.exit(1);}let o=await n.getAvailableComponents(),i=o.components.map(c=>c.name).sort((c,d)=>c.localeCompare(d)),a=await ht(r,i);try{n.validateComponents(a,o);}catch(c){s.error(c.message),s.log("Run velyx list to see available components"),process.exit(1);}let l=await n.addComponents(a);n.displayResults(l),n.displayNextSteps(l);}var vt=z$1.object({components:z$1.array(z$1.string()).optional(),yes:z$1.boolean(),overwrite:z$1.boolean(),cwd:z$1.string(),all:z$1.boolean(),path:z$1.string().optional(),silent:z$1.boolean(),srcDir:z$1.boolean().optional(),cssVariables:z$1.boolean().optional()}),Pe=new Command().name("add").argument("[components...]","Names of components to add").option("-y, --yes","skip confirmation prompt.",false).option("-o, --overwrite","overwrite existing files.",false).option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("-a, --all","add all available components",false).option("-p, --path <path>","the path to add the component to.").option("-s, --silent","mute output.",false).option("--src-dir","use the src directory when creating a new project.",false).option("--no-src-dir","do not use the src directory when creating a new project.").option("--css-variables","use CSS variables for theming.",true).option("--no-css-variables","do not use CSS variables for theming.").description("Add one or more UI components to your Laravel project").action(async(r,e)=>{let t=new E;try{let n={components:r,cwd:b.resolve(e.cwd),...e,cssVariables:e.cssVariables??!0},o=vt.parse(n);await Oe(o);}catch(n){t.handle(n,"add command"),process.exit(1);}});function St(r,e){if(!e)return [...r];let t=e.toLowerCase();return r.filter(n=>{let o=n.name.toLowerCase().includes(t),i=n.description?n.description.toLowerCase().includes(t):false,a=n.categories?n.categories.some(l=>l.toLowerCase().includes(t)):false;return o||i||a})}function Ct(r,e,t){let n=Math.max(0,e??0);return t===void 0?r.slice(n):r.slice(n,n+Math.max(0,t))}async function Ne(r){let n=[...(await new F().fetchRegistry()).components].sort((l,c)=>l.name.localeCompare(c.name)),o=St(n,r.query),i=Ct(o,r.offset,r.limit);if(r.json){console.log(JSON.stringify({total:o.length,count:i.length,offset:r.offset??0,limit:r.limit??null,components:i},null,2));return}if(i.length===0){s.warn("No components found.");return}console.log(v.bold(`
22
- Available components:`)),console.log("");let a=new bt({head:[v.bold("Component"),v.bold("Description"),v.bold("Categories")],colWidths:[24,50,24],wordWrap:true,style:{head:[],border:[]}});for(let l of i)a.push([v.cyan(l.name),v.white(l.description||"No description"),v.gray(l.categories?.join(", ")||"-")]);console.log(a.toString()),console.log(""),s.info(`Run ${v.green("velyx add <component>")} to add one.`);}var Et=z$1.object({cwd:z$1.string(),query:z$1.string().optional(),limit:z$1.number().optional(),offset:z$1.number().optional(),json:z$1.boolean()}),Te=new Command().name("list").alias("search").description("List or search components from the registry").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("-q, --query <query>","query string").option("-l, --limit <number>","maximum number of items to display",void 0).option("-o, --offset <number>","number of items to skip",void 0).option("--json","output JSON",false).action(async r=>{let e=new E;try{let t=Et.parse({cwd:b.resolve(r.cwd),query:r.query,limit:r.limit?Number.parseInt(r.limit,10):void 0,offset:r.offset?Number.parseInt(r.offset,10):void 0,json:!!r.json});process.chdir(t.cwd);let n=new I;try{await n.load();}catch{s.error("Velyx is not initialized"),s.log("Run velyx init first"),process.exit(1);}await Ne(t);}catch(t){e.handle(t,"list command"),process.exit(1);}});function Ft(){console.log(""),console.log(v.bold.cyan(` \u25BC VELYX CLI v${P.version}`)),console.log(v.gray(" Tailwind CSS v4+ components for Laravel")),console.log("");}var oe=new Command;oe.name("velyx").description("Velyx CLI: Copy UI components into your Laravel project").version(P.version,"-v, --version","display the version number").hook("preAction",()=>{Ft();});oe.addCommand(Pe).addCommand(Fe).addCommand(Te);oe.parse(process.argv);//# sourceMappingURL=index.js.map
17
+ \u{1F4A1} Want to customize your Tailwind palette? Try https://tweakcn.com/ \u2014 a visual generator for Tailwind-compatible color scales.`);}};var g={start(r){return tt(r).start()},async withTask(r,e,t,n){let s=this.start(r);try{let i=await e();return t?s.succeed(t):s.stop(),i}catch(i){throw s.fail(n||"Operation failed"),i}}};var st=promisify(exec);async function ot(r){try{let e=w.resolve(r,"composer.json"),t=w.resolve(r,"package.json");if(!h.existsSync(e))return null;let n=await h.readJson(e);if(!(n.require?.["laravel/framework"]||n.require?.["illuminate/foundation"]))return null;let i=process.cwd();process.chdir(r);let a=V();console.log(`Detected package manager: ${a}`),process.chdir(i);let c={name:n.name||w.basename(r),framework:{name:"laravel",label:"Laravel",version:n.require?.["laravel/framework"]||"unknown"},hasAlpine:!1,hasVite:!1,packageManager:a,paths:{views:"resources/views",assets:"resources/js",public:"public",config:"config"}};if(h.existsSync(t)){let u=await h.readJson(t);c.hasAlpine=!!(u.dependencies?.alpinejs||u.devDependencies?.alpinejs),c.hasVite=!!u.devDependencies?.vite;}let l=w.resolve(r,"resources/views"),m=w.resolve(r,"resources/js");return h.existsSync(l)&&(c.paths.views="resources/views"),h.existsSync(m)&&(c.paths.assets="resources/js"),c}catch{return null}}async function Se(r){let e={};if(!h.existsSync(r.cwd))return e.MISSING_DIR=true,{errors:e,projectInfo:null};let t=g.start("Checking project environment..."),n=w.resolve(r.cwd,"velyx.json");if(h.existsSync(n)&&!r.force){t.fail(),o.break();let{action:c}=await be({type:"select",name:"action",message:`A ${d.info("velyx.json")} file already exists. What would you like to do?`,choices:[{title:"Re-initialize Velyx configuration",value:"reinit"},{title:"Keep existing configuration",value:"keep"},{title:"Exit",value:"exit"}],initial:0});c==="exit"&&(o.log("Operation cancelled."),process.exit(0)),c==="keep"&&(o.log("Keeping existing configuration."),process.exit(0)),o.log("Re-initializing Velyx configuration...");}let s=await ot(r.cwd);(!s||s.framework.name!=="laravel")&&(e.UNSUPPORTED_PROJECT=true,t.fail(),o.break(),o.error(`We could not detect a supported Laravel project at ${d.info(r.cwd)}.
18
+ Velyx is designed to work with Laravel projects.`),o.break(),process.exit(1)),t.succeed(`Found ${d.info(s.framework.label)} project`);let i=g.start("Checking Alpine.js...");if(s.hasAlpine)i.succeed("Alpine.js found");else {i.fail(),o.break(),o.warn("Alpine.js is required but not found in your project.");let{installAlpine:c}=await be({type:"confirm",name:"installAlpine",message:"Would you like to install Alpine.js now?",initial:true});if(c){let l=s.packageManager,m=g.start(`Installing Alpine.js with ${l}...`);try{await st(`${l} install alpinejs`,{cwd:r.cwd}),m.succeed("Alpine.js installed successfully"),s.hasAlpine=!0;}catch(u){m.fail(`Failed to install Alpine.js: ${u.message}`),o.error(`Please install Alpine.js manually: ${d.info(`${l} install alpinejs`)}`),o.break(),process.exit(1);}}else {let l=s.packageManager;o.error(`Alpine.js is required. Install it with: ${d.info(`${l} install alpinejs`)}`),o.break(),process.exit(1);}}let a=g.start("Checking build tools...");return s.hasVite?a.succeed("Vite found"):(o.warn("Vite not found. Using Vite is recommended for better development experience."),a.warn("Vite not found (but optional)")),Object.keys(e).length>0&&(o.break(),process.exit(1)),{errors:e,projectInfo:s}}var Ce=z$1.object({baseColor:z$1.string().optional(),defaults:z$1.boolean(),force:z$1.boolean(),cwd:z$1.string()});async function it(){let r=A();r.length===0&&(o.error("No base colors available."),process.exit(1));let{theme:e}=await be({type:"select",name:"theme",message:"Choose a base color theme",choices:r.map(t=>({title:t.label,value:t.name}))},{onCancel:()=>{o.error("Theme selection aborted"),process.exit(1);}});return e}async function at(){let{shouldImport:r}=await be({type:"confirm",name:"shouldImport",message:"Import Velyx styles into your main CSS file?",initial:true},{onCancel:()=>false});return !!r}function ct(r){if(!r.baseColor)return;let t=A().find(n=>n.name===r.baseColor);if(t)return t.name;o.warn(`Unknown base color "${r.baseColor}".`);}async function ke(r,e){e||(e=(await Se(r)).projectInfo),process.chdir(r.cwd);let t=new f,n=new L(t);try{let s=n.validateEnvironment();n.displayEnvironmentInfo(s);let i=e.packageManager,a=A(),c=a.find(u=>u.name==="neutral")?.name??a[0]?.name,l=ct(r);l||(l=r.defaults&&c?c:await it()),l||(o.error("No base color available."),process.exit(1)),await n.createComponentsDirectory(),await n.createThemeFile(l);let m=!1;s.cssFile&&s.canInjectCss&&(r.defaults||await at())&&(await n.injectStylesImport(s.cssFile.path),m=!0),await n.generateConfig({packageManager:i,theme:l,importStyles:m},s),n.displaySummary({packageManager:i,theme:l,importStyles:m},s,m);}catch(s){o.error(s.message),s instanceof Error&&(s.message.includes("Laravel project")?o.log("Run velyx init at the root of a Laravel project"):s.message.includes("Tailwind")&&o.log(`Velyx requires ${d.info("Tailwind CSS v4+")}`)),process.exit(1);}}process.on("exit",r=>{let e=w.resolve(process.cwd(),"velyx.json");return r===0?T(e):N(e)});var Ee=new Command().name("init").description("initialize your project and install dependencies").option("-b, --base-color <base-color>","the base color to use. (neutral, gray, zinc, stone, slate)",void 0).option("-d, --defaults","use default configuration.",false).option("-f, --force","force overwrite of existing configuration.",false).option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).action(async r=>{let e=Ce.parse({baseColor:r.baseColor,defaults:!!r.defaults,force:!!r.force,cwd:w.resolve(r.cwd)});await ke(e);});var X=class extends Error{constructor(t,n,s){super(t);this.code=n;this.context=s;this.name="VelyxError";}},C=class{handle(e,t){e instanceof X?(console.error(`[${e.code}] ${e.message}`),e.context&&console.error("Context:",e.context)):console.error(`Unexpected error in ${t}: ${e.message}`);}};var pt={UNKNOWN_ERROR:"UNKNOWN_ERROR"},U=class extends Error{code;statusCode;context;suggestion;timestamp;cause;constructor(e,t={}){super(e),this.name="RegistryError",this.code=t.code||pt.UNKNOWN_ERROR,this.statusCode=t.statusCode,this.cause=t.cause,this.context=t.context,this.suggestion=t.suggestion,this.timestamp=new Date,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);}toJSON(){return {name:this.name,message:this.message,code:this.code,statusCode:this.statusCode,context:this.context,suggestion:this.suggestion,timestamp:this.timestamp,stack:this.stack}}};function Q(r){if(o.break(),o.error("Something went wrong. Please check the error below for more details."),o.error("If the problem persists, please open an issue on GitHub."),o.error(""),typeof r=="string"&&(o.error(r),o.break(),process.exit(1)),r instanceof U&&(r.message&&(o.error(r.cause?"Error:":"Message:"),o.error(r.message)),r.cause&&(o.error(`
19
+ Message:`),o.error(r.cause)),r.suggestion&&(o.error(`
20
+ Suggestion:`),o.error(r.suggestion)),o.break(),process.exit(1)),r instanceof z$1.ZodError){o.error("Validation failed:");for(let[e,t]of Object.entries(r.flatten().fieldErrors))o.error(`- ${d.info(e)}: ${t}`);o.break(),process.exit(1);}r instanceof Error&&(o.error(r.message),o.break(),process.exit(1)),o.break(),process.exit(1);}var k=class{config;async load(){try{return this.config=we(),this.config||(o.error(""),Q(new Error("Configuration not found")),process.exit(1)),this.config}catch{o.error(""),Q(new Error("Something went wrong. Please try again.")),process.exit(1);}}getPackageManager(){if(!this.config)throw new Error("Configuration not loaded");return this.config.packageManager||"npm"}validate(){return !!this.config}getComponentsPath(){if(!this.config)throw new Error("Configuration not loaded");return this.config.components.path}getThemePath(){if(!this.config)throw new Error("Configuration not loaded");return this.config.css.velyx}getJsEntryPath(){if(!this.config)throw new Error("Configuration not loaded");return this.config.js?.entry??""}getTheme(){if(!this.config)throw new Error("Configuration not loaded");return this.config.theme}};var Fe=promisify(exec);function gt(r){if(r.startsWith("@")){let t=r.lastIndexOf("@");return t>r.indexOf("/")?{name:r.slice(0,t),version:r.slice(t+1)}:{name:r,version:null}}let e=r.lastIndexOf("@");return e>0?{name:r.slice(0,e),version:r.slice(e+1)}:{name:r,version:null}}function $e(r){let e=r.indexOf(":");if(e>0)return {name:r.slice(0,e),version:r.slice(e+1)};let t=r.lastIndexOf("@");return t>0?{name:r.slice(0,t),version:r.slice(t+1)}:{name:r,version:null}}function yt(r){let e=$e(r);return e.version?`${e.name}:${e.version}`:e.name}function je(r){try{return JSON.parse(readFileSync(r,"utf8"))}catch{return null}}var J=class{fileSystem;constructor(e){this.fileSystem=e??new f;}async installDependencies(e,t){let n=[],s=[];e.npm&&e.npm.length>0&&n.push(this.installNpmDependencies(e.npm,t)),e.composer&&e.composer.length>0&&s.push(this.installComposerDependencies(e.composer)),await Promise.allSettled([...n,...s]);}async installNpmDependencies(e,t){if(!await this.fileSystem.fileExists("package.json")){o.warn("No package.json found, skipping npm dependencies");return}let n=await this.filterMissingNpmDependencies(e);if(n.length===0){o.info("All npm dependencies already installed");return}let s=this.getNpmInstallCommand(t,n);try{o.info(`Installing npm dependencies: ${n.join(", ")}`);let{stdout:i,stderr:a}=await Fe(s,{cwd:process.cwd(),timeout:12e4});i&&process.env.NODE_ENV!=="test"&&console.log(i),a&&!a.includes("WARN")&&o.warn(`npm install warnings: ${a}`),o.success(`Installed ${n.length} npm dependencies`);}catch(i){throw o.error(`Failed to install npm dependencies: ${i.message}`),i}}async installComposerDependencies(e){if(!await this.fileSystem.fileExists("composer.json")){o.warn("No composer.json found, skipping composer dependencies");return}let t=await this.filterMissingComposerDependencies(e);if(t.length===0){o.info("All composer dependencies already installed");return}let n=t.map(yt);try{o.info(`Installing composer dependencies: ${n.join(", ")}`);let{stdout:s,stderr:i}=await Fe(`composer require ${n.join(" ")}`,{cwd:process.cwd(),timeout:3e5});s&&process.env.NODE_ENV!=="test"&&console.log(s),i&&o.warn(`composer require warnings: ${i}`),o.success(`Installed ${t.length} composer dependencies`);}catch(s){throw o.error(`Failed to install composer dependencies: ${s.message}`),s}}getNpmInstallCommand(e,t){switch(e){case "pnpm":return `pnpm add ${t.join(" ")}`;case "yarn":return `yarn add ${t.join(" ")}`;case "bun":return `bun add ${t.join(" ")}`;default:return `npm install ${t.join(" ")}`}}async filterMissingNpmDependencies(e){let t=je("package.json");if(!t)return [...e];let n={...t.dependencies,...t.devDependencies};return e.filter(s=>{let i=gt(s),a=n[i.name];return a?i.version?a!==i.version:false:true})}async filterMissingComposerDependencies(e){let t=je("composer.json");if(!t)return [...e];let n={...t.require,...t["require-dev"]};return e.filter(s=>{let i=$e(s),a=n[i.name];return a?i.version?a!==i.version:false:true})}};function xt(r){return r.endsWith(".blade.php")?"blade":r.endsWith(".js")?"js":r.endsWith(".css")?"css":null}var q=class{constructor(e,t,n){this.registryService=e;this.configManager=n;if(this.fileSystem=t??new f,this.dependencyService=new J(this.fileSystem),!this.configManager)throw new Error("ConfigManager is required")}fileSystem;dependencyService;async addComponents(e){let t={added:[],skipped:[],failed:[]};for(let n of e)try{let s=await this.addComponent(n);t.added.push(...s.added),t.skipped.push(...s.skipped),t.failed.push(...s.failed);}catch(s){t.failed.push({name:n,error:s.message});}return t}async addComponent(e){let t={added:[],skipped:[],failed:[]},n=await this.registryService.fetchComponent(e,{includeFiles:true});await this.registryService.resolveDependencies(n);let s=this.buildDependencies(n);if(s){let c=this.configManager.getPackageManager();try{await this.dependencyService.installDependencies(s,c);}catch(l){o.warn(`Failed to install dependencies for ${e}: ${l.message}`);}}let i=[],a=await this.fetchComponentWithFiles(e);for(let[c,l]of Object.entries(a.files)){let m=this.getDestinationPath(c),u=xt(c),se=await this.fileSystem.fileExists(m);if(se){let oe=await this.handleFileConflict(c);if(oe==="skip"){t.skipped.push(m);continue}else oe==="cancel"&&(o.error("Cancelled."),process.exit(0));}i.push({componentName:e,filePath:c,fileType:u,destPath:m,content:l,existedBefore:se});}if(i.length>0)try{await this.applyFileBatch(i),i.forEach(l=>t.added.push(l.destPath));let c=new Set(i.filter(l=>l.fileType==="js").map(l=>l.componentName));for(let l of Array.from(c))await this.autoImportJs(l);}catch(c){i.forEach(l=>t.failed.push({name:l.destPath,error:c.message}));}return t}buildDependencies(e){let t={};e.requires?.composer?.length&&(t.composer=Array.from(new Set(e.requires.composer)));let n=e.requires?.npm?[...e.requires.npm]:[];return e.requires_alpine&&!n.some(s=>s==="alpinejs"||s.startsWith("alpinejs@"))&&n.unshift("alpinejs"),n.length>0&&(t.npm=Array.from(new Set(n))),Object.keys(t).length>0?t:null}async fetchComponentWithFiles(e){let t=await this.registryService.fetchComponent(e,{includeFiles:true});return "files"in t?t:{files:{}}}async autoImportJs(e){try{let t=this.configManager?.getJsEntryPath();if(!t||!await this.fileSystem.fileExists(t))return;let n=`./ui/${e}`;ge(t,e,n),o.success(`Auto-imported ${e} into ${t}`);}catch(t){o.warn(`Failed to auto-import JS for ${e}: ${t.message}`);}}getDestinationPath(e){return e}async handleFileConflict(e){let{action:t}=await be({type:"select",name:"action",message:`File "${e}" already exists. What do you want to do?`,choices:[{title:"Skip",value:"skip"},{title:"Overwrite",value:"overwrite"},{title:"Cancel",value:"cancel"}],initial:0},{onCancel:()=>{o.error("Cancelled."),process.exit(0);}});return t}async applyFileBatch(e){let t=[],n=[];try{for(let s of e){let i=`${s.destPath}.velyx-tmp`;await this.fileSystem.writeFile(i,s.content),t.push(i);}for(let s of e){if(!s.existedBefore)continue;if(!ie(s.destPath))throw new Error(`Failed to create backup for ${s.destPath}`);n.push(s.destPath);}for(let s of e){let i=`${s.destPath}.velyx-tmp`;await h.move(i,s.destPath,{overwrite:!0});}n.forEach(s=>T(s));}catch(s){for(let i of e)await this.fileSystem.fileExists(i.destPath)&&await h.remove(i.destPath),i.existedBefore&&N(i.destPath);for(let i of t)await this.fileSystem.fileExists(i)&&await h.remove(i);throw s}}};var B=class{constructor(e,t,n){this.registryService=e;this.configManager=t;this.componentService=n??new q(e,new f,t);}componentService;validateInitialization(){if(!this.configManager.validate())throw new Error("Velyx is not initialized")}validateComponents(e,t){for(let n of e)if(!t.components.find(i=>i.name===n))throw new Error(`Component "${n}" not found`)}async getAvailableComponents(){return await this.registryService.fetchRegistry()}async addComponents(e){return await this.componentService.addComponents(e)}displayResults(e){e.added.forEach(t=>o.success(`Added ${t}`)),e.skipped.forEach(t=>o.warn(`Skipped ${t}`)),e.failed.forEach(({name:t,error:n})=>o.error(`Failed to add ${t}: ${n}`));}displayNextSteps(e){e.added.length!==0&&console.log(`
21
+ \u{1F389} Happy coding! Enjoy building beautiful components!`);}};var W=class extends Error{constructor(t,n){super(t);this.cause=n;this.name="RegistryError";}},p=class extends W{constructor(e,t){super(e,t),this.name="NetworkError";}},y=class extends W{constructor(e,t){super(`Component "${e}" not found`,t),this.name="ComponentNotFoundError";}};var x={maxRetries:3,initialDelay:1e3,backoffFactor:2,maxDelay:1e4,retryableStatusCodes:[408,429,500,502,503,504],timeout:3e4,headers:{}};function te(r){return new Promise(e=>setTimeout(e,r))}function re(r,e,t,n){let s=e*Math.pow(t,r);return Math.min(s,n)}function vt(r,e){return e.includes(r)}async function wt(r,e){let{timeout:t=x.timeout,headers:n={}}=e,s=new AbortController,i=setTimeout(()=>s.abort(),t);try{return await fetch(r,{signal:s.signal,headers:{"User-Agent":"Velyx-CLI",...n}})}catch(a){throw a instanceof Error&&a.name==="AbortError"?new p(`Request timeout after ${t}ms for ${r}`,a):a}finally{clearTimeout(i);}}var G=class{async fetch(e,t={}){let n={maxRetries:t.maxRetries??x.maxRetries,initialDelay:t.initialDelay??x.initialDelay,backoffFactor:t.backoffFactor??x.backoffFactor,maxDelay:t.maxDelay??x.maxDelay,retryableStatusCodes:t.retryableStatusCodes??x.retryableStatusCodes,timeout:t.timeout??x.timeout,headers:t.headers??x.headers},s=null;for(let i=0;i<=n.maxRetries;i++)try{let a=await wt(e,{...t,timeout:n.timeout,headers:n.headers});if(a.ok||!vt(a.status,n.retryableStatusCodes))return a;if(console.log("Attempt: ",i),i===n.maxRetries)throw new p(`Request failed after ${n.maxRetries+1} attempts: ${a.status} ${a.statusText}`);let c=re(i,n.initialDelay,n.backoffFactor,n.maxDelay);await te(c);}catch(a){if(s=a,a instanceof p&&a.message.includes("timeout")){if(i===n.maxRetries)throw a;let l=re(i,n.initialDelay,n.backoffFactor,n.maxDelay);await te(l);continue}if(i===n.maxRetries)throw s instanceof p?s:new p(`Request failed after ${n.maxRetries+1} attempts: ${s.message}`,s);let c=re(i,n.initialDelay,n.backoffFactor,n.maxDelay);await te(c);}throw new p(`Request failed after ${n.maxRetries+1} attempts: ${s?.message??"Unknown error"}`,s??void 0)}async fetchJson(e,t){let n=await this.fetch(e,t);if(!n.ok)throw new p(`Failed to fetch JSON from ${e}: ${n.status} ${n.statusText}`);try{return await n.json()}catch(s){throw new p(`Failed to parse JSON from ${e}: ${s.message}`,s)}}async fetchText(e,t){let n=await this.fetch(e,t);if(!n.ok)throw new p(`Failed to fetch text from ${e}: ${n.status} ${n.statusText}`);try{return await n.text()}catch(s){throw new p(`Failed to read text from ${e}: ${s.message}`,s)}}};var Oe=()=>process.env.VELYX_REGISTRY_URL?process.env.VELYX_REGISTRY_URL.replace(/\/$/,""):"http://velyx.test/api/v1";var z=class{httpService;baseUrl;constructor(e){this.httpService=e??new G,this.baseUrl=Oe();}async fetchRegistry(){try{let e=await this.httpService.fetch(`${this.baseUrl}/components`);if(!e.ok)throw new p(`Failed to fetch registry: ${e.status} ${e.statusText}`);let t=await this.httpService.fetchJson(`${this.baseUrl}/components`);return {components:Object.values(t.data),count:t.count}}catch(e){throw e instanceof p?e:new p(`Failed to fetch registry: ${e.message}`)}}async fetchComponent(e,t){try{let n=this.buildComponentUrl(e,t),s=await this.httpService.fetch(n);if(s.status===404)throw new y(e);if(!s.ok)throw new p(`Failed to fetch component: ${s.status} ${s.statusText}`);let i=await this.httpService.fetchJson(n);return t?.includeFiles?i.data:this.convertRegistryComponentToMeta(i.data)}catch(n){throw n instanceof y||n instanceof p?n:new p(`Failed to fetch component "${e}": ${n.message}`)}}async fetchFile(e,t){try{let n=e.split("/").pop()||e,s=await this.httpService.fetch(`${this.baseUrl}/components/${n}`);if(s.status===404)throw new y(n);if(!s.ok)throw new p(`Failed to fetch component: ${s.status} ${s.statusText}`);let a=(await this.httpService.fetchJson(`${this.baseUrl}/components/${n}`)).files[t];if(a===void 0)throw new p(`File "${t}" not found in component "${n}"`);return a}catch(n){throw n instanceof y||n instanceof p?n:new p(`Failed to fetch file "${t}": ${n.message}`)}}async resolveDependencies(e){let t=new Set,n=[];return await(async i=>{t.has(i.name)||(t.add(i.name),n.push(i));})(e),n}convertRegistryComponentToMeta(e){return {name:e.name,description:e.description,latest:e.latest,versions:e.versions,requires_alpine:e.requires_alpine,requires:e.requires,categories:e.categories,laravel:e.laravel}}buildComponentUrl(e,t){let n=new URLSearchParams;t?.version&&n.append("version",t.version),t?.includeFiles&&n.append("include","files");let s=n.toString();return `${this.baseUrl}/components/${e}${s?`?${s}`:""}`}async getComponentVersions(e){try{let t=await this.httpService.fetch(`${this.baseUrl}/components/${e}/versions`);if(t.status===404)throw new y(e);if(!t.ok)throw new p(`Failed to fetch component versions: ${t.status} ${t.statusText}`);return await this.httpService.fetchJson(`${this.baseUrl}/components/${e}/versions`)}catch(t){throw t instanceof y||t instanceof p?t:new p(`Failed to fetch versions for "${e}": ${t.message}`)}}};var I=class{velyxService;constructor(){this.velyxService=new z;}async fetchRegistry(){return await g.withTask("Fetching registry...",()=>this.velyxService.fetchRegistry(),void 0,"Failed to fetch registry")}async fetchComponent(e,t){let n=t?.includeFiles?`Fetching component "${e}" with files...`:`Fetching component "${e}" metadata...`;return await g.withTask(n,()=>this.velyxService.fetchComponent(e,t),void 0,`Failed to fetch component "${e}"`)}async resolveDependencies(e){return await g.withTask("Resolving dependencies...",()=>this.velyxService.resolveDependencies(e),void 0,"Failed to resolve dependencies")}};async function St(r,e){if(r.all)return [...e];if(r.components?.length)return r.components;o.info("Use arrow keys and space to select, then press enter.");let{components:t}=await be({type:"multiselect",name:"components",message:"Which components would you like to add?",hint:"Space to select. A to toggle all. Enter to submit.",instructions:false,choices:e.map(s=>({title:s,value:s,selected:r.all?true:r.components?.includes(s)}))});t?.length||(o.warn("No components selected. Exiting."),o.info(""),process.exit(1));let n=z$1.array(z$1.string()).safeParse(t);return n.success||(o.error("Something went wrong. Please try again."),process.exit(1)),n.data}async function Ne(r){process.chdir(r.cwd);let e=new k;await e.load();let t=new I,n=new B(t,e);try{n.validateInitialization();}catch{o.error("Velyx is not initialized"),o.log("Run velyx init first"),process.exit(1);}let s=await n.getAvailableComponents(),i=s.components.map(l=>l.name).sort((l,m)=>l.localeCompare(m)),a=await St(r,i);try{n.validateComponents(a,s);}catch(l){o.error(l.message),o.log("Run velyx list to see available components"),process.exit(1);}let c=await n.addComponents(a);n.displayResults(c),n.displayNextSteps(c);}var kt=z$1.object({components:z$1.array(z$1.string()).optional(),cwd:z$1.string(),all:z$1.boolean()}),Te=new Command().name("add").argument("[components...]","Names of components to add").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("-a, --all","add all available components",false).description("Add one or more UI components to your Laravel project").action(async(r,e)=>{let t=new C;try{let n={components:r,cwd:w.resolve(e.cwd),all:!!e.all},s=kt.parse(n);await Ne(s);}catch(n){t.handle(n,"add command"),process.exit(1);}});function Et(r,e){if(!e)return [...r];let t=e.toLowerCase();return r.filter(n=>{let s=n.name.toLowerCase().includes(t),i=n.description?n.description.toLowerCase().includes(t):false,a=n.categories?n.categories.some(c=>c.toLowerCase().includes(t)):false;return s||i||a})}function Ft(r,e,t){let n=Math.max(0,e??0);return t===void 0?r.slice(n):r.slice(n,n+Math.max(0,t))}async function De(r){let n=[...(await new I().fetchRegistry()).components].sort((c,l)=>c.name.localeCompare(l.name)),s=Et(n,r.query),i=Ft(s,r.offset,r.limit);if(r.json){console.log(JSON.stringify({total:s.length,count:i.length,offset:r.offset??0,limit:r.limit??null,components:i},null,2));return}if(i.length===0){o.warn("No components found.");return}console.log(v.bold(`
22
+ Available components:`)),console.log("");let a=new It({head:[v.bold("Component"),v.bold("Description"),v.bold("Categories")],colWidths:[24,50,24],wordWrap:true,style:{head:[],border:[]}});for(let c of i)a.push([v.cyan(c.name),v.white(c.description||"No description"),v.gray(c.categories?.join(", ")||"-")]);console.log(a.toString()),console.log(""),o.info(`Run ${v.green("velyx add <component>")} to add one.`);}var Ot=z$1.object({cwd:z$1.string(),query:z$1.string().optional(),limit:z$1.number().optional(),offset:z$1.number().optional(),json:z$1.boolean()}),Ve=new Command().name("list").alias("search").description("List or search components from the registry").option("-c, --cwd <cwd>","the working directory. defaults to the current directory.",process.cwd()).option("-q, --query <query>","query string").option("-l, --limit <number>","maximum number of items to display",void 0).option("-o, --offset <number>","number of items to skip",void 0).option("--json","output JSON",false).action(async r=>{let e=new C;try{let t=Ot.parse({cwd:w.resolve(r.cwd),query:r.query,limit:r.limit?Number.parseInt(r.limit,10):void 0,offset:r.offset?Number.parseInt(r.offset,10):void 0,json:!!r.json});process.chdir(t.cwd);let n=new k;try{await n.load();}catch{o.error("Velyx is not initialized"),o.log("Run velyx init first"),process.exit(1);}await De(t);}catch(t){e.handle(t,"list command"),process.exit(1);}});function Nt(){console.log(""),console.log(v.bold.cyan(` \u25BC VELYX CLI v${$.version}`)),console.log(v.gray(" Tailwind CSS v4+ components for Laravel")),console.log("");}var ne=new Command;ne.name("velyx").description("Velyx CLI: Copy UI components into your Laravel project").version($.version,"-v, --version","display the version number").hook("preAction",()=>{Nt();});ne.addCommand(Te).addCommand(Ee).addCommand(Ve);ne.parse(process.argv);//# sourceMappingURL=index.js.map
23
23
  //# sourceMappingURL=index.js.map