@sugarcube-org/cli
Version:
A CLI for scaffolding sugarcube applications
181 lines (132 loc) • 47.6 kB
JavaScript
var et=Object.defineProperty;var r=(e,t)=>et(e,"name",{value:t,configurable:!0});import{Command as P}from"commander";import{relative as D,join as R,basename as ye,resolve as U,dirname as tt,isAbsolute as nt,normalize as st}from"pathe";import c from"picocolors";import{existsSync as N,readFileSync as Te}from"node:fs";import{z as y}from"zod";import se,{mkdir as V,writeFile as Q,readFile as Ie}from"node:fs/promises";import{execa as rt}from"execa";import{loadAndResolveTokens as it,findResolverDocument as re,loadInternalConfig as X,isNoConfigError as be,configFileExists as Se,processAndConvertTokens as ie,generateCSSVariables as Ee,writeCSSVariablesToDisk as ke,writeCSSUtilitiesToDisk as ve,fillDefaults as Re,convertConfigToUnoRules as ot,DEFAULT_CONFIG as _e}from"@sugarcube-org/core";import{select as at,isCancel as oe,log as ct,multiselect as lt,confirm as ut,cancel as $e}from"@clack/prompts";import{getColumns as dt}from"@clack/core";import{wrapAnsi as ft}from"fast-wrap-ansi";import pt from"is-unicode-supported";import*as Ce from"node:readline";import De from"node:readline";import{createLogUpdate as Ne}from"log-update";import ae,{resolve as mt}from"node:path";import{detect as gt}from"@antfu/ni";import{createGenerator as ht}from"@unocss/core";import{glob as ce}from"tinyglobby";import{getTsconfig as wt}from"get-tsconfig";var yt="0.0.0-alpha.38",Tt={version:yt};const le="fluid",It="**/*.json",Fe="@sugarcube-org/vite",bt="@sugarcube-org/cli",St=["node_modules",".git",".next","dist","build"],Et=5,F={INIT:"make-sugarcube init",COMPONENTS:"make-sugarcube components",CUBE:"make-sugarcube cube"},Oe={INITIALIZATION:"https://sugarcube.sh/docs/setup",CONFIGURATION:"https://sugarcube.sh/docs/configuration"},g={PROJECT_REQUIRED:`No sugarcube project detected. Please run ${c.cyan(F.INIT)} first.
For more information, visit: ${c.cyan(Oe.INITIALIZATION)}`,CONFIG_EXISTS:r(()=>`A sugarcube config file already exists in this project.
To start over, remove it and run ${c.cyan(F.INIT)} again.`,"CONFIG_EXISTS"),PLUGIN_INSTALL_FAILED:r(e=>{const t=e.packageManager==="npm"?"install":"add";return`Failed to install ${e.pluginToInstall} plugin.
This is usually a temporary issue. Try these steps:
1. Run the command again
2. Check your internet connection
3. Install manually: ${e.packageManager} ${t} ${e.pluginToInstall}
If the problem continues, please open an issue at:
https://github.com/sugarcube-org/sugarcube/issues`},"PLUGIN_INSTALL_FAILED"),CLI_INSTALL_FAILED:r(e=>{const t=e.packageManager==="npm"?"install":"add";return`Failed to install @sugarcube-org/cli.
This is usually a temporary issue. Try these steps:
1. Run the command again
2. Check your internet connection
3. Install manually: ${e.packageManager} ${t} -D @sugarcube-org/cli
If the problem continues, please open an issue at:
https://github.com/sugarcube-org/sugarcube/issues`},"CLI_INSTALL_FAILED"),INITIALIZATION_INCOMPLETE:r(()=>`The initialization process was not completed properly.
This is an internal error that should not occur.
Try running the \`init\` command again.
If the problem persists, please report this issue at
https://github.com/sugarcube-org/sugarcube/issues`,"INITIALIZATION_INCOMPLETE"),CONFIG_WRITE_FAILED:r(()=>"Failed to write configuration file. Check permissions and try again.","CONFIG_WRITE_FAILED"),DIRECTORY_PATH_EMPTY:r(e=>`${e} cannot be empty. Please provide a valid directory path.`,"DIRECTORY_PATH_EMPTY"),DIRECTORY_PATH_RESERVED:r((e,t)=>`Option: ${e}
Value: "${t}"
${e} cannot be in a reserved directory`,"DIRECTORY_PATH_RESERVED"),KIT_INCOMPLETE:r(()=>`The starter kit appears to be incomplete or corrupted.
This is likely a temporary issue. Please try running the command again or choose a different starter kit.`,"KIT_INCOMPLETE"),REGISTRY_AUTH_REQUIRED:r(e=>`Registry access denied: Authentication required
URL: ${c.cyan(e)}`,"REGISTRY_AUTH_REQUIRED"),REGISTRY_AUTH_INVALID:r(e=>`Registry access denied: Invalid or missing token
URL: ${c.cyan(e)}`,"REGISTRY_AUTH_INVALID"),REGISTRY_NOT_FOUND:r(e=>`Registry resource not found
URL: ${c.cyan(e)}`,"REGISTRY_NOT_FOUND"),REGISTRY_REQUEST_FAILED:r((e,t)=>`Registry request failed: ${e}
URL: ${c.cyan(t)}`,"REGISTRY_REQUEST_FAILED"),REGISTRY_NETWORK_ERROR:r(e=>`Failed to connect to registry
URL: ${c.cyan(e)}
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:r(e=>`Invalid registry data received
URL: ${c.cyan(e)}`,"REGISTRY_INVALID_DATA"),REGISTRY_ITEM_NOT_FOUND:r((e,t,n)=>`${e==="tokens"?"Starter kit":e}'${c.cyan(t)} ' not found in registry
Available ${e==="tokens"?"starter kit":e}s: ${n.join(", ")}`,"REGISTRY_ITEM_NOT_FOUND"),REGISTRY_FILE_INVALID:r(e=>`Invalid file content received
File: ${c.cyan(e)}`,"REGISTRY_FILE_INVALID"),STARTER_KIT_UNAVAILABLE:r(e=>`Starter kit '${c.cyan(e)}' is currently unavailable.
Please try a different starter kit or run the command again in a few minutes.`,"STARTER_KIT_UNAVAILABLE"),RESOLVER_NOT_CONFIGURED:r(()=>`No resolver path configured.
Add a resolver path to your sugarcube config:
${c.cyan(`export default {
resolver: "./tokens.resolver.json",
// ...
}`)}
See ${c.cyan("https://sugarcube.sh/docs/resolver")} for more information.`,"RESOLVER_NOT_CONFIGURED"),RESOLVER_NOT_FOUND:r(e=>`No resolver document found in ${c.cyan(e)}.
A resolver document (*.resolver.json) is required to define how your tokens are loaded.
See ${c.cyan("https://sugarcube.sh/docs/resolver")} to learn how to create one.`,"RESOLVER_NOT_FOUND"),RESOLVER_MULTIPLE_FOUND:r(e=>`Multiple resolver documents found:
${e.map(t=>` - ${c.cyan(t)}`).join(`
`)}
A project should have only one resolver document. Please remove the extras or consolidate them.`,"RESOLVER_MULTIPLE_FOUND"),TOKEN_LOAD_FAILED:r(e=>`Failed to load token files:
${e.join(`
`)}
Please check your token files and try again.`,"TOKEN_LOAD_FAILED"),TOKEN_VALIDATION_FAILED:r(e=>{let t=`Token validation failed:
`;for(const[n,s]of e){t+=`Error(s) in ${c.cyan(n)}:
`;for(const i of s)t+=` - ${i}
`;t+=`
`}return t+=`See ${c.cyan("https://sugarcube.sh/docs/design-tokens")} for valid token formats`,t},"TOKEN_VALIDATION_FAILED"),TOKEN_FILE_INVALID_JSON:r(e=>`File ${e}: Invalid JSON syntax`,"TOKEN_FILE_INVALID_JSON"),TOKEN_FILE_INCOMPLETE_JSON:r(e=>`File ${e}: Incomplete JSON file`,"TOKEN_FILE_INCOMPLETE_JSON"),TOKEN_FILE_GENERIC_ERROR:r((e,t)=>`File ${e}: ${t}`,"TOKEN_FILE_GENERIC_ERROR"),DEPENDENCY_INSTALL_FAILED:r(e=>`Failed to install dependencies using ${e}.
Please check your package manager configuration and try again.`,"DEPENDENCY_INSTALL_FAILED"),VALIDATE_NO_PATH_SPECIFIED:r(()=>`No path specified.
Run ${c.cyan("make-sugarcube validate --help")} for more information.`,"VALIDATE_NO_PATH_SPECIFIED"),VALIDATE_PATH_NOT_FOUND:r(e=>`Path not found: ${e}
Please check that the specified path exists`,"VALIDATE_PATH_NOT_FOUND"),VALIDATE_NO_TOKEN_FILES:r(()=>`No token files found.
Please ensure the path contains .json token files`,"VALIDATE_NO_TOKEN_FILES"),COMPONENTS_FRAMEWORK_REQUIRED:r(()=>`Framework is required when specifying components. Use --framework to specify a framework (react, css-only) or run without arguments for interactive mode.
See ${c.cyan("https://sugarcube.sh/docs/cli/components")} for more information.`,"COMPONENTS_FRAMEWORK_REQUIRED"),COMPONENTS_INVALID_FRAMEWORK:r(()=>"Invalid framework. Must be one of: react, css-only.","COMPONENTS_INVALID_FRAMEWORK"),COMPONENTS_DIRECTORY_NOT_CONFIGURED:r(()=>"Components directory must be configured in non-interactive mode. Please run the 'components' command without arguments first.","COMPONENTS_DIRECTORY_NOT_CONFIGURED"),PLUGIN_DETECTED:r(e=>`Plugin detected: ${e}
The 'generate' command is for manual generation without plugins. Since you have a plugin installed, use your development server instead:
npm run dev # or your framework's dev command
The plugin will automatically generate CSS with hot module replacement.`,"PLUGIN_DETECTED"),GENERATE_NO_CONFIG_OR_RESOLVER:r(()=>`No design tokens found.
Run ${c.cyan(F.INIT)} to set up your design tokens.
Stuck? ${c.cyan("https://sugarcube.sh")}`,"GENERATE_NO_CONFIG_OR_RESOLVER"),GENERATE_MULTIPLE_RESOLVERS_NO_CONFIG:r(e=>`No config file found, but multiple resolver files detected:
${e.map(t=>` - ${t}`).join(`
`)}
Please either:
- Create a config file with ${c.cyan(F.INIT)}
- Use --resolver flag to specify which resolver to use`,"GENERATE_MULTIPLE_RESOLVERS_NO_CONFIG")};class p extends Error{static{r(this,"CLIError")}constructor(t,n){super(t),this.name="CLIError",this.cause=n}}const ue=y.enum(["react","web-components","css-only"]),Ae=y.object({path:y.string(),type:y.string()}),kt=Ae.extend({framework:ue}),vt=y.object({name:y.string(),type:y.string(),description:y.string().optional(),frameworks:y.array(y.string()).optional(),files:y.array(y.union([kt,Ae])),tokens:y.record(y.object({type:y.string(),mapping:y.string()})).optional(),dependencies:y.record(ue,y.array(y.string())).optional(),registryDependencies:y.record(ue,y.array(y.string())).optional(),tokenDependencies:y.array(y.string()).optional()}),Rt=y.array(vt),_t=y.object({content:y.string()}),Le=process.env.REGISTRY_URL??"https://sugarcube.sh/r";async function Me(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))}}r(Me,"fetchRegistry");async function j(){const e=`${Le}/index.json`,t=await Me(e);try{return Rt.parse(t)}catch{throw new p(g.REGISTRY_INVALID_DATA(e))}}r(j,"getRegistryIndex");async function de({type:e,name:t,framework:n}){const s=await j(),i=s.find(l=>l.type===e&&l.name===t);if(!i){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=i.files;e==="component"&&n&&(o=i.files.filter(l=>"framework"in l&&l.framework===n));const a=await Promise.all(o.map(async l=>{const f=`${Le}/${l.path}.json`,d=await Me(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:i,files:a}}r(de,"getRegistryFiles");async function $t(e){const t=await de({type:"tokens",name:e});if(!t.files[0])throw new p(g.STARTER_KIT_UNAVAILABLE(e));return t}r($t,"fetchStarterKit");async function fe(e,t,n){const s=[],i=new Set;async function o(a){if(i.has(a))return;i.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
Available components: ${d}`)}const f=l.registryDependencies?.[n]||[];for(const d of f)await o(d);s.push(l)}r(o,"resolveComponent");for(const a of t)await o(a);return s}r(fe,"resolveTree");async function Ct({selectedComponents:e,componentType:t,componentsOutputDirectory:n}){const s={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},i=await j(),a=(await fe(i,e,t)).map(u=>u.name),l=i.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=>D(process.cwd(),R(n,u.name,`${u.name}.${m.type}`))));s.componentFiles=f.filter(u=>N(R(process.cwd(),u)));const d=l.map(u=>{const m=u.name;return D(process.cwd(),R(n,u.name,`${m}.css`))});return s.componentCSS=d.filter(u=>N(R(process.cwd(),u))),s}r(Ct,"collectComponentOverwriteWarnings");async function Dt({cubeDirectory:e}){const t={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},s=(await j()).filter(i=>i.type==="cube").flatMap(i=>i.files).map(i=>{const o=i.path.replace(/^styles\//,"");return D(process.cwd(),R(e,o))});return t.cubeCSS=s.filter(i=>N(R(process.cwd(),i))),t}r(Dt,"collectCubeOverwriteWarnings");function Pe(e){const t=[];if(e.variableCSS.length>0&&t.push(`CSS variables files:
${e.variableCSS.map(s=>` - ${s}`).join(`
`)}`),e.utilityCSS.length>0&&t.push(`CSS utility files:
${e.utilityCSS.map(s=>` - ${s}`).join(`
`)}`),e.cubeCSS.length>0&&t.push(`CUBE CSS files:
${e.cubeCSS.map(s=>` - ${s}`).join(`
`)}`),e.componentFiles.length>0||e.componentCSS.length>0){const s=[...e.componentFiles,...e.componentCSS];t.push(`Component files:
${s.map(i=>` - ${i}`).join(`
`)}`)}return e.indexFiles.length>0&&t.push(`Index files:
${e.indexFiles.map(s=>` - ${s}`).join(`
`)}`),t.length===0?void 0:`The following file(s) already exist and will be overwritten:
${t.join(`
`)}`}r(Pe,"formatOverwriteWarnings");async function ee(e,t,n,s={}){if(e.length===0)return;const{devDependency:i=!1}=s,o=n==="npm"?"install":"add",a=(()=>{if(!i)return[];switch(n){case"npm":return["--save-dev"];case"pnpm":return["-D"];case"yarn":return["-D"];case"bun":return["-d"]}})();try{await rt(n,[o,...a,...e],{cwd:t})}catch{throw new p(g.DEPENDENCY_INSTALL_FAILED(n))}}r(ee,"installDependencies");async function Nt(e,t,n){const s=R(n,t.name);if(await V(s,{recursive:!0}),e.path.endsWith(".css")){const o=R(s,`${t.name}.css`);return await Q(o,e.content),o}const i=R(s,ye(e.path));return await Q(i,e.content),i}r(Nt,"writeComponentFile");async function Ft({registryIndex:e,selectedComponents:t,componentType:n,componentsOutputDirectory:s,packageManager:i}){const o=[],a=new Set;await V(s,{recursive:!0});const l=await fe(e,t,n);for(const f of l){const d=await de({type:"component",name:f.name,framework:n});for(const m of d.files)if(m)try{const h=await Nt(m,f,s);h&&o.push(h)}catch(h){const b=h instanceof Error?`: ${h.message}`:"";throw new p(`Failed to write component file for "${f.name}"${b}`)}const u=f.dependencies?.[n]||[];for(const m of u)a.add(m)}if(a.size>0)try{await ee(Array.from(a),process.cwd(),i)}catch(f){const d=f instanceof Error?`: ${f.message}`:"";throw new p(`Failed to install component dependencies${d}`)}return{createdFiles:o,npmDependencies:a}}r(Ft,"installComponents");function Ot(e,t){const n=U(e),s=U(t),i=D(s,n);return!i.startsWith("..")&&!nt(i)}r(Ot,"isWithinDirectory");async function At(e){const t=[],n=U(process.cwd(),e);await V(n,{recursive:!0});const i=(await j()).filter(o=>o.type==="cube").map(o=>o.name);for(const o of i){const a=await de({type:"cube",name:o});for(const l of a.files){if(!l)continue;const f=l.path.replace(/^styles\//,""),d=U(n,f);if(!Ot(d,n))throw new p(`Invalid file path detected in CUBE module "${o}": path escapes target directory`);const u=tt(d);try{await V(u,{recursive:!0}),await Q(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}r(At,"installCUBE");async function Lt(e,t){await se.mkdir(t,{recursive:!0});const n=[];for(const s of e)await se.writeFile(s.path,s.content),n.push(s.path);return n}r(Lt,"writeTokenFiles");async function W(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:i,modifiers:o,errors:a}=await it(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:i,modifiers:o}}r(W,"loadAndResolveTokensForCLI");const Mt=r(async(e,t,n)=>{const s=await $t(e),i=U(process.cwd(),t),o=s.files.map(a=>({path:R(i,ye(a.path)),content:a.content}));return{config:n,tokenFiles:o,tokensDir:i,createdTokenPaths:o.map(a=>D(process.cwd(),a.path))}},"prepareStarterKitForInstall");async function Pt(e){const t=await Mt(e.starterKit??"",e.tokensDir,e.config),n=await Lt(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 i={...e.config,resolver:s.path},{trees:o,resolved:a}=await W(i);e.setupResult={config:i,createdTokenPaths:t.createdTokenPaths,trees:o,resolved:a,tokenFiles:t.tokenFiles,tokensDir:t.tokensDir},e.createdFiles.push(...n),e.config=i,e.sugarcubeConfig={...e.sugarcubeConfig,resolver:s.path}}r(Pt,"installFromStarterKit");async function Ue(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 at({message:"Build with",options:t});return oe(n)&&process.exit(0),n==="web-components"?(ct.info(c.blue("Web components are coming soon! Please choose React or CSS Only for now.")),Ue(e)):n}r(Ue,"promptComponentFramework");async function Ut(e,t){const n=e.filter(i=>i.type==="component"&&i.frameworks?.includes(t)),s=await lt({message:"Select components to add",options:n.map(i=>({label:i.name,value:i.name,hint:i.description})),required:!0});return oe(s)&&process.exit(0),s}r(Ut,"promptComponentSelectionFiltered");async function je(e,t=!1){const n=await ut({message:e,initialValue:t});return(!n||oe(n))&&($e(),process.exit(0)),!0}r(je,"confirmOverwrite");function x(e){return{absolute:U(process.cwd(),e)}}r(x,"resolveDirectoryFromFlag");async function jt(e){if(e){const{absolute:t}=x(e);return{directory:t}}try{const{config:t}=await X(),n=t.output.cube||t.output.cssRoot,{absolute:s}=x(n);return{directory:s}}catch(t){if(be(t)){const{absolute:n}=x("src/styles");return{directory:n}}throw t}}r(jt,"getCubeDir");async function xt(e){if(e){const{absolute:t}=x(e);return{directory:t}}try{const{config:t}=await X(),n=t.output.components??"src/components/ui",{absolute:s}=x(n);return{directory:s}}catch(t){if(be(t)){const{absolute:n}=x("src/components/ui");return{directory:n}}throw t}}r(xt,"getComponentsDir");const Gt=pt(),S=r((e,t)=>Gt?e:t,"unicodeOr"),Bt=S("\u25C7","o"),xe=S("\u250C","T"),O=S("\u2502","|"),pe=S("\u2514","\u2014"),Vt=S("\u2510","T"),Wt=S("\u2518","\u2014"),te=S("\u2500","-"),Kt=S("\u256E","+"),Yt=S("\u256F","+"),zt=S("\u2570","+"),Ht=S("\u256D","+"),Jt=S("\u25CF","\u2022"),qt=S("\u25C6","*"),Zt=S("\u25B2","!"),Qt=S("\u25A0","x"),K=r((e,t=c.bgGreen,n=c.black)=>t(` ${n(e)} `),"label"),Y=r(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"),z=r((e="",t)=>{process.stdout.write(`
${c.gray(xe)}${c.gray(te)} ${e}
`)},"intro"),ne=r((e="",t)=>{process.stdout.write(`${c.gray(O)}
${c.gray(pe)}${c.gray(te)} ${e}
`)},"outro");function G(e){return new Promise(t=>setTimeout(t,e))}r(G,"sleep");const Xt=[Ht,Kt,zt,Yt],en=[xe,Vt,pe,Wt];function Ge(e,t,n,s){let i=n,o=n;return s==="center"?i=Math.floor((t-e)/2):s==="right"&&(i=t-e-n),o=t-i-e,[i,o]}r(Ge,"getPaddingForLine");const tn=r(e=>e,"defaultFormatBorder"),me=r((e="",t="",n)=>{const s=n?.output??process.stdout,i=dt(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?`${O} `:"",m=n?.formatBorder??tn,h=(n?.rounded?Xt:en).map(m),b=m(te),w=m(O),v=i-u.length;let k=Math.floor(i*d)-u.length;if(n?.width==="auto"){const q=e.split(`
`);let B=Y(t).length+l*2;for(const Xe of q){const we=Y(Xe).length+f*2;we>B&&(B=we)}const Z=B+a;Z<k&&(k=Z)}k%2!==0&&(k<v?k++:k--);const E=k-a,C=E-l*2,T=Y(t).length>C?`${t.slice(0,C-3)}...`:t,[_,$]=Ge(Y(T).length,E,l,n?.titleAlign),A=ft(e,E-f*2,{hard:!0,trim:!1});s.write(`${u}${h[0]}${b.repeat(_)}${T}${b.repeat($)}${h[1]}
`);const J=A.split(`
`);for(const q of J){const[B,Z]=Ge(Y(q).length,E,f,n?.contentAlign);s.write(`${u}${w}${" ".repeat(B)}${q}${" ".repeat(Z)}${w}
`)}s.write(`${u}${h[2]}${b.repeat(E)}${h[3]}
`)},"box");function ge(e,t={}){const n=`
${e}`;me(n,c.black(c.bgRed(" ERROR ")),{width:"auto",titlePadding:2,formatBorder:c.red,...t})}r(ge,"errorBoxWithBadge");function Be(e,t={}){const n=`
${e}`;me(n,c.black(c.bgYellow(" WARNING ")),{width:"auto",titlePadding:2,formatBorder:c.yellow,...t})}r(Be,"warningBoxWithBadge");function nn(e,t={}){const n=`
${e}`;me(n,c.black(c.bgCyan(" INFO ")),{width:"auto",titlePadding:2,formatBorder:c.cyan,...t})}r(nn,"infoBoxWithBadge");const sn=r((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"),rn=r(async(e,t={})=>{const{sidebarSymbol:n=c.gray("\u2502"),clear:s=!1,stdin:i=process.stdin,stdout:o=process.stdout}=t,a=De.createInterface({input:i,escapeCodeTimeout:50}),l=Ne(o,{showCursor:!1});De.emitKeypressEvents(i,a);let f=0,d=!1;const u=r(async()=>{i.off("keypress",m),i.isTTY&&i.setRawMode(!1),a.close(),d=!0,f<e.length-1||s?l.clear():l.done()},"done"),m=r((h,b)=>{i.isTTY&&i.setRawMode(!0);const w=sn(b);if(w==="abort")return u(),process.exit(0);["up","down","left","right"].includes(w)||u()},"handleKeyPress");i.isTTY&&i.setRawMode(!0),i.on("keypress",m);for(const h of e){const b=Array.isArray(h)?h:h.split(" "),w=[];for(const E of[""].concat(b)){E&&w.push(E);const C=w.join(" ").replace(/sugarcube/g,c.cyan("sugarcube")),T=`${n} ${C}`;l(T),d||await new Promise(_=>setTimeout(_,Math.floor(Math.random()*126)+75))}d||await new Promise(E=>setTimeout(E,100));const k=(await Promise.all(b).then(E=>E.join(" "))).replace(/sugarcube/g,c.cyan("sugarcube"));l(`${n} ${k}`),d||await new Promise(E=>setTimeout(E,Math.floor(Math.random()*201)+1200)),f++}i.off("keypress",m),await new Promise(h=>setTimeout(h,100)),u(),i.isTTY&&i.setRawMode(!1),i.removeAllListeners("keypress")},"sayAnimatedInSidebar");function on(){return Math.floor(Math.random()*551)+200}r(on,"getRandomTaskDuration");async function an(e,{sidebarSymbol:t="\u2502",spacing:n=1,stdin:s=process.stdin,stdout:i=process.stdout,initialDelayMs:o=200,minDurationMs:a,successPauseMs:l=300,successMessage:f,successAsOutro:d=!1}={}){const u=r((T,_)=>{let $="";switch(_){case"start":$=`${c.cyan(`\u25B6 ${T.start}`)}`;break;case"pending":$=`${c.dim(`\u25A1 ${T.pending}`)}`;break;case"success":$=`${c.green(`\u2714 ${T.end}`)}`;break;case"end":$=`${c.dim(`\u25A0 ${T.end}`)}`;break}return`${t} ${$}`},"formatWithSidebar"),m=Array.from({length:e.length},()=>"");e.forEach((T,_)=>{m[_]=u(T,"pending")});const h=Ne(i),b=Ce.createInterface({input:s,escapeCodeTimeout:50});Ce.emitKeypressEvents(s,b);const w=r(T=>{T===""&&(h.clear(),b.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 v=Array.from({length:Math.max(n,0)},()=>`${t}`),k=r(()=>[...v,...m].join(`
`),"renderContent");h(k()),await G(o);let E=0;for(const T of e){m[E]=u(T,"start"),h(k());const _=Date.now(),$=T.while();try{await $;const A=Date.now()-_,J=typeof a=="number"?a:on();A<J&&await G(J-A),m[E]=u(T,"success"),h(k()),await G(l)}catch(A){throw m[E]=`${t} ${c.red(`\u2717 ${T.end} (failed)`)}`,h(k()),T.onError?.(A),s.removeListener("keypress",w),b.close(),s.isTTY&&s.setRawMode(!1),A}E++}const C=e.map(T=>u(T,"end"));if(f)if(d){const T=`${c.gray(pe)}${c.gray(te)} ${c.green(f)}`;h([...v,...C,`${t}`,T].join(`
`))}else{const T=`${t} ${c.green(f)}`;h([...v,...C,`${t}`,T].join(`
`))}else h([...v,...C].join(`
`));await G(1e3),s.removeListener("keypress",w),s.isTTY&&s.setRawMode(!1),b.close(),h.done()}r(an,"executeTasksInSidebar");const cn=r(e=>process.stdout.write(`${e}
`),"rawLog"),I={message:r((e=[],{symbol:t=c.gray(O),secondarySymbol:n=c.gray(O),output:s=process.stdout,spacing:i=1}={})=>{const o=[];for(let l=0;l<i;l++)o.push(`${n}`);const a=Array.isArray(e)?e:e.split(`
`);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(`
`)}
`)},"message"),info:r((e,t)=>{I.message(e,{...t,symbol:c.blue(Jt)})},"info"),success:r((e,t)=>{I.message(e,{...t,symbol:c.green(qt)})},"success"),step:r((e,t)=>{I.message(e,{...t,symbol:c.green(Bt)})},"step"),warn:r((e,t)=>{I.message(e,{...t,symbol:c.yellow(Zt)})},"warn"),error:r((e,t)=>{I.message(e,{...t,symbol:c.red(Qt)})},"error"),animated:r(async(e,{secondarySymbol:t=c.gray(O),output:n=process.stdout,clear:s=!1,...i}={})=>rn(e,{sidebarSymbol:t,stdout:n,clear:s,...i}),"animated"),tasks:r(async(e,{spacing:t=1,secondarySymbol:n=c.gray(O),output:s=process.stdout,...i}={})=>an(e,{sidebarSymbol:n,spacing:t,stdout:s,...i}),"tasks"),space:r((e=1)=>{for(let t=0;t<e;t++)process.stdout.write(`${c.gray(O)}
`)},"space"),break:r((e=1)=>{for(let t=0;t<e;t++)process.stdout.write(`
`)},"break")};function H(e){if(e instanceof p)I.space(1),ge(e.message,{});else{const t=`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
If this issue persists, please report it: ${c.cyan("https://github.com/sugarcube-org/sugarcube/issues")}`;I.space(1),ge(t,{})}process.exit(1)}r(H,"handleError");function L(e,t=process.cwd()){try{const n=mt(t,"package.json");if(!N(n))return!1;const s=Te(n,"utf-8"),i=JSON.parse(s),o={...i.dependencies,...i.devDependencies,...i.peerDependencies};return e in o}catch{return!1}}r(L,"isPackageInstalled");async function Ve(e,{withFallback:t=!1}={}){const n=await gt({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"}r(Ve,"getPackageManager");const ln=new P().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||z(K(c.bgGreen(c.black("Components"))));const{directory:n}=await xt(t.componentsDir);let s=[],i;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());i=t.framework,s=e}else{i=await Ue(!1);const w=await j();w||($e("Failed to fetch component list"),process.exit(1)),s=await Ut(w,i)}const o=await Ve(process.cwd(),{withFallback:!0}),a=await j(),l=await fe(a,s,i),f=await Ct({selectedComponents:s,componentType:i,componentsOutputDirectory:n}),d=Pe(f);if(d&&!t.force&&!t.silent){const w=Be(d,{});I.space(1),await je("Continue?",!1)}const u=[],m=[],h=new Set;for(const w of l){const v=w.dependencies?.[i]||[];for(const k of v)h.add(k)}const b=Array.from(h).filter(w=>!L(w,process.cwd()));b.length>0&&u.push({pending:`Install ${b.length} dependencies`,start:`Installing ${b.join(", ")}...`,end:`Installed ${b.join(", ")}`,while:r(async()=>{await ee(b,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:r(async()=>{const v=await Ft({registryIndex:a,selectedComponents:[w.name],componentType:i,componentsOutputDirectory:n,overwrite:t.overwrite||!1,packageManager:o});m.push(...v.createdFiles)},"while")});await I.tasks(u,{successMessage:"Components added successfully! \u{1F389} ",minDurationMs:0,successAsOutro:!0}),cn("")}catch(n){H(n)}}),un=new P().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||z(K("CUBE CSS"));const{directory:t}=await jt(e.cubeDir);try{await V(t,{recursive:!0})}catch(o){const a=o instanceof Error?`: ${o.message}`:"";throw new p(`Failed to create output directory${a}`)}const n=await Dt({cubeDirectory:t}),s=Pe(n);if(s&&!e.force&&!e.silent){I.space(1);const o=Be(s,{});await je("Continue?",!1)}const i=await At(t);if(!e.silent){I.space(1);const o=i,f=[...new Set(o)].map(d=>D(process.cwd(),d)).map(d=>({pending:`Write ${d}`,start:`Writing ${d}`,end:`Wrote ${d}`,while:r(async()=>{},"while")}));await I.tasks(f,{spacing:0,minDurationMs:0,successPauseMs:100,successMessage:"\u{1F389} Files written!"}),ne(c.green("CUBE added successfully."))}}catch(t){H(t)}}),dn="**/*.{html,htm,js,ts,jsx,tsx,vue,svelte,astro,php,njk,liquid,pug,hbs,handlebars,twig,erb,ejs}",fn=["**/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"],We=1e4,Ke=100;async function Ye(e,t){const n={name:"sugarcube",rules:ot(t.utilities??{},e),preflights:[]},s=await ht({presets:[n]}),i=await ce([dn],{ignore:fn,dot:!1,onlyFiles:!0,absolute:!1});if(i.length===0)return[];if(i.length>We)throw new p(`Found ${i.length} files to scan (limit: ${We}). 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=Ke*1024*1024;for(const u of i){const m=await Ie(u,"utf8");if(a+=m.length,a>l)throw new p(`Total source size exceeds ${Ke}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(`
`),{css:d}=await s.generate(f,{preflights:!1});return d?.trim()?[{path:`${t.output.utilities}/utilities.gen.css`,css:d}]:[]}r(Ye,"generateSugarcubeUtilities");async function pn(e,t,n,s){const i=[],o=await ie(e,t,n),a=await Ee(o,n,s);await ke(a),i.push(...a);const l=await Ye(o,n);return await ve(l),i.push(...l),i}r(pn,"generateAllCSS");function mn(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,utilities:e.utilitiesDir},transforms:{fluid:t,colorFallbackStrategy:e.colorFallback}};return Re(n)}r(mn,"buildConfigFromFlags");function gn(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,utilities:t.utilitiesDir??e.output.utilities}}}r(gn,"mergeConfigWithFlags");function hn(e){return!!(e.resolver||e.stylesDir||e.variablesDir||e.utilitiesDir||e.fluidMin||e.fluidMax||e.colorFallback)}r(hn,"hasRelevantFlags");function wn(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.`)}}r(wn,"validateFlags");async function yn(e){if(Se()){const{config:s}=await X();return gn(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||hn(e))return mn({...e,resolver:n});throw new p(g.GENERATE_NO_CONFIG_OR_RESOLVER())}r(yn,"resolveConfig");const Tn=new P().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("--utilities-dir <dir>","Utilities output directory (default: 'src/styles/utilities')").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||z(K("Generate CSS")),wn(e),L("@sugarcube-org/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 yn(e),{trees:n,resolved:s,modifiers:i}=await W(t),o=await pn(n,s,t,i);if(!e.silent){const a=o.map(u=>u.path),d=[...new Set(a)].map(u=>D(process.cwd(),u)).map(u=>({pending:`Write ${u}`,start:`Writing ${u}`,end:`Wrote ${u}`,while:r(async()=>{},"while")}));await I.tasks(d,{spacing:1,minDurationMs:0,successPauseMs:100,successMessage:"\u{1F389} Files written!"}),I.space(1),ne(c.green("CSS generated successfully."))}}catch(t){H(t)}});async function In(e){const t={};return(e.stylesDir||e.variablesDir||e.utilitiesDir)&&(t.output={},e.stylesDir&&(t.output.cssRoot=e.stylesDir),e.variablesDir&&(t.output.variables=e.variablesDir),e.utilitiesDir&&(t.output.utilities=e.utilitiesDir)),(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}r(In,"buildSugarcubeConfig");function ze(e){try{const t=ae.resolve(e,"package.json");if(!N(t))return null;const n=Te(t,"utf-8");return JSON.parse(n)}catch{return null}}r(ze,"getPackageJson");function M(e,t){if(!e)return!1;const n=e.dependencies,s=e.devDependencies;return!!(n?.[t]||s?.[t])}r(M,"hasDependency");function bn(e,t){if(!e)return!1;const n=e.dependencies,s=e.devDependencies,i={...n,...s};return Object.keys(i).some(o=>o.startsWith(t))}r(bn,"hasDependencyStartingWith");function Sn(e){const t=N(ae.resolve(e,"src")),n=ze(e),s=t?"src/design-tokens":"design-tokens",i=t?"src/styles":"styles",o=t?"src/components":"components";let a="none";return M(n,"next")?a=N(ae.resolve(e,`${t?"src/":""}app`))?"next-app":"next-pages":M(n,"astro")?a="astro":M(n,"nuxt")?a="nuxt":M(n,"@sveltejs/kit")?a="sveltekit":bn(n,"@remix-run/")?a="remix":M(n,"@11ty/eleventy")?a="eleventy":M(n,"vite")&&(a="vite"),{framework:a,isSrcDir:t,tokensDir:s,stylesDir:i,componentDir:o}}r(Sn,"getProjectInfo");function En(e,t){if(["vite","astro","nuxt","sveltekit","remix"].includes(e))return!0;if(e==="eleventy"){const s=ze(t);return M(s,"vite")}return!1}r(En,"shouldInstallVitePlugin");function He(e,t=0){if(typeof e!="object"||e===null||t>Et)return!1;for(const[n,s]of Object.entries(e))if(!n.startsWith("$")&&typeof s=="object"&&s!==null&&("$value"in s||He(s,t+1)))return!0;return!1}r(He,"hasAnyToken");async function kn(e){try{const t=await ce([It],{cwd:e,absolute:!0});for(const n of t)try{const s=await se.readFile(n,"utf-8"),i=JSON.parse(s);if(He(i))return!0}catch{}return!1}catch{return!1}}r(kn,"detectExistingTokens");function vn(e=process.cwd()){return wt(e)!==null}r(vn,"isTypeScriptProject");async function Je(e=process.cwd()){return vn(e)?"sugarcube.config.ts":"sugarcube.config.js"}r(Je,"getConfigFileName");function Rn(e){return/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(e)}r(Rn,"isValidIdentifier");function he(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?"[]":`[
${e.map(i=>`${n} ${he(i,t+1)}`).join(`,
`)}
${n}]`;if(typeof e=="object"){const s=Object.entries(e);return s.length===0?"{}":`{
${s.map(([o,a])=>{const l=Rn(o)?o:JSON.stringify(o);return`${n} ${l}: ${he(a,t+1)}`}).join(`,
`)}
${n}}`}return JSON.stringify(e)}r(he,"formatValue");function _n(e,t){const n=he(e,0);return t?`import { defineConfig } from "${t}";
export default defineConfig(${n});
`:`${`// Configuration reference: ${Oe.CONFIGURATION}
export default `}${n};
`}r(_n,"formatConfigAsCode");async function $n(e,t){try{const n=await Je(),s=_n(e,t);await Q(n,s,"utf-8")}catch(n){const s=n instanceof Error?`: ${n.message}`:"";throw new p(`Failed to write config file${s}`)}}r($n,"writeSugarcubeConfig");const Cn=r(async e=>{I.space(2),await G(200);let t="Next steps";if(e.pluginToInstall===Fe)t+=`
`,t+=`1. Configure the plugin
`,t+=` Add the plugin to your build configuration:
`,t+=` ${c.cyan("e.g. vite.config.ts or astro.config.mjs")}
`,t+=` ${c.dim("plugins: [sugarcube()]")}`,t+=`
`,t+=`2. Import the generated CSS
`,t+=` ${c.cyan("import 'virtual:sugarcube.css'")}
`,t+=`
`,t+=`3. (Optional) Add CUBE CSS
`,t+=` ${c.cyan(F.CUBE)}`,t+=`
`,t+=`4. (Optional) Add components
`,t+=` ${c.cyan(F.COMPONENTS)}`;else{const n=`${e.stylesDir}/global/tokens.variables.gen.css`;t+=`
`,t+=`1. Import the generated CSS
`;const s=e.isSrcDir?`"${n}"`:`"./${n}"`;t+=` ${c.cyan(`import ${s}`)}`,t+=`
`,t+=`2. (Optional) Add CUBE CSS
`,t+=` ${c.cyan(F.CUBE)}`,t+=`
`,t+=`3. (Optional) Add components
`,t+=` ${c.cyan(F.COMPONENTS)}`}t+=`
`,t+=`Docs: ${c.cyan("https://sugarcube.sh")}`,nn(t,{width:.75}),await G(200),I.break(1)},"nextSteps");async function Dn(e){await Cn(e)}r(Dn,"next");const Nn=r(async()=>{const e=["Welcome to sugarcube \u2014 the toolkit for seriously sweet frontends!"];I.space(1),await I.animated(e,{clear:!1})},"welcome");function qe(e,t){if(!e||e.trim()==="")throw new p(g.DIRECTORY_PATH_EMPTY(t));const s=st(e).split("/")[0];if(s&&St.includes(s))throw new p(g.DIRECTORY_PATH_RESERVED(t,e))}r(qe,"validateDirectoryPath");function Fn(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.
Either specify both flags or omit both to use defaults (320px - 1200px).`)}r(Fn,"validateOptions");async function On(){Se()&&(ge(g.CONFIG_EXISTS(),{}),process.exit(1))}r(On,"preflightInit");async function An(e){const t=Sn(process.cwd()),n=e.tokensDir||t.tokensDir,s=e.stylesDir||t.stylesDir,i=await kn(n);let o=null;if(i){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:i,resolverPath:o,framework:t.framework}}r(An,"initializeProjectContext");function Ln(e,t,n){const s=t?null:e.kit||le;if(e.skipDeps)return{starterKit:s,pluginToInstall:null,cliToInstall:null};const i=Mn(n,process.cwd());return{starterKit:s,pluginToInstall:i,cliToInstall:i?null:bt}}r(Ln,"determineInstallationTargets");function Mn(e,t){return En(e,t)?Fe:null}r(Mn,"determinePlugin");async function Pn(e,t,n,s,i){const o=await Ve(process.cwd(),{withFallback:!0});return{options:e,...t,isSrcDir:t.isSrcDir,config:n,sugarcubeConfig:s,...i,packageManager:o,createdFiles:[],createdDirectories:[],installedDependencies:[],tasks:[]}}r(Pn,"buildInitContext");async function Un(e){const{trees:t,resolved:n}=await W(e.config);e.setupResult={config:e.config,createdTokenPaths:[],trees:t,resolved:n,tokenFiles:[],tokensDir:e.tokensDir}}r(Un,"processExistingTokens");async function jn(e){!e.hasExistingTokens&&e.starterKit?await Pt(e):await Un(e)}r(jn,"setupDesignTokens");async function xn(e){if(!e.setupResult)throw new p(g.INITIALIZATION_INCOMPLETE());const{trees:t,resolved:n}=e.setupResult,s=await ie(t,n,e.config),i=await Ee(s,e.config);await ke(i)}r(xn,"writeCSSVariables");async function Gn(e){if(!e.setupResult)throw new p(g.INITIALIZATION_INCOMPLETE());const{trees:t,resolved:n}=e.setupResult,s=await ie(t,n,e.config),i=await Ye(s,e.config);i.length&&await ve(i)}r(Gn,"writeCSSUtilities");async function Bn(e){if(e.pluginToInstall&&!L(e.pluginToInstall))try{await ee([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}))}}r(Bn,"installPlugins");async function Vn(e){if(e.cliToInstall&&!L(e.cliToInstall))try{await ee([e.cliToInstall],process.cwd(),e.packageManager,{devDependency:!0}),e.installedDependencies.push(e.cliToInstall)}catch{throw new p(g.CLI_INSTALL_FAILED({packageManager:e.packageManager}))}}r(Vn,"installCLI");function Ze(e){return!!(e.stylesDir||e.variablesDir||e.utilitiesDir||e.fluidMin||e.fluidMax||e.colorFallback)}r(Ze,"hasCustomizationFlags");function Wn(e){return e.pluginToInstall?"@sugarcube-org/vite":e.cliToInstall?"@sugarcube-org/cli":null}r(Wn,"getTypeSource");async function Qe(e){if(Ze(e.options))try{await $n(e.sugarcubeConfig,Wn(e));const t=await Je();e.createdFiles.push(t)}catch{throw new p(g.CONFIG_WRITE_FAILED())}}r(Qe,"finalize");function Kn(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} ${S("\u2192","->")} using them`,while:r(async()=>{},"while")}):e.starterKit&&t.push({pending:"Looking for existing tokens",start:"Looking for existing tokens...",end:`No existing tokens detected ${S("\u2192","->")} adding starter kit`,while:r(async()=>{},"while")}),e.pluginToInstall){const n="Vite";L(e.pluginToInstall)?t.push({pending:`Checking for ${n} compatibility`,start:`Checking for ${n} compatibility...`,end:`${n} plugin already installed ${S("\u2192","->")} skipping plugin installation`,while:r(async()=>{},"while")}):t.push({pending:"Checking for Vite compatibility",start:"Checking for Vite compatibility...",end:`Vite detected ${S("\u2192","->")} plugin will be installed`,while:r(async()=>{},"while")})}else{const n=e.options.skipDeps;t.push({pending:"Checking for Vite compatibility",start:"Checking for Vite compatibility...",end:n?`Dependencies skipped ${S("\u2192","->")} no plugins or CLI will be installed`:`No Vite detected ${S("\u2192","->")} CSS will be generated as file(s)`,while:r(async()=>{},"while")})}return t}r(Kn,"buildDetectionTasks");async function Yn(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:r(async()=>{await jn(e)},"while")}),!e.pluginToInstall)e.tasks.push({pending:"Generate CSS variables",start:"Generating CSS variables...",end:"CSS variables generated",while:r(async()=>{await xn(e)},"while")}),e.tasks.push({pending:"Generate CSS utilities",start:"Generating CSS utilities...",end:"CSS utilities generated",while:r(async()=>{await Gn(e)},"while")}),e.cliToInstall&&!L(e.cliToInstall)&&e.tasks.push({pending:"Install CLI",start:"Installing CLI...",end:"CLI installed",while:r(async()=>{await Vn(e)},"while")});else if(e.pluginToInstall&&!L(e.pluginToInstall)){const t="Vite";e.tasks.push({pending:`Install ${t} plugin`,start:`Installing ${t} plugin...`,end:`${t} plugin installed`,while:r(async()=>{await Bn(e)},"while")})}Ze(e.options)?e.tasks.push({pending:"Write configuration file",start:"Writing configuration file...",end:"Configuration file written",while:r(async()=>{await Qe(e)},"while")}):e.tasks.push({pending:"Finalize setup",start:"Finalizing...",end:"Setup complete",while:r(async()=>{await Qe(e)},"while")})}r(Yn,"buildExecutionTasks");const zn=new P().name("init").description("Initialize a new sugarcube project").option("--kit <kit>",`Starter kit to use (default: ${le})`,le).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("--utilities-dir <dir>","Utilities directory (e.g., 'src/styles/utilities')").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{Fn(e),await On();const n=await An(e),s=await In(e),i=Re(s),o=Ln(e,n.hasExistingTokens,n.framework);t=await Pn(e,n,i,s,o),z(K("sugarcube")),await Nn();const a=Kn(t);a.length>0&&(I.message("Detecting project\u2026"),await I.tasks(a,{minDurationMs:1e3})),t.tasks=[],await Yn(t),t.tasks.length>0&&(I.message("Setting things up\u2026"),await I.tasks(t.tasks,{successMessage:"\u{1F389} Tasks completed successfully!"})),await Dn(t)}catch(n){H(n)}}),Hn=new P().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(z(K("Validate")),!e.length)try{const{config:o}=await X();await W(o),ne(c.greenBright("All tokens valid \u2728"));return}catch{throw new p(g.VALIDATE_NO_PATH_SPECIFIED())}for(const o of e)if(!N(o))throw new p(g.VALIDATE_PATH_NOT_FOUND(o));const n=(await ce(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 Ie(o,"utf-8"),l=D(process.cwd(),o);s[l]={content:a}}const i={output:_e.output,transforms:_e.transforms};await W(i,s),ne(c.greenBright("All tokens valid \u2728"))}catch(t){H(t)}});process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function Jn(){const e=new P().name("make-sugarcube").description("CLI for sugarcube").version(Tt.version,"-v, --version","display the version number");e.addCommand(zn).addCommand(Tn).addCommand(Hn).addCommand(ln).addCommand(un),e.parse()}r(Jn,"main"),Jn();