@sugarcube-sh/cli 0.0.2

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,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Mark Tomlinson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @sugarcube-sh/cli
2
+
3
+ <p>
4
+ <a href="https://www.npmjs.com/package/@sugarcube-sh/cli"><img src="https://img.shields.io/npm/v/@sugarcube-sh/cli.svg" alt="Latest Release"></a>
5
+ <a href="https://www.npmjs.com/package/@sugarcube-sh/cli"><img src="https://img.shields.io/npm/dt/@sugarcube-sh/cli.svg" alt="Total Downloads"></a>
6
+ <a href="https://github.com/sugarcube-sh/sugarcube/blob/main/LICENSE.md"><img src="https://img.shields.io/badge/license-see%20LICENSE-blue" alt="License"></a>
7
+ </p>
8
+
9
+ CLI for [sugarcube](https://sugarcube.sh).
10
+
11
+ ## Commands
12
+
13
+ - `@sugarcube-sh/cli init` - Set up sugarcube in your project
14
+ - `@sugarcube-sh/cli generate` - Generate CSS from your design tokens
15
+ - `@sugarcube-sh/cli validate` - Validate your token files
16
+ - `@sugarcube-sh/cli components` - Add components to your project
17
+ - `@sugarcube-sh/cli cube` - Add CUBE CSS
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pnpm add -D @sugarcube-sh/cli
23
+ ```
24
+
25
+ ## Documentation
26
+
27
+ For full documentation, visit [sugarcube.sh](https://sugarcube.sh).
28
+
29
+ ## License
30
+
31
+ See [LICENSE.md](./LICENSE.md) for terms.
@@ -0,0 +1 @@
1
+ export { SugarcubeConfig, defineConfig } from '@sugarcube-sh/core';
@@ -0,0 +1 @@
1
+ import{defineConfig as o}from"@sugarcube-sh/core";export{o as defineConfig};
package/dist/index.mjs ADDED
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+ var nt=Object.defineProperty;var i=(e,t)=>nt(e,"name",{value:t,configurable:!0});import{Command as U}from"commander";import{relative as N,join as R,basename as Se,resolve as j,dirname as st,isAbsolute as it,normalize as rt}from"pathe";import c from"picocolors";import{existsSync as D,readFileSync as Ie}from"node:fs";import{z as y}from"zod";import ie,{mkdir as W,writeFile as X,readFile as be}from"node:fs/promises";import{execa as ot}from"execa";import{loadAndResolveTokens as at,findResolverDocument as re,loadInternalConfig as ee,isNoConfigError as Ee,configFileExists as ve,processAndConvertTokens as oe,generateCSSVariables as ke,writeCSSVariablesToDisk as Re,writeCSSUtilitiesToDisk as _e,fillDefaults as $e,convertConfigToUnoRules as ct,DEFAULT_CONFIG as ae}from"@sugarcube-sh/core";import{select as lt,isCancel as ce,log as ut,multiselect as dt,confirm as ft,cancel as Ce}from"@clack/prompts";import{getColumns as pt}from"@clack/core";import{wrapAnsi as mt}from"fast-wrap-ansi";import gt from"is-unicode-supported";import*as Fe from"node:readline";import Ne from"node:readline";import{createLogUpdate as De}from"log-update";import le,{resolve as ht}from"node:path";import{detect as wt}from"@antfu/ni";import{createGenerator as yt}from"@unocss/core";import{glob as ue}from"tinyglobby";import{getTsconfig as Tt}from"get-tsconfig";var St="0.0.2",Oe={version:St};const de="fluid",It="**/*.json",Ae="@sugarcube-sh/vite",bt="@sugarcube-sh/cli",Et=["node_modules",".git",".next","dist","build"],vt=20,O={INIT:"@sugarcube-sh/cli init",COMPONENTS:"@sugarcube-sh/cli components",CUBE:"@sugarcube-sh/cli cube"},_={INITIALIZATION:"https://sugarcube.sh/docs/getting-started",CONFIGURATION:"https://sugarcube.sh/docs/configuration",ISSUES:"https://github.com/sugarcube-sh/sugarcube/issues",RESOLVER:"https://sugarcube.sh/docs/resolver",DESIGN_TOKENS:"https://sugarcube.sh/docs/tokens",COMPONENTS_CLI:"https://sugarcube.sh/docs/reference/cli-commands/#components",HOMEPAGE:"https://sugarcube.sh"},g={PROJECT_REQUIRED:`No sugarcube project detected. Please run ${c.cyan(O.INIT)} first.
3
+
4
+ For more information, visit: ${c.cyan(_.INITIALIZATION)}`,CONFIG_EXISTS:i(()=>`A sugarcube config file already exists in this project.
5
+
6
+ To start over, remove it and run ${c.cyan(O.INIT)} again.`,"CONFIG_EXISTS"),PLUGIN_INSTALL_FAILED:i(e=>{const t=e.packageManager==="npm"?"install":"add";return`Failed to install ${e.pluginToInstall} plugin.
7
+
8
+ This is usually a temporary issue. Try these steps:
9
+
10
+ 1. Run the command again
11
+ 2. Check your internet connection
12
+ 3. Install manually: ${e.packageManager} ${t} ${e.pluginToInstall}
13
+
14
+ If the problem continues, please open an issue at:
15
+ ${_.ISSUES}`},"PLUGIN_INSTALL_FAILED"),CLI_INSTALL_FAILED:i(e=>{const t=e.packageManager==="npm"?"install":"add";return`Failed to install @sugarcube-sh/cli.
16
+
17
+ This is usually a temporary issue. Try these steps:
18
+
19
+ 1. Run the command again
20
+ 2. Check your internet connection
21
+ 3. Install manually: ${e.packageManager} ${t} -D @sugarcube-sh/cli
22
+
23
+ If the problem continues, please open an issue at:
24
+ ${_.ISSUES}`},"CLI_INSTALL_FAILED"),INITIALIZATION_INCOMPLETE:i(()=>`The initialization process was not completed properly.
25
+ This is an internal error that should not occur.
26
+ Try running the \`init\` command again.
27
+
28
+ If the problem persists, please report this issue at
29
+ ${_.ISSUES}`,"INITIALIZATION_INCOMPLETE"),CONFIG_WRITE_FAILED:i(()=>"Failed to write configuration file. Check permissions and try again.","CONFIG_WRITE_FAILED"),DIRECTORY_PATH_EMPTY:i(e=>`${e} cannot be empty. Please provide a valid directory path.`,"DIRECTORY_PATH_EMPTY"),DIRECTORY_PATH_RESERVED:i((e,t)=>`Option: ${e}
30
+ Value: "${t}"
31
+
32
+ ${e} cannot be in a reserved directory`,"DIRECTORY_PATH_RESERVED"),KIT_INCOMPLETE:i(()=>`The starter kit appears to be incomplete or corrupted.
33
+
34
+ This is likely a temporary issue. Please try running the command again or choose a different starter kit.`,"KIT_INCOMPLETE"),REGISTRY_AUTH_REQUIRED:i(e=>`Registry access denied: Authentication required
35
+ URL: ${c.cyan(e)}`,"REGISTRY_AUTH_REQUIRED"),REGISTRY_AUTH_INVALID:i(e=>`Registry access denied: Invalid or missing token
36
+ URL: ${c.cyan(e)}`,"REGISTRY_AUTH_INVALID"),REGISTRY_NOT_FOUND:i(e=>`Registry resource not found
37
+ URL: ${c.cyan(e)}`,"REGISTRY_NOT_FOUND"),REGISTRY_REQUEST_FAILED:i((e,t)=>`Registry request failed: ${e}
38
+ URL: ${c.cyan(t)}`,"REGISTRY_REQUEST_FAILED"),REGISTRY_NETWORK_ERROR:i(e=>`Failed to connect to registry
39
+
40
+ URL: ${c.cyan(e)}
41
+
42
+ The registry server may be temporarily unavailable or there might be network connectivity issues. Please try again in a few minutes.`,"REGISTRY_NETWORK_ERROR"),REGISTRY_INVALID_DATA:i(e=>`Invalid registry data received
43
+ URL: ${c.cyan(e)}`,"REGISTRY_INVALID_DATA"),REGISTRY_ITEM_NOT_FOUND:i((e,t,n)=>`${e==="tokens"?"Starter kit":e}'${c.cyan(t)} ' not found in registry
44
+ Available ${e==="tokens"?"starter kit":e}s: ${n.join(", ")}`,"REGISTRY_ITEM_NOT_FOUND"),REGISTRY_FILE_INVALID:i(e=>`Invalid file content received
45
+ File: ${c.cyan(e)}`,"REGISTRY_FILE_INVALID"),STARTER_KIT_UNAVAILABLE:i(e=>`Starter kit '${c.cyan(e)}' is currently unavailable.
46
+
47
+ Please try a different starter kit or run the command again in a few minutes.`,"STARTER_KIT_UNAVAILABLE"),RESOLVER_NOT_CONFIGURED:i(()=>`No resolver path configured.
48
+
49
+ Add a resolver path to your sugarcube config:
50
+
51
+ ${c.cyan(`export default {
52
+ resolver: "./tokens.resolver.json",
53
+ // ...
54
+ }`)}
55
+
56
+ See ${c.cyan(_.RESOLVER)} for more information.`,"RESOLVER_NOT_CONFIGURED"),RESOLVER_NOT_FOUND:i(e=>`No resolver document found in ${c.cyan(e)}.
57
+
58
+ A resolver document (*.resolver.json) is required to define how your tokens are loaded.
59
+
60
+ See ${c.cyan(_.RESOLVER)} to learn how to create one.`,"RESOLVER_NOT_FOUND"),RESOLVER_MULTIPLE_FOUND:i(e=>`Multiple resolver documents found:
61
+ ${e.map(t=>` - ${c.cyan(t)}`).join(`
62
+ `)}
63
+
64
+ A project should have only one resolver document. Please remove the extras or consolidate them.`,"RESOLVER_MULTIPLE_FOUND"),TOKEN_LOAD_FAILED:i(e=>`Failed to load token files:
65
+
66
+ ${e.join(`
67
+ `)}
68
+
69
+ Please check your token files and try again.`,"TOKEN_LOAD_FAILED"),TOKEN_VALIDATION_FAILED:i(e=>{let t=`Token validation failed:
70
+
71
+ `;for(const[n,s]of e){t+=`Error(s) in ${c.cyan(n)}:
72
+ `;for(const r of s)t+=` - ${r}
73
+ `;t+=`
74
+ `}return t+=`See ${c.cyan(_.DESIGN_TOKENS)} for valid token formats`,t},"TOKEN_VALIDATION_FAILED"),TOKEN_FILE_INVALID_JSON:i(e=>`File ${e}: Invalid JSON syntax`,"TOKEN_FILE_INVALID_JSON"),TOKEN_FILE_INCOMPLETE_JSON:i(e=>`File ${e}: Incomplete JSON file`,"TOKEN_FILE_INCOMPLETE_JSON"),TOKEN_FILE_GENERIC_ERROR:i((e,t)=>`File ${e}: ${t}`,"TOKEN_FILE_GENERIC_ERROR"),DEPENDENCY_INSTALL_FAILED:i(e=>`Failed to install dependencies using ${e}.
75
+ Please check your package manager configuration and try again.`,"DEPENDENCY_INSTALL_FAILED"),VALIDATE_NO_PATH_SPECIFIED:i(()=>`No path specified.
76
+
77
+ Run ${c.cyan("sugarcube validate --help")} for more information.`,"VALIDATE_NO_PATH_SPECIFIED"),VALIDATE_PATH_NOT_FOUND:i(e=>`Path not found: ${e}
78
+
79
+ Please check that the specified path exists`,"VALIDATE_PATH_NOT_FOUND"),VALIDATE_NO_TOKEN_FILES:i(()=>`No token files found.
80
+
81
+ Please ensure the path contains .json token files`,"VALIDATE_NO_TOKEN_FILES"),COMPONENTS_FRAMEWORK_REQUIRED:i(()=>`Framework is required when specifying components. Use --framework to specify a framework (react, css-only) or run without arguments for interactive mode.
82
+
83
+ See ${c.cyan(_.COMPONENTS_CLI)} for more information.`,"COMPONENTS_FRAMEWORK_REQUIRED"),COMPONENTS_INVALID_FRAMEWORK:i(()=>"Invalid framework. Must be one of: react, css-only.","COMPONENTS_INVALID_FRAMEWORK"),COMPONENTS_DIRECTORY_NOT_CONFIGURED:i(()=>"Components directory must be configured in non-interactive mode. Please run the 'components' command without arguments first.","COMPONENTS_DIRECTORY_NOT_CONFIGURED"),PLUGIN_DETECTED:i(e=>`Plugin detected: ${e}
84
+
85
+ The 'generate' command is for manual generation without plugins. Since you have a plugin installed, use your development server instead:
86
+
87
+ npm run dev # or your framework's dev command
88
+
89
+ The plugin will automatically generate CSS with hot module replacement.`,"PLUGIN_DETECTED"),GENERATE_NO_CONFIG_OR_RESOLVER:i(()=>`No design tokens found.
90
+
91
+ Run ${c.cyan(O.INIT)} to set up your design tokens.
92
+
93
+ Stuck? ${c.cyan(_.HOMEPAGE)}`,"GENERATE_NO_CONFIG_OR_RESOLVER"),GENERATE_MULTIPLE_RESOLVERS_NO_CONFIG:i(e=>`No config file found, but multiple resolver files detected:
94
+ ${e.map(t=>` - ${t}`).join(`
95
+ `)}
96
+
97
+ Please either:
98
+ - Create a config file with ${c.cyan(O.INIT)}
99
+ - Use --resolver flag to specify which resolver to use`,"GENERATE_MULTIPLE_RESOLVERS_NO_CONFIG")};class p extends Error{static{i(this,"CLIError")}constructor(t,n){super(t),this.name="CLIError",this.cause=n}}const fe=y.enum(["react","web-components","css-only"]),Le=y.object({path:y.string(),type:y.string()}),kt=Le.extend({framework:fe}),Rt=y.object({name:y.string(),type:y.string(),description:y.string().optional(),frameworks:y.array(y.string()).optional(),files:y.array(y.union([kt,Le])),tokens:y.record(y.object({type:y.string(),mapping:y.string()})).optional(),dependencies:y.record(fe,y.array(y.string())).optional(),registryDependencies:y.record(fe,y.array(y.string())).optional(),tokenDependencies:y.array(y.string()).optional()}),_t=y.array(Rt),$t=y.object({content:y.string()}),Me=process.env.REGISTRY_URL??"https://sugarcube.sh/r";async function Pe(e){try{const t=await fetch(e);if(!t.ok){if(t.status===401)throw new p(g.REGISTRY_AUTH_REQUIRED(e));if(t.status===403)throw new p(g.REGISTRY_AUTH_INVALID(e));if(t.status===404)throw new p(g.REGISTRY_NOT_FOUND(e));const n=await t.json().catch(()=>null),s=n&&typeof n=="object"&&"error"in n?String(n.error):t.statusText;throw new p(g.REGISTRY_REQUEST_FAILED(s,e))}return t.json()}catch(t){throw t instanceof p?t:new p(g.REGISTRY_NETWORK_ERROR(e))}}i(Pe,"fetchRegistry");async function G(){const e=`${Me}/index.json`,t=await Pe(e);try{return _t.parse(t)}catch{throw new p(g.REGISTRY_INVALID_DATA(e))}}i(G,"getRegistryIndex");async function pe({type:e,name:t,framework:n}){const s=await G(),r=s.find(l=>l.type===e&&l.name===t);if(!r){const l=s.filter(f=>f.type===e).map(f=>f.name);throw new p(g.REGISTRY_ITEM_NOT_FOUND(e,t,l))}let o=r.files;e==="component"&&n&&(o=r.files.filter(l=>"framework"in l&&l.framework===n));const a=await Promise.all(o.map(async l=>{const f=`${Me}/${l.path}.json`,d=await Pe(f);try{const u=$t.parse(d);return{path:l.path,type:l.type,framework:"framework"in l?l.framework:void 0,content:u.content}}catch{throw new p(g.REGISTRY_FILE_INVALID(l.path))}}));return{item:r,files:a}}i(pe,"getRegistryFiles");async function Ct(e){const t=await pe({type:"tokens",name:e});if(!t.files[0])throw new p(g.STARTER_KIT_UNAVAILABLE(e));return t}i(Ct,"fetchStarterKit");async function me(e,t,n){const s=[],r=new Set;async function o(a){if(r.has(a))return;r.add(a);const l=e.find(d=>d.name===a);if(!l){const d=e.filter(u=>u.type==="component").map(u=>u.name).join(", ");throw new p(`Component '${a}' not found in registry
100
+ Available components: ${d}`)}const f=l.registryDependencies?.[n]||[];for(const d of f)await o(d);s.push(l)}i(o,"resolveComponent");for(const a of t)await o(a);return s}i(me,"resolveTree");async function Ft({selectedComponents:e,componentType:t,componentsOutputDirectory:n}){const s={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},r=await G(),a=(await me(r,e,t)).map(u=>u.name),l=r.filter(u=>u.type==="component").filter(u=>a.includes(u.name)),f=l.flatMap(u=>u.files.filter(m=>(m.type==="tsx"||m.type==="astro"||m.type==="njk")&&"framework"in m&&m.framework===t).map(m=>N(process.cwd(),R(n,u.name,`${u.name}.${m.type}`))));s.componentFiles=f.filter(u=>D(R(process.cwd(),u)));const d=l.map(u=>{const m=u.name;return N(process.cwd(),R(n,u.name,`${m}.css`))});return s.componentCSS=d.filter(u=>D(R(process.cwd(),u))),s}i(Ft,"collectComponentOverwriteWarnings");async function Nt({cubeDirectory:e}){const t={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},s=(await G()).filter(r=>r.type==="cube").flatMap(r=>r.files).map(r=>{const o=r.path.replace(/^styles\//,"");return N(process.cwd(),R(e,o))});return t.cubeCSS=s.filter(r=>D(R(process.cwd(),r))),t}i(Nt,"collectCubeOverwriteWarnings");function Ue(e){const t=[];if(e.variableCSS.length>0&&t.push(`CSS variables files:
101
+ ${e.variableCSS.map(s=>` - ${s}`).join(`
102
+ `)}`),e.utilityCSS.length>0&&t.push(`CSS utility files:
103
+ ${e.utilityCSS.map(s=>` - ${s}`).join(`
104
+ `)}`),e.cubeCSS.length>0&&t.push(`CUBE CSS files:
105
+ ${e.cubeCSS.map(s=>` - ${s}`).join(`
106
+ `)}`),e.componentFiles.length>0||e.componentCSS.length>0){const s=[...e.componentFiles,...e.componentCSS];t.push(`Component files:
107
+ ${s.map(r=>` - ${r}`).join(`
108
+ `)}`)}return e.indexFiles.length>0&&t.push(`Index files:
109
+ ${e.indexFiles.map(s=>` - ${s}`).join(`
110
+ `)}`),t.length===0?void 0:`The following file(s) already exist and will be overwritten:
111
+
112
+ ${t.join(`
113
+
114
+ `)}`}i(Ue,"formatOverwriteWarnings");async function te(e,t,n,s={}){if(e.length===0)return;const{devDependency:r=!1}=s,o=n==="npm"?"install":"add",a=(()=>{if(!r)return[];switch(n){case"npm":return["--save-dev"];case"pnpm":return["-D"];case"yarn":return["-D"];case"bun":return["-d"]}})();try{await ot(n,[o,...a,...e],{cwd:t})}catch{throw new p(g.DEPENDENCY_INSTALL_FAILED(n))}}i(te,"installDependencies");async function Dt(e,t,n){const s=R(n,t.name);if(await W(s,{recursive:!0}),e.path.endsWith(".css")){const o=R(s,`${t.name}.css`);return await X(o,e.content),o}const r=R(s,Se(e.path));return await X(r,e.content),r}i(Dt,"writeComponentFile");async function Ot({registryIndex:e,selectedComponents:t,componentType:n,componentsOutputDirectory:s,packageManager:r}){const o=[],a=new Set;await W(s,{recursive:!0});const l=await me(e,t,n);for(const f of l){const d=await pe({type:"component",name:f.name,framework:n});for(const m of d.files)if(m)try{const h=await Dt(m,f,s);h&&o.push(h)}catch(h){const I=h instanceof Error?`: ${h.message}`:"";throw new p(`Failed to write component file for "${f.name}"${I}`)}const u=f.dependencies?.[n]||[];for(const m of u)a.add(m)}if(a.size>0)try{await te(Array.from(a),process.cwd(),r)}catch(f){const d=f instanceof Error?`: ${f.message}`:"";throw new p(`Failed to install component dependencies${d}`)}return{createdFiles:o,npmDependencies:a}}i(Ot,"installComponents");function At(e,t){const n=j(e),s=j(t),r=N(s,n);return!r.startsWith("..")&&!it(r)}i(At,"isWithinDirectory");async function Lt(e){const t=[],n=j(process.cwd(),e);await W(n,{recursive:!0});const r=(await G()).filter(o=>o.type==="cube").map(o=>o.name);for(const o of r){const a=await pe({type:"cube",name:o});for(const l of a.files){if(!l)continue;const f=l.path.replace(/^styles\//,""),d=j(n,f);if(!At(d,n))throw new p(`Invalid file path detected in CUBE module "${o}": path escapes target directory`);const u=st(d);try{await W(u,{recursive:!0}),await X(d,l.content),t.push(d)}catch(m){const h=m instanceof Error?`: ${m.message}`:"";throw new p(`Failed to write CUBE module "${o}"${h}`)}}}return t}i(Lt,"installCUBE");async function Mt(e,t){await ie.mkdir(t,{recursive:!0});const n=[];for(const s of e)await ie.writeFile(s.path,s.content),n.push(s.path);return n}i(Mt,"writeTokenFiles");async function K(e,t){let n;if(t)n={type:"memory",data:t,config:e};else{if(!e.resolver)throw new p(g.RESOLVER_NOT_CONFIGURED());n={type:"resolver",resolverPath:e.resolver,config:e}}const{trees:s,resolved:r,modifiers:o,errors:a}=await at(n);if(a.load.length>0){const l=a.load.map(f=>{const d=f.file.split("/").pop()||"unknown file";let u=`File ${d}: `;return f.message.includes("Unexpected token")?u=g.TOKEN_FILE_INVALID_JSON(d):f.message.includes("Unexpected end")?u=g.TOKEN_FILE_INCOMPLETE_JSON(d):u=g.TOKEN_FILE_GENERIC_ERROR(d,f.message),u});throw new p(g.TOKEN_LOAD_FAILED(l))}if(a.validation.length>0||a.flatten.length>0||a.resolution.length>0){const l=[...a.flatten,...a.validation,...a.resolution],f=new Map;for(const d of l)if(d.source?.sourcePath){const u=f.get(d.source.sourcePath)||[];u.push(d.message),f.set(d.source.sourcePath,u)}throw new p(g.TOKEN_VALIDATION_FAILED(f))}return{trees:s,resolved:r,modifiers:o}}i(K,"loadAndResolveTokensForCLI");const Pt=i(async(e,t,n)=>{const s=await Ct(e),r=j(process.cwd(),t),o=s.files.map(a=>({path:R(r,Se(a.path)),content:a.content}));return{config:n,tokenFiles:o,tokensDir:r,createdTokenPaths:o.map(a=>N(process.cwd(),a.path))}},"prepareStarterKitForInstall");async function Ut(e){const t=await Pt(e.starterKit??"",e.tokensDir,e.config),n=await Mt(t.tokenFiles,e.tokensDir),s=await re(e.tokensDir);if(s.found==="none")throw new p(g.RESOLVER_NOT_FOUND(e.tokensDir));if(s.found==="multiple")throw new p(g.RESOLVER_MULTIPLE_FOUND(s.paths));const r={...e.config,resolver:s.path},{trees:o,resolved:a}=await K(r);e.setupResult={config:r,createdTokenPaths:t.createdTokenPaths,trees:o,resolved:a,tokenFiles:t.tokenFiles,tokensDir:t.tokensDir},e.createdFiles.push(...n),e.config=r,e.sugarcubeConfig={...e.sugarcubeConfig,resolver:s.path}}i(Ut,"installFromStarterKit");async function je(e=!0){const t=[{label:"React",value:"react",hint:".tsx"},{label:"CSS Only",value:"css-only",hint:".css"},{label:c.dim("Web components"),value:"web-components",hint:"Coming soon!"}];e&&t.push({label:"Skip",value:"skip",hint:"continue without components"});const n=await lt({message:"Build with",options:t});return ce(n)&&process.exit(0),n==="web-components"?(ut.info(c.blue("Web components are coming soon! Please choose React or CSS Only for now.")),je(e)):n}i(je,"promptComponentFramework");async function jt(e,t){const n=e.filter(r=>r.type==="component"&&r.frameworks?.includes(t)),s=await dt({message:"Select components to add",options:n.map(r=>({label:r.name,value:r.name,hint:r.description})),required:!0});return ce(s)&&process.exit(0),s}i(jt,"promptComponentSelectionFiltered");async function Ge(e,t=!1){const n=await ft({message:e,initialValue:t});return(!n||ce(n))&&(Ce(),process.exit(0)),!0}i(Ge,"confirmOverwrite");function x(e){return{absolute:j(process.cwd(),e)}}i(x,"resolveDirectoryFromFlag");async function Gt(e){if(e){const{absolute:t}=x(e);return{directory:t}}try{const{config:t}=await ee(),n=t.output.cube||t.output.cssRoot,{absolute:s}=x(n);return{directory:s}}catch(t){if(Ee(t)){const{absolute:n}=x("src/styles");return{directory:n}}throw t}}i(Gt,"getCubeDir");async function xt(e){if(e){const{absolute:t}=x(e);return{directory:t}}try{const{config:t}=await ee(),n=t.output.components??"src/components/ui",{absolute:s}=x(n);return{directory:s}}catch(t){if(Ee(t)){const{absolute:n}=x("src/components/ui");return{directory:n}}throw t}}i(xt,"getComponentsDir");const Bt=gt(),b=i((e,t)=>Bt?e:t,"unicodeOr"),Vt=b("\u25C7","o"),xe=b("\u250C","T"),A=b("\u2502","|"),ge=b("\u2514","\u2014"),Wt=b("\u2510","T"),Kt=b("\u2518","\u2014"),ne=b("\u2500","-"),Yt=b("\u256E","+"),zt=b("\u256F","+"),Ht=b("\u2570","+"),Jt=b("\u256D","+"),qt=b("\u25CF","\u2022"),Zt=b("\u25C6","*"),Qt=b("\u25B2","!"),Xt=b("\u25A0","x"),Y=i((e,t=c.bgGreen,n=c.black)=>t(` ${n(e)} `),"label"),z=i(e=>{const t=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"].join("|"),n=new RegExp(t,"g");return typeof e=="string"?e.replace(n,""):e},"strip"),H=i((e="",t)=>{process.stdout.write(`
115
+
116
+ ${c.gray(xe)}${c.gray(ne)} ${e}
117
+ `)},"intro"),se=i((e="",t)=>{process.stdout.write(`${c.gray(A)}
118
+ ${c.gray(ge)}${c.gray(ne)} ${e}
119
+
120
+ `)},"outro");function B(e){return new Promise(t=>setTimeout(t,e))}i(B,"sleep");const en=[Jt,Yt,Ht,zt],tn=[xe,Wt,ge,Kt];function Be(e,t,n,s){let r=n,o=n;return s==="center"?r=Math.floor((t-e)/2):s==="right"&&(r=t-e-n),o=t-r-e,[r,o]}i(Be,"getPaddingForLine");const nn=i(e=>e,"defaultFormatBorder"),he=i((e="",t="",n)=>{const s=n?.output??process.stdout,r=pt(s),a=1*2,l=n?.titlePadding??1,f=n?.contentPadding??2,d=n?.width===void 0||n.width==="auto"?1:Math.min(1,n.width),u=n?.includePrefix?`${A} `:"",m=n?.formatBorder??nn,h=(n?.rounded?en:tn).map(m),I=m(ne),w=m(A),k=r-u.length;let v=Math.floor(r*d)-u.length;if(n?.width==="auto"){const Z=e.split(`
121
+ `);let V=z(t).length+l*2;for(const tt of Z){const Te=z(tt).length+f*2;Te>V&&(V=Te)}const Q=V+a;Q<v&&(v=Q)}v%2!==0&&(v<k?v++:v--);const E=v-a,F=E-l*2,T=z(t).length>F?`${t.slice(0,F-3)}...`:t,[$,C]=Be(z(T).length,E,l,n?.titleAlign),L=mt(e,E-f*2,{hard:!0,trim:!1});s.write(`${u}${h[0]}${I.repeat($)}${T}${I.repeat(C)}${h[1]}
122
+ `);const q=L.split(`
123
+ `);for(const Z of q){const[V,Q]=Be(z(Z).length,E,f,n?.contentAlign);s.write(`${u}${w}${" ".repeat(V)}${Z}${" ".repeat(Q)}${w}
124
+ `)}s.write(`${u}${h[2]}${I.repeat(E)}${h[3]}
125
+ `)},"box");function we(e,t={}){const n=`
126
+ ${e}`;he(n,c.black(c.bgRed(" ERROR ")),{width:"auto",titlePadding:2,formatBorder:c.red,...t})}i(we,"errorBoxWithBadge");function Ve(e,t={}){const n=`
127
+ ${e}`;he(n,c.black(c.bgYellow(" WARNING ")),{width:"auto",titlePadding:2,formatBorder:c.yellow,...t})}i(Ve,"warningBoxWithBadge");function sn(e,t={}){const n=`
128
+ ${e}`;he(n,c.black(c.bgCyan(" INFO ")),{width:"auto",titlePadding:2,formatBorder:c.cyan,...t})}i(sn,"infoBoxWithBadge");const rn=i((e,t)=>{if(!(e.meta&&e.name!=="escape")){if(e.ctrl){if(e.name==="a")return"first";if(e.name==="c"||e.name==="d")return"abort";if(e.name==="e")return"last";if(e.name==="g")return"reset"}return e.name==="return"||e.name==="enter"?"submit":e.name==="backspace"?"delete":e.name==="delete"?"deleteForward":e.name==="abort"?"abort":e.name==="escape"?"exit":e.name==="tab"?"next":e.name==="pagedown"?"nextPage":e.name==="pageup"?"prevPage":e.name==="home"?"home":e.name==="end"?"end":e.name==="up"?"up":e.name==="down"?"down":e.name==="right"?"right":e.name==="left"?"left":!1}},"action"),on=i(async(e,t={})=>{const{sidebarSymbol:n=c.gray("\u2502"),clear:s=!1,stdin:r=process.stdin,stdout:o=process.stdout}=t,a=Ne.createInterface({input:r,escapeCodeTimeout:50}),l=De(o,{showCursor:!1});Ne.emitKeypressEvents(r,a);let f=0,d=!1;const u=i(async()=>{r.off("keypress",m),r.isTTY&&r.setRawMode(!1),a.close(),d=!0,f<e.length-1||s?l.clear():l.done()},"done"),m=i((h,I)=>{r.isTTY&&r.setRawMode(!0);const w=rn(I);if(w==="abort")return u(),process.exit(0);["up","down","left","right"].includes(w)||u()},"handleKeyPress");r.isTTY&&r.setRawMode(!0),r.on("keypress",m);for(const h of e){const I=Array.isArray(h)?h:h.split(" "),w=[];for(const E of[""].concat(I)){E&&w.push(E);const F=w.join(" ").replace(/sugarcube/g,c.cyan("sugarcube")),T=`${n} ${F}`;l(T),d||await new Promise($=>setTimeout($,Math.floor(Math.random()*126)+75))}d||await new Promise(E=>setTimeout(E,100));const v=(await Promise.all(I).then(E=>E.join(" "))).replace(/sugarcube/g,c.cyan("sugarcube"));l(`${n} ${v}`),d||await new Promise(E=>setTimeout(E,Math.floor(Math.random()*201)+1200)),f++}r.off("keypress",m),await new Promise(h=>setTimeout(h,100)),u(),r.isTTY&&r.setRawMode(!1),r.removeAllListeners("keypress")},"sayAnimatedInSidebar");function an(){return Math.floor(Math.random()*551)+200}i(an,"getRandomTaskDuration");async function cn(e,{sidebarSymbol:t="\u2502",spacing:n=1,stdin:s=process.stdin,stdout:r=process.stdout,initialDelayMs:o=200,minDurationMs:a,successPauseMs:l=300,successMessage:f,successAsOutro:d=!1}={}){const u=i((T,$)=>{let C="";switch($){case"start":C=`${c.cyan(`\u25B6 ${T.start}`)}`;break;case"pending":C=`${c.dim(`\u25A1 ${T.pending}`)}`;break;case"success":C=`${c.green(`\u2714 ${T.end}`)}`;break;case"end":C=`${c.dim(`\u25A0 ${T.end}`)}`;break}return`${t} ${C}`},"formatWithSidebar"),m=Array.from({length:e.length},()=>"");e.forEach((T,$)=>{m[$]=u(T,"pending")});const h=De(r),I=Fe.createInterface({input:s,escapeCodeTimeout:50});Fe.emitKeypressEvents(s,I);const w=i(T=>{T===""&&(h.clear(),I.close(),s.isTTY&&s.setRawMode(!1),process.exit(0)),s.isTTY&&s.setRawMode(!0)},"keypress");s.isTTY&&s.setRawMode(!0),s.on("keypress",w);const k=Array.from({length:Math.max(n,0)},()=>`${t}`),v=i(()=>[...k,...m].join(`
129
+ `),"renderContent");h(v()),await B(o);let E=0;for(const T of e){m[E]=u(T,"start"),h(v());const $=Date.now(),C=T.while();try{await C;const L=Date.now()-$,q=typeof a=="number"?a:an();L<q&&await B(q-L),m[E]=u(T,"success"),h(v()),await B(l)}catch(L){throw m[E]=`${t} ${c.red(`\u2717 ${T.end} (failed)`)}`,h(v()),T.onError?.(L),s.removeListener("keypress",w),I.close(),s.isTTY&&s.setRawMode(!1),L}E++}const F=e.map(T=>u(T,"end"));if(f)if(d){const T=`${c.gray(ge)}${c.gray(ne)} ${c.green(f)}`;h([...k,...F,`${t}`,T].join(`
130
+ `))}else{const T=`${t} ${c.green(f)}`;h([...k,...F,`${t}`,T].join(`
131
+ `))}else h([...k,...F].join(`
132
+ `));await B(1e3),s.removeListener("keypress",w),s.isTTY&&s.setRawMode(!1),I.close(),h.done()}i(cn,"executeTasksInSidebar");const ln=i(e=>process.stdout.write(`${e}
133
+ `),"rawLog"),S={message:i((e=[],{symbol:t=c.gray(A),secondarySymbol:n=c.gray(A),output:s=process.stdout,spacing:r=1}={})=>{const o=[];for(let l=0;l<r;l++)o.push(`${n}`);const a=Array.isArray(e)?e:e.split(`
134
+ `);if(a.length>0){const[l,...f]=a;l&&l.length>0?o.push(`${t} ${l}`):o.push(t);for(const d of f)d.length>0?o.push(`${n} ${d}`):o.push(n)}s.write(`${o.join(`
135
+ `)}
136
+ `)},"message"),info:i((e,t)=>{S.message(e,{...t,symbol:c.blue(qt)})},"info"),success:i((e,t)=>{S.message(e,{...t,symbol:c.green(Zt)})},"success"),step:i((e,t)=>{S.message(e,{...t,symbol:c.green(Vt)})},"step"),warn:i((e,t)=>{S.message(e,{...t,symbol:c.yellow(Qt)})},"warn"),error:i((e,t)=>{S.message(e,{...t,symbol:c.red(Xt)})},"error"),animated:i(async(e,{secondarySymbol:t=c.gray(A),output:n=process.stdout,clear:s=!1,...r}={})=>on(e,{sidebarSymbol:t,stdout:n,clear:s,...r}),"animated"),tasks:i(async(e,{spacing:t=1,secondarySymbol:n=c.gray(A),output:s=process.stdout,...r}={})=>cn(e,{sidebarSymbol:n,spacing:t,stdout:s,...r}),"tasks"),space:i((e=1)=>{for(let t=0;t<e;t++)process.stdout.write(`${c.gray(A)}
137
+ `)},"space"),break:i((e=1)=>{for(let t=0;t<e;t++)process.stdout.write(`
138
+ `)},"break")};function J(e){if(e instanceof p)S.space(1),we(e.message,{});else{const t=`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
139
+
140
+ If this issue persists, please report it: ${c.cyan("https://github.com/sugarcube-sh/sugarcube/issues")}`;S.space(1),we(t,{})}process.exit(1)}i(J,"handleError");function M(e,t=process.cwd()){try{const n=ht(t,"package.json");if(!D(n))return!1;const s=Ie(n,"utf-8"),r=JSON.parse(s),o={...r.dependencies,...r.devDependencies,...r.peerDependencies};return e in o}catch{return!1}}i(M,"isPackageInstalled");async function We(e,{withFallback:t=!1}={}){const n=await wt({programmatic:!0,cwd:e});if(n?.includes("yarn"))return"yarn";if(n?.includes("pnpm"))return"pnpm";if(n?.includes("bun"))return"bun";if(n?.includes("npm"))return"npm";if(t){const s=process.env.npm_config_user_agent||"";if(s.includes("yarn"))return"yarn";if(s.includes("pnpm"))return"pnpm";if(s.includes("bun"))return"bun"}return"npm"}i(We,"getPackageManager");const un=new U().name("components").description("Add components to your project").argument("[components...]","Components to add (e.g., button card)").option("-f, --framework <type>","Framework to use (react, css-only)").option("--components-dir <dir>","Components output directory (e.g., 'src/components')").option("-s, --silent","Suppress logs and prompts").option("-o, --overwrite","Overwrite existing files").action(async(e,t)=>{try{t.silent||H(Y(c.bgGreen(c.black("Components"))));const{directory:n}=await xt(t.componentsDir);let s=[],r;if(e.length>0||t.framework){if(!t.framework)throw new p(g.COMPONENTS_FRAMEWORK_REQUIRED());if(!["react","css-only"].includes(t.framework))throw new p(g.COMPONENTS_INVALID_FRAMEWORK());r=t.framework,s=e}else{r=await je(!1);const w=await G();w||(Ce("Failed to fetch component list"),process.exit(1)),s=await jt(w,r)}const o=await We(process.cwd(),{withFallback:!0}),a=await G(),l=await me(a,s,r),f=await Ft({selectedComponents:s,componentType:r,componentsOutputDirectory:n}),d=Ue(f);if(d&&!t.force&&!t.silent){const w=Ve(d,{});S.space(1),await Ge("Continue?",!1)}const u=[],m=[],h=new Set;for(const w of l){const k=w.dependencies?.[r]||[];for(const v of k)h.add(v)}const I=Array.from(h).filter(w=>!M(w,process.cwd()));I.length>0&&u.push({pending:`Install ${I.length} dependencies`,start:`Installing ${I.join(", ")}...`,end:`Installed ${I.join(", ")}`,while:i(async()=>{await te(I,process.cwd(),o)},"while")});for(const w of l)u.push({pending:`Write component files for ${w.name}`,start:`Writing component files for ${w.name}...`,end:`Wrote component files for ${w.name}`,while:i(async()=>{const k=await Ot({registryIndex:a,selectedComponents:[w.name],componentType:r,componentsOutputDirectory:n,overwrite:t.overwrite||!1,packageManager:o});m.push(...k.createdFiles)},"while")});await S.tasks(u,{successMessage:"Components added successfully! \u{1F389} ",minDurationMs:0,successAsOutro:!0}),ln("")}catch(n){J(n)}}),dn=new U().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").option("-f, --force","Skip overwrite confirmation").option("--cube-dir <dir>","CUBE CSS output directory (defaults to cssRoot)").action(async e=>{try{e.silent||H(Y("CUBE CSS"));const{directory:t}=await Gt(e.cubeDir);try{await W(t,{recursive:!0})}catch(o){const a=o instanceof Error?`: ${o.message}`:"";throw new p(`Failed to create output directory${a}`)}const n=await Nt({cubeDirectory:t}),s=Ue(n);if(s&&!e.force&&!e.silent){S.space(1);const o=Ve(s,{});await Ge("Continue?",!1)}const r=await Lt(t);if(!e.silent){S.space(1);const o=r,f=[...new Set(o)].map(d=>N(process.cwd(),d)).map(d=>({pending:`Write ${d}`,start:`Writing ${d}`,end:`Wrote ${d}`,while:i(async()=>{},"while")}));await S.tasks(f,{spacing:0,minDurationMs:0,successPauseMs:100,successMessage:"\u{1F389} Files written!"}),se(c.green("CUBE added successfully."))}}catch(t){J(t)}}),fn=`/* Generated by @sugarcube-sh/cli v${Oe.version} */
141
+
142
+ `,pn="**/*.{html,htm,js,ts,jsx,tsx,vue,svelte,astro,php,njk,liquid,pug,hbs,handlebars,twig,erb,ejs}",mn=["**/node_modules/**","**/dist/**","**/build/**","**/.next/**","**/.nuxt/**","**/.astro/**","**/.git/**","**/coverage/**","**/.pnpm/**","**/.pnpm-store/**","**/.npm/**","**/.cache/**","**/.turbo/**","**/.vercel/**","**/.svelte-kit/**","**/out/**","**/__snapshots__/**","**/*.config.{js,ts,mjs}","**/*.min.js","**/*.bundle.js","**/*.d.ts"],Ke=1e4,Ye=100;async function ze(e,t){const n={name:"sugarcube",rules:ct(t.utilities??{},e),preflights:[]},s=await yt({presets:[n]}),r=await ue([pn],{ignore:mn,dot:!1,onlyFiles:!0,absolute:!1});if(r.length===0)return[];if(r.length>Ke)throw new p(`Found ${r.length} files to scan (limit: ${Ke}). Are you running this from a monorepo root or a directory containing multiple projects? Run the command from within a single project directory instead.`);const o=[];let a=0;const l=Ye*1024*1024;for(const u of r){const m=await be(u,"utf8");if(a+=m.length,a>l)throw new p(`Total source size exceeds ${Ye}MB. Are you running this from a monorepo root or a directory containing multiple projects? Run the command from within a single project directory instead.`);o.push(m)}const f=o.join(`
143
+ `),{css:d}=await s.generate(f,{preflights:!1});return d?.trim()?[{path:`${t.output.utilities}/${t.output.utilitiesFilename}`,css:d}]:[]}i(ze,"generateSugarcubeUtilities");function He(e){return e.map(t=>({...t,css:fn+t.css}))}i(He,"addBanner");async function gn(e,t,n,s){const r=[],o=await oe(e,t,n),a=await ke(o,n,s),l=He(a);await Re(l),r.push(...l);const f=await ze(o,n),d=He(f);return await _e(d),r.push(...d),r}i(gn,"generateAllCSS");function hn(e){let t;(e.fluidMin||e.fluidMax)&&(t={min:e.fluidMin?Number.parseInt(e.fluidMin,10):320,max:e.fluidMax?Number.parseInt(e.fluidMax,10):1200});const n={resolver:e.resolver,output:{cssRoot:e.stylesDir,variables:e.variablesDir,variablesFilename:e.variablesFilename,utilities:e.utilitiesDir,utilitiesFilename:e.utilitiesFilename},transforms:{fluid:t,colorFallbackStrategy:e.colorFallback}};return $e(n)}i(hn,"buildConfigFromFlags");function wn(e,t){const n={min:t.fluidMin?Number.parseInt(t.fluidMin,10):e.transforms.fluid.min,max:t.fluidMax?Number.parseInt(t.fluidMax,10):e.transforms.fluid.max};return{...e,resolver:t.resolver??e.resolver,transforms:{fluid:n,colorFallbackStrategy:t.colorFallback??e.transforms.colorFallbackStrategy},output:{...e.output,cssRoot:t.stylesDir??e.output.cssRoot,variables:t.variablesDir??e.output.variables,variablesFilename:t.variablesFilename??e.output.variablesFilename,utilities:t.utilitiesDir??e.output.utilities,utilitiesFilename:t.utilitiesFilename??e.output.utilitiesFilename}}}i(wn,"mergeConfigWithFlags");function yn(e){return!!(e.resolver||e.stylesDir||e.variablesDir||e.variablesFilename||e.utilitiesDir||e.utilitiesFilename||e.fluidMin||e.fluidMax||e.colorFallback)}i(yn,"hasRelevantFlags");function Tn(e){if(e.colorFallback&&!["native","polyfill"].includes(e.colorFallback))throw new p(`Invalid --color-fallback value: "${e.colorFallback}". Must be "native" or "polyfill".`);if(e.fluidMin){const t=Number.parseInt(e.fluidMin,10);if(Number.isNaN(t)||t<=0)throw new p(`Invalid --fluid-min value: "${e.fluidMin}". Must be a positive number.`)}if(e.fluidMax){const t=Number.parseInt(e.fluidMax,10);if(Number.isNaN(t)||t<=0)throw new p(`Invalid --fluid-max value: "${e.fluidMax}". Must be a positive number.`)}}i(Tn,"validateFlags");async function Sn(e){if(ve()){const{config:s}=await ee();return wn(s,e)}const t=await re(process.cwd());if(t.found==="multiple")throw new p(g.GENERATE_MULTIPLE_RESOLVERS_NO_CONFIG(t.paths));const n=e.resolver??(t.found==="one"?t.path:void 0);if(n||yn(e))return hn({...e,resolver:n});throw new p(g.GENERATE_NO_CONFIG_OR_RESOLVER())}i(Sn,"resolveConfig");const In=new U().name("generate").description("Generate CSS from your design tokens").option("--force","Skip overwrite confirmation").option("-s, --silent","Suppress logs and prompts").option("--resolver <path>","Path to token resolver file (.resolver.json)").option("--styles-dir <dir>","CSS output directory (default: 'src/styles')").option("--variables-dir <dir>","Token variables output directory (default: 'src/styles/global')").option("--variables-filename <name>","Token variables filename (default: 'tokens.variables.gen.css')").option("--utilities-dir <dir>","Utilities output directory (default: 'src/styles/utilities')").option("--utilities-filename <name>","Utilities filename (default: 'utilities.gen.css')").option("--fluid-min <number>","Minimum viewport width for fluid scaling (default: 320)").option("--fluid-max <number>","Maximum viewport width for fluid scaling (default: 1200)").option("--color-fallback <strategy>","Color fallback strategy: 'native' or 'polyfill' (default: native)").action(async e=>{try{if(e.silent||H(Y("Generate CSS")),Tn(e),M("@sugarcube-sh/vite"))throw new p("Sugarcube vite plugin detected. When using the plugin, CSS is generated automatically during your build process. Remove the plugin to use CLI generation instead.");const t=await Sn(e),{trees:n,resolved:s,modifiers:r}=await K(t),o=await gn(n,s,t,r);if(!e.silent){const a=o.map(u=>u.path),d=[...new Set(a)].map(u=>N(process.cwd(),u)).map(u=>({pending:`Write ${u}`,start:`Writing ${u}`,end:`Wrote ${u}`,while:i(async()=>{},"while")}));await S.tasks(d,{spacing:1,minDurationMs:0,successPauseMs:100,successMessage:"\u{1F389} Files written!"}),S.space(1),se(c.green("CSS generated successfully."))}}catch(t){J(t)}});async function bn(e){const t={};return(e.stylesDir||e.variablesDir||e.variablesFilename||e.utilitiesDir||e.utilitiesFilename)&&(t.output={},e.stylesDir&&(t.output.cssRoot=e.stylesDir),e.variablesDir&&(t.output.variables=e.variablesDir),e.variablesFilename&&(t.output.variablesFilename=e.variablesFilename),e.utilitiesDir&&(t.output.utilities=e.utilitiesDir),e.utilitiesFilename&&(t.output.utilitiesFilename=e.utilitiesFilename)),(e.fluidMin!==void 0||e.colorFallback)&&(t.transforms={},e.fluidMin!==void 0&&e.fluidMax!==void 0&&(t.transforms.fluid={min:Number(e.fluidMin),max:Number(e.fluidMax)}),e.colorFallback&&(t.transforms.colorFallbackStrategy=e.colorFallback)),t}i(bn,"buildSugarcubeConfig");function Je(e){try{const t=le.resolve(e,"package.json");if(!D(t))return null;const n=Ie(t,"utf-8");return JSON.parse(n)}catch{return null}}i(Je,"getPackageJson");function P(e,t){if(!e)return!1;const n=e.dependencies,s=e.devDependencies;return!!(n?.[t]||s?.[t])}i(P,"hasDependency");function En(e,t){if(!e)return!1;const n=e.dependencies,s=e.devDependencies,r={...n,...s};return Object.keys(r).some(o=>o.startsWith(t))}i(En,"hasDependencyStartingWith");function vn(e){const t=D(le.resolve(e,"src")),n=Je(e),s=t?"src/design-tokens":"design-tokens",r=t?"src/styles":"styles",o=t?"src/components":"components";let a="none";return P(n,"next")?a=D(le.resolve(e,`${t?"src/":""}app`))?"next-app":"next-pages":P(n,"astro")?a="astro":P(n,"nuxt")?a="nuxt":P(n,"@sveltejs/kit")?a="sveltekit":En(n,"@remix-run/")?a="remix":P(n,"@11ty/eleventy")?a="eleventy":P(n,"vite")&&(a="vite"),{framework:a,isSrcDir:t,tokensDir:s,stylesDir:r,componentDir:o}}i(vn,"getProjectInfo");function kn(e,t){if(["vite","astro","nuxt","sveltekit","remix"].includes(e))return!0;if(e==="eleventy"){const s=Je(t);return P(s,"vite")}return!1}i(kn,"shouldInstallVitePlugin");function qe(e,t=0){if(typeof e!="object"||e===null||t>vt)return!1;for(const[n,s]of Object.entries(e))if(!n.startsWith("$")&&typeof s=="object"&&s!==null&&("$value"in s||qe(s,t+1)))return!0;return!1}i(qe,"hasAnyToken");async function Rn(e){try{const t=await ue([It],{cwd:e,absolute:!0});for(const n of t)try{const s=await ie.readFile(n,"utf-8"),r=JSON.parse(s);if(qe(r))return!0}catch{}return!1}catch{return!1}}i(Rn,"detectExistingTokens");function _n(e=process.cwd()){return Tt(e)!==null}i(_n,"isTypeScriptProject");async function Ze(e=process.cwd()){return _n(e)?"sugarcube.config.ts":"sugarcube.config.js"}i(Ze,"getConfigFileName");function $n(e){return/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(e)}i($n,"isValidIdentifier");function ye(e,t=0){const n=" ".repeat(t);if(e===null)return"null";if(e===void 0)return"undefined";if(typeof e=="string")return JSON.stringify(e);if(typeof e=="number"||typeof e=="boolean")return String(e);if(Array.isArray(e))return e.length===0?"[]":`[
144
+ ${e.map(r=>`${n} ${ye(r,t+1)}`).join(`,
145
+ `)}
146
+ ${n}]`;if(typeof e=="object"){const s=Object.entries(e);return s.length===0?"{}":`{
147
+ ${s.map(([o,a])=>{const l=$n(o)?o:JSON.stringify(o);return`${n} ${l}: ${ye(a,t+1)}`}).join(`,
148
+ `)}
149
+ ${n}}`}return JSON.stringify(e)}i(ye,"formatValue");function Cn(e,t){const n=ye(e,0);return t?`import { defineConfig } from "${t}";
150
+
151
+ export default defineConfig(${n});
152
+ `:`${`// Configuration reference: ${_.CONFIGURATION}
153
+ export default `}${n};
154
+ `}i(Cn,"formatConfigAsCode");async function Fn(e,t){try{const n=await Ze(),s=Cn(e,t);await X(n,s,"utf-8")}catch(n){const s=n instanceof Error?`: ${n.message}`:"";throw new p(`Failed to write config file${s}`)}}i(Fn,"writeSugarcubeConfig");const Nn=i(async e=>{S.space(2),await B(200);let t="Next steps";if(e.pluginToInstall===Ae)t+=`
155
+
156
+ `,t+=`1. Configure the plugin
157
+ `,t+=` Add the plugin to your build configuration:
158
+ `,t+=` ${c.cyan("e.g. vite.config.ts or astro.config.mjs")}
159
+ `,t+=` ${c.dim("plugins: [sugarcube()]")}`,t+=`
160
+
161
+ `,t+=`2. Import the generated CSS
162
+ `,t+=` ${c.cyan("import 'virtual:sugarcube.css'")}
163
+ `,t+=`
164
+
165
+ `,t+=`3. (Optional) Add CUBE CSS
166
+ `,t+=` ${c.cyan(O.CUBE)}`,t+=`
167
+
168
+ `,t+=`4. (Optional) Add components
169
+ `,t+=` ${c.cyan(O.COMPONENTS)}`;else{const n=`${e.stylesDir}/global/${ae.output.variablesFilename}`;t+=`
170
+
171
+ `,t+=`1. Import the generated CSS
172
+ `;const s=e.isSrcDir?`"${n}"`:`"./${n}"`;t+=` ${c.cyan(`import ${s}`)}`,t+=`
173
+
174
+ `,t+=`2. (Optional) Add CUBE CSS
175
+ `,t+=` ${c.cyan(O.CUBE)}`,t+=`
176
+
177
+ `,t+=`3. (Optional) Add components
178
+ `,t+=` ${c.cyan(O.COMPONENTS)}`}t+=`
179
+
180
+ `,t+=`Docs: ${c.cyan("https://sugarcube.sh")}`,sn(t,{width:.75}),await B(200),S.break(1)},"nextSteps");async function Dn(e){await Nn(e)}i(Dn,"next");const On=i(async()=>{const e=["Welcome to sugarcube \u2014 the toolkit for seriously sweet frontends!"];S.space(1),await S.animated(e,{clear:!1})},"welcome");function Qe(e,t){if(!e||e.trim()==="")throw new p(g.DIRECTORY_PATH_EMPTY(t));const s=rt(e).split("/")[0];if(s&&Et.includes(s))throw new p(g.DIRECTORY_PATH_RESERVED(t,e))}i(Qe,"validateDirectoryPath");function An(e){e.tokensDir&&Qe(e.tokensDir,"tokens-dir"),e.stylesDir&&Qe(e.stylesDir,"styles-dir");const t=e.fluidMin!==void 0,n=e.fluidMax!==void 0;if(t!==n)throw new p(`Both --fluid-min and --fluid-max must be provided together.
181
+
182
+ Either specify both flags or omit both to use defaults (320px - 1200px).`)}i(An,"validateOptions");async function Ln(){ve()&&(we(g.CONFIG_EXISTS(),{}),process.exit(1))}i(Ln,"preflightInit");async function Mn(e){const t=vn(process.cwd()),n=e.tokensDir||t.tokensDir,s=e.stylesDir||t.stylesDir,r=await Rn(n);let o=null;if(r){const a=await re(n);if(a.found==="none")throw new p(g.RESOLVER_NOT_FOUND(n));if(a.found==="multiple")throw new p(g.RESOLVER_MULTIPLE_FOUND(a.paths));o=a.path}return{tokensDir:n,stylesDir:s,isSrcDir:t.isSrcDir,hasExistingTokens:r,resolverPath:o,framework:t.framework}}i(Mn,"initializeProjectContext");function Pn(e,t,n){const s=t?null:e.kit||de;if(e.skipDeps)return{starterKit:s,pluginToInstall:null,cliToInstall:null};const r=Un(n,process.cwd());return{starterKit:s,pluginToInstall:r,cliToInstall:r?null:bt}}i(Pn,"determineInstallationTargets");function Un(e,t){return kn(e,t)?Ae:null}i(Un,"determinePlugin");async function jn(e,t,n,s,r){const o=await We(process.cwd(),{withFallback:!0});return t.resolverPath&&(n.resolver=t.resolverPath),{options:e,...t,isSrcDir:t.isSrcDir,config:n,sugarcubeConfig:s,...r,packageManager:o,createdFiles:[],createdDirectories:[],installedDependencies:[],tasks:[]}}i(jn,"buildInitContext");async function Gn(e){const{trees:t,resolved:n}=await K(e.config);e.setupResult={config:e.config,createdTokenPaths:[],trees:t,resolved:n,tokenFiles:[],tokensDir:e.tokensDir}}i(Gn,"processExistingTokens");async function xn(e){!e.hasExistingTokens&&e.starterKit?await Ut(e):await Gn(e)}i(xn,"setupDesignTokens");async function Bn(e){if(!e.setupResult)throw new p(g.INITIALIZATION_INCOMPLETE());const{trees:t,resolved:n}=e.setupResult,s=await oe(t,n,e.config),r=await ke(s,e.config);await Re(r)}i(Bn,"writeCSSVariables");async function Vn(e){if(!e.setupResult)throw new p(g.INITIALIZATION_INCOMPLETE());const{trees:t,resolved:n}=e.setupResult,s=await oe(t,n,e.config),r=await ze(s,e.config);r.length&&await _e(r)}i(Vn,"writeCSSUtilities");async function Wn(e){if(e.pluginToInstall&&!M(e.pluginToInstall))try{await te([e.pluginToInstall],process.cwd(),e.packageManager,{devDependency:!0}),e.installedDependencies.push(e.pluginToInstall)}catch{throw new p(g.PLUGIN_INSTALL_FAILED({pluginToInstall:e.pluginToInstall,packageManager:e.packageManager}))}}i(Wn,"installPlugins");async function Kn(e){if(e.cliToInstall&&!M(e.cliToInstall))try{await te([e.cliToInstall],process.cwd(),e.packageManager,{devDependency:!0}),e.installedDependencies.push(e.cliToInstall)}catch{throw new p(g.CLI_INSTALL_FAILED({packageManager:e.packageManager}))}}i(Kn,"installCLI");function Xe(e){return!!(e.stylesDir||e.variablesDir||e.variablesFilename||e.utilitiesDir||e.utilitiesFilename||e.fluidMin||e.fluidMax||e.colorFallback)}i(Xe,"hasCustomizationFlags");function Yn(e){return e.pluginToInstall?"@sugarcube-sh/vite":e.cliToInstall?"@sugarcube-sh/cli":null}i(Yn,"getTypeSource");async function et(e){if(Xe(e.options))try{await Fn(e.sugarcubeConfig,Yn(e));const t=await Ze();e.createdFiles.push(t)}catch{throw new p(g.CONFIG_WRITE_FAILED())}}i(et,"finalize");function zn(e){const t=[];if(e.hasExistingTokens?t.push({pending:"Looking for existing tokens",start:"Looking for existing tokens...",end:`Existing tokens found at ${e.tokensDir} ${b("\u2192","->")} using them`,while:i(async()=>{},"while")}):e.starterKit&&t.push({pending:"Looking for existing tokens",start:"Looking for existing tokens...",end:`No existing tokens detected ${b("\u2192","->")} adding starter kit`,while:i(async()=>{},"while")}),e.pluginToInstall){const n="Vite";M(e.pluginToInstall)?t.push({pending:`Checking for ${n} compatibility`,start:`Checking for ${n} compatibility...`,end:`${n} plugin already installed ${b("\u2192","->")} skipping plugin installation`,while:i(async()=>{},"while")}):t.push({pending:"Checking for Vite compatibility",start:"Checking for Vite compatibility...",end:`Vite detected ${b("\u2192","->")} plugin will be installed`,while:i(async()=>{},"while")})}else{const n=e.options.skipDeps;t.push({pending:"Checking for Vite compatibility",start:"Checking for Vite compatibility...",end:n?`Dependencies skipped ${b("\u2192","->")} no plugins or CLI will be installed`:`No Vite detected ${b("\u2192","->")} CSS will be generated as file(s)`,while:i(async()=>{},"while")})}return t}i(zn,"buildDetectionTasks");async function Hn(e){if(e.tasks.push({pending:e.hasExistingTokens?"Process existing design tokens":"Add design tokens",start:e.hasExistingTokens?"Processing existing design tokens...":"Adding design tokens...",end:e.hasExistingTokens?"Design tokens processed":"Design tokens added",while:i(async()=>{await xn(e)},"while")}),!e.pluginToInstall)e.tasks.push({pending:"Generate CSS variables",start:"Generating CSS variables...",end:"CSS variables generated",while:i(async()=>{await Bn(e)},"while")}),e.tasks.push({pending:"Generate CSS utilities",start:"Generating CSS utilities...",end:"CSS utilities generated",while:i(async()=>{await Vn(e)},"while")}),e.cliToInstall&&!M(e.cliToInstall)&&e.tasks.push({pending:"Install CLI",start:"Installing CLI...",end:"CLI installed",while:i(async()=>{await Kn(e)},"while")});else if(e.pluginToInstall&&!M(e.pluginToInstall)){const t="Vite";e.tasks.push({pending:`Install ${t} plugin`,start:`Installing ${t} plugin...`,end:`${t} plugin installed`,while:i(async()=>{await Wn(e)},"while")})}Xe(e.options)?e.tasks.push({pending:"Write configuration file",start:"Writing configuration file...",end:"Configuration file written",while:i(async()=>{await et(e)},"while")}):e.tasks.push({pending:"Finalize setup",start:"Finalizing...",end:"Setup complete",while:i(async()=>{await et(e)},"while")})}i(Hn,"buildExecutionTasks");const Jn=new U().name("init").description("Initialize a new sugarcube project").option("--kit <kit>",`Starter kit to use (default: ${de})`,de).option("--tokens-dir <dir>","Design tokens directory (e.g., 'src/design-tokens')").option("--styles-dir <dir>","Styles output directory (e.g., 'src/styles')").option("--variables-dir <dir>","Token variables directory (e.g., 'src/styles/global')").option("--variables-filename <name>","Token variables filename (default: 'tokens.variables.gen.css')").option("--utilities-dir <dir>","Utilities directory (e.g., 'src/styles/utilities')").option("--utilities-filename <name>","Utilities filename (default: 'utilities.gen.css')").option("--fluid-min <number>","Minimum viewport width for fluid scaling (default: 320)").option("--fluid-max <number>","Maximum viewport width for fluid scaling (default: 1200)").option("--color-fallback <strategy>","Color fallback strategy: 'native' or 'polyfill' (default: native)").option("--skip-deps","Don't install any sugarcube packages").action(async e=>{let t;try{An(e),await Ln();const n=await Mn(e),s=await bn(e),r=$e(s),o=Pn(e,n.hasExistingTokens,n.framework);t=await jn(e,n,r,s,o),H(Y("sugarcube")),await On();const a=zn(t);a.length>0&&(S.message("Detecting project\u2026"),await S.tasks(a,{minDurationMs:1e3})),t.tasks=[],await Hn(t),t.tasks.length>0&&(S.message("Setting things up\u2026"),await S.tasks(t.tasks,{successMessage:"\u{1F389} Tasks completed successfully!"})),await Dn(t)}catch(n){J(n)}}),qn=new U().name("validate").description("Validate design token files").argument("[paths...]","Token files or directories to validate (e.g., src/design-tokens)").action(async e=>{try{if(H(Y("Validate")),!e.length)try{const{config:o}=await ee();await K(o),se(c.greenBright("All tokens valid \u2728"));return}catch{throw new p(g.VALIDATE_NO_PATH_SPECIFIED())}for(const o of e)if(!D(o))throw new p(g.VALIDATE_PATH_NOT_FOUND(o));const n=(await ue(e.map(o=>o.endsWith(".json")?o:R(o,"**/*.json")),{absolute:!0})).filter(o=>!o.endsWith(".resolver.json"));if(n.length===0)throw new p(g.VALIDATE_NO_TOKEN_FILES());const s={};for(const o of n){const a=await be(o,"utf-8"),l=N(process.cwd(),o);s[l]={content:a}}const r={output:ae.output,transforms:ae.transforms};await K(r,s),se(c.greenBright("All tokens valid \u2728"))}catch(t){J(t)}});process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function Zn(){const e=new U().name("sugarcube").description("CLI for sugarcube").version(Oe.version,"-v, --version","display the version number");e.addCommand(Jn).addCommand(In).addCommand(qn).addCommand(un).addCommand(dn),e.parse()}i(Zn,"main"),Zn();
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@sugarcube-sh/cli",
3
+ "version": "0.0.2",
4
+ "publishConfig": {
5
+ "access": "public",
6
+ "provenance": false
7
+ },
8
+ "description": "CLI for sugarcube",
9
+ "license": "MIT",
10
+ "author": {
11
+ "name": "Mark Tomlinson",
12
+ "email": "mark@marktomlinson.dev",
13
+ "url": "https://marktomlinson.dev"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/sugarcube-sh/sugarcube"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/sugarcube-sh/sugarcube/issues"
21
+ },
22
+ "keywords": [
23
+ "cli",
24
+ "design-system",
25
+ "components",
26
+ "CUBE CSS",
27
+ "react",
28
+ "sugarcube"
29
+ ],
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE.md"
34
+ ],
35
+ "type": "module",
36
+ "main": "./dist/index.mjs",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/exports.d.mts",
40
+ "import": "./dist/exports.mjs"
41
+ }
42
+ },
43
+ "bin": {
44
+ "sugarcube": "./dist/index.mjs"
45
+ },
46
+ "dependencies": {
47
+ "@antfu/ni": "23.3.0",
48
+ "@clack/core": "1.0.0-alpha.3",
49
+ "@clack/prompts": "1.0.0-alpha.3",
50
+ "@unocss/core": "66.5.2",
51
+ "commander": "12.1.0",
52
+ "execa": "9.5.2",
53
+ "fast-wrap-ansi": "0.1.3",
54
+ "get-tsconfig": "4.7.2",
55
+ "is-unicode-supported": "2.1.0",
56
+ "log-update": "6.1.0",
57
+ "pathe": "2.0.3",
58
+ "picocolors": "1.1.1",
59
+ "tinyglobby": "^0.2.9",
60
+ "zod": "^3.23.8",
61
+ "@sugarcube-sh/core": "0.0.2"
62
+ },
63
+ "devDependencies": {
64
+ "cross-env": "7.0.3",
65
+ "pkgroll": "^2.26.0",
66
+ "tsx": "^4.21.0"
67
+ },
68
+ "engines": {
69
+ "node": ">=18.0.0"
70
+ },
71
+ "scripts": {
72
+ "build": "tsc --noEmit && pkgroll --minify",
73
+ "dev": "cross-env REGISTRY_URL=http://localhost:4321/r tsx src/index.ts",
74
+ "test": "vitest run --exclude 'tests/e2e/**'",
75
+ "test:e2e": "vitest run tests/e2e",
76
+ "test:watch": "vitest --exclude 'tests/e2e/**'",
77
+ "type-check": "tsc --noEmit",
78
+ "start": "cross-env REGISTRY_URL=https://sugarcube.sh/r tsx src/index.ts"
79
+ }
80
+ }