@sugarcube-org/cli 0.0.0-alpha.15 → 0.0.0-alpha.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,31 @@
1
+ # Sugarcube Private Alpha License
2
+
3
+ Copyright © 2025 Mark Tomlinson. All rights reserved.
4
+
5
+ **Version 1.0 – December 2025**
6
+
7
+ This software is provided under a temporary, non-exclusive, non-transferable
8
+ license for private evaluation and internal use as part of the Sugarcube
9
+ Private Alpha Program.
10
+
11
+ ## Permitted
12
+
13
+ - Use in internal and client projects for the purpose of evaluating Sugarcube
14
+ - Reporting bugs, performance issues, and usability feedback
15
+
16
+ ## Not Permitted
17
+
18
+ - Redistribution of the software or any derivative works
19
+ - Public hosting of the source code
20
+ - Sublicensing, resale, or commercial distribution of Sugarcube itself
21
+ - Reverse engineering for the purpose of creating a competing product
22
+
23
+ ## Disclaimer
24
+
25
+ This software is provided "as is", without warranty of any kind, express or
26
+ implied. The author assumes no liability for damages arising from its use.
27
+
28
+ ## Future Licensing
29
+
30
+ This license will be replaced by an open-source license at public beta or
31
+ general availability.
package/README.md CHANGED
@@ -1,9 +1,7 @@
1
- # make-sugarcube
1
+ # @sugarcube-org/cli
2
2
 
3
- 🚧 Coming soon! 🚧
3
+ > ⚠️ **Private Alpha** — This package is under active development and not yet ready for public use.
4
4
 
5
- A CLI for scaffolding sugarcube applications. This package is currently in development.
5
+ ## License
6
6
 
7
- ## Stay Tuned
8
-
9
- Follow our progress on [GitHub](https://github.com/sugarcube-org)
7
+ See [LICENSE.md](./LICENSE.md) for terms.
package/dist/index.mjs CHANGED
@@ -1,58 +1,158 @@
1
1
  #!/usr/bin/env node
2
- var Ne=Object.defineProperty;var p=(e,n)=>Ne(e,"name",{value:n,configurable:!0});import{Command as z}from"commander";import{existsSync as j}from"node:fs";import i from"node:path";import{select as H,isCancel as C,log as b,multiselect as X,text as U,confirm as W,spinner as oe,intro as V,cancel as Z,outro as L,note as ie}from"@clack/prompts";import{manageCSSIndex as Re,loadConfig as _,generationPipeline as Pe,getTokenPathsFromConfig as De,writeCSSFilesToDisk as Oe,validationPipeline as Ae,validateConfig as me}from"@sugarcube-org/core";import f from"picocolors";import Me from"node-fetch";import{z as y}from"zod";import re,{mkdir as A,writeFile as q,readFile as de}from"node:fs/promises";import{execa as Ue}from"execa";import{detect as We}from"@antfu/ni";import ge from"fast-glob";var Be="0.0.0-alpha.15",ze={version:Be};class g extends Error{static{p(this,"CLIError")}constructor(n,t){super(n),this.name="CLIError",this.cause=t}}const ae=y.enum(["react","astro-native","astro-enhanced","web-components"]),we=y.object({path:y.string(),type:y.string()}),Le=we.extend({framework:ae});y.object({themes:y.record(y.string(),y.array(y.string())).optional()}).strict();const Ge=y.object({name:y.string(),type:y.string(),description:y.string().optional(),frameworks:y.array(y.string()).optional(),files:y.array(y.union([Le,we])),tokens:y.record(y.object({type:y.string(),mapping:y.string()})).optional(),dependencies:y.record(ae,y.array(y.string())).optional(),registryDependencies:y.record(ae,y.array(y.string())).optional(),tokenDependencies:y.array(y.string()).optional()}),Je=y.array(Ge),Ve=y.object({content:y.string()}),E={error:f.red,warn:f.yellow,info:f.cyan,success:f.green,bold:f.bold,path:f.cyan},he=process.env.REGISTRY_URL??"https://sugarcube.sh/r";async function ye(e){try{const n=await Me(e);if(!n.ok){if(n.status===401)throw new g(`Registry access denied: Authentication required
3
- URL: ${E.info(e)}`);if(n.status===403)throw new g(`Registry access denied: Invalid or missing token
4
- URL: ${E.info(e)}`);if(n.status===404)throw new g(`Registry resource not found
5
- URL: ${E.info(e)}`);const t=await n.json().catch(()=>null),o=t&&typeof t=="object"&&"error"in t?t.error:n.statusText;throw new g(`Registry request failed: ${o}
6
- URL: ${E.info(e)}`)}return n.json()}catch(n){throw n instanceof g?n:new g(`Failed to connect to registry
7
- URL: ${E.info(e)}
8
- Check your internet connection`)}}p(ye,"fetchRegistry");async function O(){const e=`${he}/index.json`,n=await ye(e);try{return Je.parse(n)}catch{throw new g(`Invalid registry data received
9
- URL: ${E.info(e)}`)}}p(O,"getRegistryIndex");async function ee({type:e,name:n,framework:t}){const o=await O(),s=o.find(c=>c.type===e&&c.name===n);if(!s){const c=o.filter(u=>u.type===e).map(u=>u.name);throw new g(`${e} '${E.info(n)}' not found in registry
10
- Available ${e}s: ${c.join(", ")}`)}let a=s.files;e==="component"&&t&&(a=s.files.filter(c=>"framework"in c&&c.framework===t));const r=await Promise.all(a.map(async c=>{const u=`${he}/${c.path}.json`,m=await ye(u);try{const S=Ve.parse(m);return{path:c.path,type:c.type,framework:"framework"in c?c.framework:void 0,content:S.content}}catch{throw new g(`Invalid file content received
11
- File: ${E.info(c.path)}`)}}));return{item:s,files:r.filter(Boolean)}}p(ee,"getRegistryFiles");async function ke(e,n,t){const o=[],s=new Set;async function a(r){if(s.has(r))return;s.add(r);const c=e.find(m=>m.name===r);if(!c){const m=e.filter(S=>S.type==="component").map(S=>S.name).join(", ");throw new g(`Component '${r}' not found in registry
12
- Available components: ${m}`)}const u=c.registryDependencies?.[t]||[];for(const m of u)await a(m);o.push(c)}p(a,"resolveComponent");for(const r of n)await a(r);return o}p(ke,"resolveTree");async function Se({config:e,cssOutputDirectory:n}){const t={designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]};if(e.tokens.type==="starter-kit"&&Array.isArray(e.tokens.source))if(e.output.css.separate){const o=e.tokens.source.map(s=>{const a=i.basename(s,".json");return i.relative(process.cwd(),i.join(n,"global/variables",`${a}.variables.css`))});t.designTokenCSS=o.filter(s=>j(i.join(process.cwd(),s)))}else{const o=i.relative(process.cwd(),i.join(n,"global/variables/tokens.variables.css"));j(i.join(process.cwd(),o))&&(t.designTokenCSS=[o])}else{const o="source"in e.tokens?[["default",e.tokens]]:Object.entries(e.tokens);if(e.output.css.separate){const s=o.flatMap(([a,r])=>r.source.map(c=>{const u=i.basename(c,".json");return i.relative(process.cwd(),i.join(n,"global/variables",`${u}.variables.css`))}));t.designTokenCSS=s.filter(a=>j(i.join(process.cwd(),a)))}else{const s=o.map(([a])=>i.relative(process.cwd(),i.join(n,"global/variables",a,"tokens.variables.css")));t.designTokenCSS=s.filter(a=>j(i.join(process.cwd(),a)))}}if(!e.output.css.separate&&e.tokens.type!=="starter-kit"){const o=i.relative(process.cwd(),i.join(n,"global/variables/tokens.variables.css"));j(i.join(process.cwd(),o))&&t.designTokenCSS.push(o)}if(e.output.css.manageIndex){const o=[i.relative(process.cwd(),i.join(n,"index.css")),i.relative(process.cwd(),i.join(n,"index.dark.css"))];t.indexFiles=o.filter(s=>j(i.join(process.cwd(),s)))}return t}p(Se,"collectTokenCSSOverwriteWarnings");async function be({cssOutputDirectory:e,selectedComponents:n,componentType:t,componentsOutputDirectory:o}){const s={designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},a=await O();if(!a)throw new Error("Failed to fetch registry index");const c=(await ke(a,n,t)).map(w=>w.name),u=a.filter(w=>w.type==="component").filter(w=>c.includes(w.name)),m=u.flatMap(w=>w.files.filter(k=>(k.type==="tsx"||k.type==="astro"||k.type==="njk")&&"framework"in k&&k.framework===t).map(k=>i.relative(process.cwd(),i.join(o,w.name,`${w.name}.${k.type}`))));s.componentFiles=m.filter(w=>j(i.join(process.cwd(),w)));const S=u.flatMap(w=>{const k=w.name,x=i.relative(process.cwd(),i.join(o,w.name,`${k}.css`)),l=i.relative(process.cwd(),i.join(e,"global/variables",`${k}.variables.css`));return[x,l]});return s.componentCSS=S.filter(w=>j(i.join(process.cwd(),w))),s}p(be,"collectComponentOverwriteWarnings");async function ve({cssOutputDirectory:e}){const n={designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},t=await O();if(!t)throw new Error("Failed to fetch registry index");const o=t.filter(s=>s.type==="cube").flatMap(s=>s.files).map(s=>{const a=s.path.replace(/^styles\//,"");return i.relative(process.cwd(),i.join(e,a))});return n.cubeCSS=o.filter(s=>j(i.join(process.cwd(),s))),n}p(ve,"collectCubeOverwriteWarnings");function _e(...e){return e.reduce((n,t)=>({designTokenCSS:[...n.designTokenCSS,...t.designTokenCSS],componentFiles:[...n.componentFiles,...t.componentFiles],componentCSS:[...n.componentCSS,...t.componentCSS],cubeCSS:[...n.cubeCSS,...t.cubeCSS],indexFiles:[...n.indexFiles,...t.indexFiles]}))}p(_e,"mergeWarnings");const ce={PROJECT_REQUIRED:`This command requires you to initialize a sugarcube project. Run ${f.cyan("make-sugarcube init")} first.
13
-
14
- For more information, visit: ${f.cyan("https://sugarcube.sh/docs/initialize")}`};function te(e){const n=[];if(e.designTokenCSS.length>0&&n.push(`Design token CSS files:
15
- ${e.designTokenCSS.map(t=>` - ${t}`).join(`
16
- `)}`),e.cubeCSS.length>0&&n.push(`CUBE CSS files:
17
- ${e.cubeCSS.map(t=>` - ${t}`).join(`
18
- `)}`),e.componentFiles.length>0||e.componentCSS.length>0){const t=[...e.componentFiles,...e.componentCSS];n.push(`Component files:
19
- ${t.map(o=>` - ${o}`).join(`
20
- `)}`)}if(e.indexFiles.length>0&&n.push(`Index files:
21
- ${e.indexFiles.map(t=>` - ${t}`).join(`
22
- `)}`),n.length!==0)return f.yellow(`WARNING: The following file(s) already exist and will be OVERWRITTEN:
23
-
24
- ${f.dim(n.join(`
25
-
26
- `))}`)}p(te,"formatOverwriteWarnings");const $={error(...e){console.log(E.error(e.join(" ")))},warn(...e){console.log(E.warn(e.join(" ")))},info(...e){console.log(E.info(e.join(" ")))},success(...e){console.log(E.success(e.join(" ")))},log(...e){console.log(e.join(" "))},break(){console.log("")}};function K(e){if($.break(),e instanceof g){const n=e.message.split(`
27
- `);if(n.length>1){$.error(n[0]),$.break();for(const t of n.slice(1))$.error(` ${t.trim()}`)}else $.error(e.message);process.env.DEBUG&&e.cause&&$.info(`
28
- Caused by:`,e.cause)}else $.error(`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
29
- If this issue persists, please report it: ${f.cyanBright("https://github.com/sugarcube-org/sugarcube/issues")}`),process.env.DEBUG&&$.info(`
30
- Error details:`,e);$.break(),process.exit(0)}p(K,"handleError");async function qe(e,{withFallback:n=!1}={}){const t=await We({programmatic:!0,cwd:e});if(t?.startsWith("yarn@"))return"yarn";if(t?.startsWith("pnpm@"))return"pnpm";if(t==="bun")return"bun";if(!n)return t?.split("@")[0]??"npm";const o=process.env.npm_config_user_agent||"";return o.startsWith("yarn")?"yarn":o.startsWith("pnpm")?"pnpm":o.startsWith("bun")?"bun":"npm"}p(qe,"getPackageManager");async function Ke(e,n){const t=await qe(n,{withFallback:!0}),o=t==="npm"?"install":"add";try{await Ue(t,[o,...e],{cwd:n})}catch{const a=`Failed to install dependencies using ${t}.
31
-
32
- This might be because you're using 'npx' with a pnpm project. Try:
33
- pnpm dlx @sugarcube-org/cli components
34
-
35
- Or use the appropriate package runner for your project:
36
- npm: npx @sugarcube-org/cli components
37
- pnpm: pnpm dlx @sugarcube-org/cli components
38
- yarn: yarn dlx @sugarcube-org/cli components
39
- bun: bunx @sugarcube-org/cli components`;throw new Error(a)}}p(Ke,"installDependencies");async function Ce({registryIndex:e,selectedComponents:n,componentType:t,componentsOutputDirectory:o,cssOutputDirectory:s}){const a=[],r=new Set;await A(o,{recursive:!0});const c=i.join(s,"global","variables");await A(i.join(s,"global"),{recursive:!0}),await A(c,{recursive:!0});const u=await ke(e,n,t);for(const m of u){const S=await ee({type:"component",name:m.name,framework:t});for(const k of S.files)if(k)try{if(k.path.endsWith(".variables.css")){const x=i.join(c,`${m.name}.variables.css`);await q(x,k.content),a.push(x)}else{const x=i.join(o,m.name);await A(x,{recursive:!0});const l=i.join(x,i.basename(k.path));await q(l,k.content),a.push(l)}}catch(x){const l=x instanceof Error?`: ${x.message}`:"";throw new g(`Failed to write component file for "${m.name}"${l}`)}const w=m.dependencies?.[t]||[];for(const k of w)r.add(k)}if(r.size>0)try{await Ke(Array.from(r),process.cwd())}catch(m){const S=m instanceof Error?`: ${m.message}`:"";throw new g(`Failed to install component dependencies${S}`)}return{createdFiles:a,npmDependencies:r}}p(Ce,"installComponents");async function ne({cssOutputDirectory:e,files:n}){try{await Re({cssOutputDirectory:e,files:n})}catch(t){const o=t instanceof Error?`: ${t.message}`:"";throw new g(`Failed to manage CSS index file ${o}`)}}p(ne,"manageCSSIndexCLI");async function xe(e="src/styles"){const n=await U({message:"Save CSS to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return C(n)&&process.exit(0),i.relative(process.cwd(),i.resolve(process.cwd(),n))}p(xe,"promptCSSOutputDirectory");async function Qe(e="src/design-tokens"){const n=await U({message:"Save tokens to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return C(n)&&process.exit(0),i.relative(process.cwd(),i.resolve(process.cwd(),n))}p(Qe,"promptTokensDirectory");async function Ye(e){const n=e.filter(r=>r.type==="tokens"&&r.files[0]?.path.includes("starter-kits")),t=n.map(r=>({label:r.name,value:r.name})),o=await H({message:"Which starter kit?",options:t});C(o)&&process.exit(0);const s=n.find(r=>r.name===o);if(!s)throw new Error(`Starter kit '${o}' not found`);const a=s.files.filter(r=>i.basename(r.path)!=="config.json").map(r=>i.basename(r.path));return{name:o,tokenFilePaths:a}}p(Ye,"promptStarterKit");async function Fe(e="src/components"){const n=await U({message:"Save components to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return C(n)&&process.exit(0),i.relative(process.cwd(),i.resolve(process.cwd(),n))}p(Fe,"promptComponentDirectory");async function le(e=!0){const n=[{label:"React",value:"react",hint:".tsx"},{label:"Astro (Native)",value:"astro-native",hint:"Minimal, standards-based .astro; uses native HTML features"},{label:"Astro (Enhanced)",value:"astro-enhanced",hint:"Advanced features, richer client-side logic - coming soon"},{label:"Web Components",value:"web-components",hint:"Native web components using TypeScript - coming soon"}];e&&n.push({label:"Skip",value:"skip",hint:"continue without components"});const t=await H({message:"Build with",options:n});return C(t)&&process.exit(0),t==="astro-enhanced"||t==="web-components"?(b.info(f.blue("Sorry, this framework is coming soon! Please choose 'Astro (Native)' or 'React' for now.")),le(e)):t}p(le,"promptComponentFramework");async function je(e,n){const t=e.filter(s=>s.type==="component"&&s.frameworks?.includes(n)),o=await X({message:"Select components to add",options:t.map(s=>({label:s.name,value:s.name,hint:s.description})),required:!0});return C(o)&&process.exit(0),o}p(je,"promptComponentSelectionFiltered");async function He(){const n=await H({message:"Set up tokens with",options:[{label:"Starter kit",value:"starter"},{label:"Own tokens",value:"existing"}]});return C(n)&&process.exit(0),n}p(He,"promptTokenSetup");async function Q(e,n=!1){const t=await W({message:e,initialValue:n});return(!t||C(t))&&process.exit(0),!0}p(Q,"confirmOverwrite");async function Xe(){const e=await W({message:"Install CUBE CSS?",active:"Yes",inactive:"No",initialValue:!0});return C(e)&&process.exit(0),e}p(Xe,"promptInstallCube");async function Ze(e="src/design-tokens"){const n=await U({message:"Path to existing tokens",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Path cannot be empty"},"validate")});return C(n)&&process.exit(0),i.relative(process.cwd(),i.resolve(process.cwd(),n))}p(Ze,"promptExistingTokensPath");async function et(){const e=await W({message:"Do you need to create collections from your token files? (e.g., core, marketing)",initialValue:!1});return C(e)&&process.exit(0),e?"collections":"simple"}p(et,"promptCollectionOrganization");async function $e(e,n=!1){if(e.length===0)return null;const t=await X({message:`Select files for your ${n?"first":"next"} collection (including any theme files)`,options:e.map(o=>({label:o,value:o}))});return C(t)&&process.exit(0),t.length===0?null:t}p($e,"promptFilesForCollection");async function pe(e){const n=e.map(o=>i.dirname(o).split(i.sep)).reduce((o,s)=>o?o.filter((a,r)=>a===s[r]):s).pop(),t=await U({message:"Name this collection:",placeholder:n||"collection"});return C(t)&&process.exit(0),t}p(pe,"promptCollectionName");async function tt(e){if(e.length<=1)return null;const n=await W({message:"Are any of these theme files?",initialValue:!1});if(C(n)&&process.exit(0),!n)return null;const t=[];let o=[...e];for(;o.length>0;){const s=await X({message:t.length===0?"Select files for first theme:":"Select files for another theme (or Enter to finish):",options:o.map(r=>({label:r,value:r}))});if(C(s)&&process.exit(0),s.length===0)break;const a=await U({message:"Name this theme:",placeholder:"light"});if(C(a)&&process.exit(0),t.push({name:a,files:s}),o=o.filter(r=>!s.includes(r)),o.length>0){const r=await W({message:"Create another theme?",initialValue:!0});if(C(r)&&process.exit(0),!r)break}}return t.length>0?t:null}p(tt,"promptIdentifyThemeFiles");async function nt(e){if(e.length<=1)return null;const n=await W({message:"Do you need to create themes from your token files? (e.g. dark, light, high contrast)",initialValue:!1});if(C(n)&&process.exit(0),!n)return null;const t=[];let o=[...e];for(;o.length>0;){const s=await X({message:t.length===0?"Select files for first theme:":"Select files for your next theme:",options:o.map(r=>({label:r,value:r}))});if(C(s)&&process.exit(0),s.length===0)break;const a=await U({message:"Name this theme:",placeholder:"dark"});if(C(a)&&process.exit(0),t.push({name:a,files:s}),o=o.filter(r=>!s.includes(r)),o.length>0){const r=await W({message:"Do you need to create another theme?",initialValue:!1});if(C(r)&&process.exit(0),!r)break}}return t.length>0?t:null}p(nt,"promptIdentifyAllThemeFiles");function se(e){const t=[...e.config?[e.config]:[],...e.tokens||[],...e.generated].map(s=>i.relative(process.cwd(),s)),o=oe();o.start(`Generating ${t.length} files:`),o.stop(`Generated ${t.length} files:`);for(const s of t)$.log(` - ${s}`);$.break()}p(se,"showSummary");async function fe(e){const n={$schema:"https://sugarcube.sh/r/schema.json",...e};try{const t=JSON.stringify(n,null,2);await q("sugarcube.config.json",t)}catch(t){const o=t instanceof Error?`: ${t.message}`:"";throw new g(`Failed to write config file${o}`)}}p(fe,"writeConfig");const st=new z().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, astro-native, astro-enhanced)").action(async(e,n)=>{try{if(V(f.inverse(" Add components ")),!j("sugarcube.config.json"))throw new g(ce.PROJECT_REQUIRED);const t=await _();let o,s=[],a;if(e.length>0||n.framework){if(!n.framework)throw new g(`Framework is required when specifying components. Use --framework to specify a framework (react, astro-native, astro-enhanced) or run without arguments for interactive mode.
40
-
41
- See ${f.cyan("https://docs.sugarcube.sh/cli/components")} for more information.`);if(!["react","astro-native","astro-enhanced","web-components"].includes(n.framework))throw new g("Invalid framework. Must be one of: React, Astro (Native) or Astro (Enhanced).");if(n.framework==="astro-enhanced"||n.framework==="web-components")throw new g("Sorry, this framework is coming soon! Please choose Astro (Native) or React for now.");if(a=n.framework,s=e,!t.output.directories.components)throw new g("Components directory must be configured in non-interactive mode. Please run the 'components' commandwithout arguments first.");o=i.resolve(process.cwd(),t.output.directories.components)}else{a=await le(!1);const u=await O();if(u||(Z("Failed to fetch component list"),process.exit(1)),s=await je(u,a),t.output.directories.components)o=i.resolve(process.cwd(),t.output.directories.components);else{const m=await Fe();o=i.resolve(process.cwd(),m),t.output.directories.components=i.relative(process.cwd(),o),await fe(t)}}const r=await be({cssOutputDirectory:i.resolve(process.cwd(),t.output.directories.css),selectedComponents:s,componentType:a,componentsOutputDirectory:o});if(r.componentFiles.length>0){const u=te(r);u&&(b.warn(u),await Q("Continue?",!1))}const c=oe();c.start("Installing components...");try{const u=await O(),{createdFiles:m,npmDependencies:S}=await Ce({registryIndex:u,selectedComponents:s,componentType:a,componentsOutputDirectory:o,cssOutputDirectory:t.output.directories.css});t.output.css.manageIndex&&await ne({cssOutputDirectory:t.output.directories.css,files:m}),c.stop("Components installed successfully"),se({generated:m}),L(f.greenBright("Success! Components installed \u2728"))}catch(u){throw c.stop("Installation failed"),u}}catch(t){K(t)}}),ot=new z().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").option("-f, --force","Skip overwrite confirmation").action(async e=>{const n=[];try{if(!j("sugarcube.config.json"))throw new g(ce.PROJECT_REQUIRED);e.silent||V(f.inverse(" Add CUBE CSS "));const t=await _(),o=i.resolve(process.cwd(),t.output.directories.css);try{await A(o,{recursive:!0})}catch(c){const u=c instanceof Error?`: ${c.message}`:"";throw new g(`Failed to create output directory${u}`)}const s=await ve({cssOutputDirectory:o});if(s.cubeCSS.length>0&&!e.silent&&!e.force){const c=te(s);c&&(b.warn(c),await Q("Continue?",!1))}const r=(await O()).filter(c=>c.type==="cube").map(c=>c.name);for(const c of r){const u=await ee({type:"cube",name:c});for(const m of u.files){if(!m)continue;const S=m.path.replace(/^styles\//,""),w=i.join(o,S),k=i.dirname(w);try{await A(k,{recursive:!0}),await q(w,m.content),n.push(w)}catch(x){const l=x instanceof Error?`: ${x.message}`:"";throw new g(`Failed to write CUBE CSS file ${w}${l}`)}}}t.output.css.manageIndex&&await ne({cssOutputDirectory:o,files:n}),await fe(t),!e.silent&&n.length>0&&(se({generated:n}),L(f.greenBright("Success! CUBE CSS added successfully. \u2728")))}catch(t){K(t)}});async function Te(e,n,t){const{output:o}=await Pe(e,n,t);try{const s=De(t);return await Oe(o,!0,s)}catch(s){throw new g(`Failed to write CSS files: ${s instanceof Error?s.message:"Unknown error"}`)}}p(Te,"generateAndWriteCSSVars");async function G(e,n={type:"files",paths:e}){const{trees:t,resolved:o,errors:s}=await Ae(e,{loader:n});if(s.load.length>0)throw new g(`Failed to load token files:
42
- ${s.load.map(a=>`${a.file}: ${a.message}`).join(`
43
- `)}`);if(s.validation.length>0||s.flatten.length>0||s.resolution.length>0){$.break();const a=[...s.flatten,...s.validation,...s.resolution],r=new Map;for(const c of a)if(c.source?.sourcePath){const u=r.get(c.source.sourcePath)||[];u.push(c.message),r.set(c.source.sourcePath,u)}for(const[c,u]of r){$.error(`Error(s) in ${E.path(c)}:`);for(const m of u)$.error(` - ${m}`);$.break()}throw new g(`Token validation failed. See ${E.info("https://docs.sugarcube.sh/w3c-token-format")} for help`)}return{trees:t,resolved:o}}p(G,"validateTokens");const it=new z().name("generate").description("Generate CSS from your design tokens").option("-s, --silent","Suppress logs and prompts").option("-f, --force","Skip overwrite confirmation").action(async e=>{try{if(e.silent||V(f.inverse(" Generate CSS variables from your design tokens ")),!j("sugarcube.config.json"))throw new g(ce.PROJECT_REQUIRED);const n=await _(),{trees:t,resolved:o}=await G(n),s=await Se({config:n,cssOutputDirectory:n.output.directories.css}),a=te(s);a&&!e.force&&!e.silent&&(b.warn(a),await Q("Continue?",!1));const r=await Te(t,o,n);n.output.css.manageIndex&&await ne({cssOutputDirectory:n.output.directories.css,files:r.map(c=>c.path)}),e.silent||(se({generated:[...r.map(c=>c.path),...n.output.css.manageIndex?["index.css"]:[]]}),L(f.greenBright("Success! CSS variables generated successfully. \u2728")))}catch(n){K(n)}}),rt=p(async({tokenFiles:e,tokensOutputDirectory:n})=>{const t=[];for(const o of e){const s=i.join(n,i.basename(o.path));j(s)&&t.push(s)}return t},"checkTokenFileExists"),at=p(async e=>{const n=await Ze(),t=await ge("**/*.json",{cwd:n,absolute:!0});if(t.length===0)throw new g(`No JSON files found in ${n}`);const o=[];for(const l of t)try{const d=await de(l,"utf-8");JSON.parse(d),o.push(l)}catch{b.warn(f.yellow(`Skipping invalid JSON file: ${l}`))}if(o.length===0)throw new g(`No valid JSON files found in ${n}
44
- Ensure files contain valid JSON`);const s=o.map(l=>i.relative(process.cwd(),l)),a=i.resolve(process.cwd(),n),r=await xe();let c=await et();const u=new Map;for(const l of s){const d=i.basename(l),h=u.get(d)||[];u.set(d,[...h,l])}const m=Array.from(u.entries()).filter(([l,d])=>d.length>1).map(([l,d])=>({name:l,files:d}));if(c==="simple"&&m.length>0){const l=m.map(({name:d,files:h})=>{const F=h.map(v=>` - ${v}`).join(`
45
- `);return`
46
- ${d} appears in:
47
- ${f.dim(F)}`}).join(`
48
- `);b.warn(f.yellow(`Simple organization cannot have duplicate filenames:
49
- ${l}`)),b.message(f.cyan("Switching to collections to help organize these files...")),c="collections"}if(c==="simple"){const l={type:"custom",source:s},d=await nt(s);if(d&&d.length>0){const h=d.flatMap(F=>F.files);l.source=s.filter(F=>!h.includes(F)),l.themes=d.reduce((F,v)=>Object.assign(F,{[v.name]:v.files}),{})}e.tokens=l}else{const l={},d=new Set;let h=[...s],F=!0;for(;h.length>0;){let v=await $e(h,F);if(!v){b.message(f.cyan("No files selected, skipping collection creation..."));break}let T=await pe(v);if(!T){b.message(f.cyan("No collection name provided, skipping collection creation..."));break}let B=!1;for(;!B;)try{if(d.has(T)){b.warn(f.yellow(`Collection name "${T}" is already in use.`));const R=await pe(v);if(!R){b.message(f.cyan("No collection name provided, skipping collection creation..."));break}T=R;continue}const I={type:"custom",source:v};l[T]=I;const N=await tt(v);if(N&&N.length>0){const R=N.flatMap(D=>D.files),P=new Set;let M=!1;for(const D of N){if(P.has(D.name)){b.warn(f.yellow(`Theme name "${D.name}" is already used in this collection.`)),b.message(f.cyan("Starting theme selection over to avoid conflicts...")),M=!0;break}P.add(D.name)}if(M)continue;I.source=v.filter(D=>!R.includes(D)),I.themes=N.reduce((D,Y)=>Object.assign(D,{[Y.name]:Y.files}),{})}const J=new Map;for(const R of I.source){const P=i.basename(R),M=J.get(P)||[];J.set(P,[...M,R])}const ue=Array.from(J.entries()).filter(([R,P])=>P.length>1).map(([R,P])=>({name:R,files:P}));if(ue.length>0){const R=ue.map(({name:D,files:Y})=>{const Ee=Y.map(Ie=>` - ${Ie}`).join(`
50
- `);return`
51
- ${D} appears in:
52
- ${f.dim(Ee)}`}).join(`
53
- `);b.warn(f.yellow(`Found duplicate filenames in collection "${T}":
54
- ${R}`)),b.message(f.cyan("Please either split these files into different collections or mark some as theme files."));const P=await $e(h,F);if(!P){b.message(f.cyan("No files selected, skipping collection creation..."));break}v=P;const M=await pe(v);if(!M){b.message(f.cyan("No collection name provided, skipping collection creation..."));break}T=M;continue}B=!0,d.add(T)}catch(I){if(I instanceof g){b.error(`${I.message}`),b.message(f.cyan("Let's try again..."));continue}throw I}if(!B){b.message(f.cyan("Skipping collection creation..."));break}h=h.filter(I=>!v.includes(I)),h.length>0&&b.message(f.cyan(`Remaining files to organize: ${h.length}`)),F=!1}h.length>0?b.warn(f.yellow(`Warning: ${h.length} files were not assigned to any collection`)):b.message(f.cyan("Token organization complete")),e.tokens=l}if(e.output={directories:{tokens:i.relative(process.cwd(),a),css:r},css:{separate:!1,manageIndex:!0}},e.options={fluid:{min:320,max:1200}},typeof e.tokens=="object"&&!Array.isArray(e.tokens)){const l=e.tokens,d=new Set;for(const[h,F]of Object.entries(l)){if(d.has(h))throw new g(`Configuration Error: Duplicate collection name "${h}". Collection names must be unique.`);if(d.add(h),F.themes){const v=new Set;for(const T of Object.keys(F.themes)){if(v.has(T))throw new g(`Configuration Error: Duplicate theme name "${T}" in collection "${h}". Theme names must be unique within a collection.`);v.add(T)}}}}const S=await Promise.all(s.map(async l=>({path:i.resolve(process.cwd(),l),content:await de(i.resolve(process.cwd(),l),"utf-8")}))),w=me(e),{trees:k,resolved:x}=await G(w);return{config:w,tokens:s,trees:k,resolved:x,tokenPath:n,tokensDir:a,tokenFiles:S}},"initializeFromExistingTokens"),ct=p(async(e,n,t)=>{const o=await ee({type:"tokens",name:e});if(!o.files[0])throw new g(`Starter kit '${e}' does not contain any token files`);const s=i.resolve(process.cwd(),t),a=o.files.find(l=>i.basename(l.path)==="config.json");let r={};if(a)try{r=JSON.parse(a.content)}catch{console.warn(`Warning: Could not parse config.json for starter kit '${e}'`)}const c=o.files.filter(l=>i.basename(l.path)!=="config.json").map(l=>({path:i.join(s,i.basename(l.path)),content:l.content})),u=Object.fromEntries(c.map(l=>[i.basename(l.path),i.relative(process.cwd(),l.path)])),m={};if(r.themes)for(const[l,d]of Object.entries(r.themes))m[l]=d.map(h=>{const F=u[h];if(!F)throw new g(`Theme file '${h}' not found in starter kit '${e}'`);return F});const S={tokens:{source:c.map(l=>i.relative(process.cwd(),l.path)),type:"starter-kit",...Object.keys(m).length>0&&{themes:m}},options:{fluid:{min:320,max:1200}},output:{directories:{tokens:i.relative(process.cwd(),s),css:n},css:{separate:!1,manageIndex:!0}}},w=me(S),{trees:k,resolved:x}=await G(w,{type:"memory",data:Object.fromEntries(c.map(l=>[l.path,{collection:"default",content:l.content}]))});return{config:w,tokens:c.map(l=>i.relative(process.cwd(),l.path)),trees:k,resolved:x,tokenFiles:c,tokensDir:s}},"initializeFromStarterKit");async function lt(e){const n=[],t=i.resolve(process.cwd(),e);await A(t,{recursive:!0});const s=(await O()).filter(a=>a.type==="cube").map(a=>a.name);for(const a of s){const r=await ee({type:"cube",name:a});for(const c of r.files){if(!c)continue;const u=c.path.replace(/^styles\//,""),m=i.join(t,u),S=i.dirname(m);try{await A(S,{recursive:!0}),await q(m,c.content),n.push(m)}catch(w){const k=w instanceof Error?`: ${w.message}`:"";throw new g(`Failed to write CUBE module "${a}"${k}`)}}}return n}p(lt,"installCUBE");async function pt(){if(j("sugarcube.config.json")){const e=await H({message:f.yellow("WARNING: You are about to re-initialize an existing sugarcube project! This will overwrite your existing configuration file. "),options:[{label:"Overwrite existing file (start from scratch)",value:"overwrite"},{label:"Cancel initialization",value:"cancel"}]});return C(e)&&process.exit(0),{shouldProceed:e==="overwrite"}}return{shouldProceed:!0}}p(pt,"preflightInit");const ft=p(()=>{$.break(),V(" Welcome to sugarcube. The toolkit for seriously sweet front ends ")},"welcome"),ut=new z().name("init").description("Initialize a new sugarcube project").action(async()=>{try{ft(),(await pt()).shouldProceed||process.exit(0),ie("Step 1. Set up tokens");const n=await He();let t;switch(n){case"starter":{const d=await O();d||(Z("Failed to fetch starter kit list"),process.exit(1));const{name:h,tokenFilePaths:F}=await Ye(d),v=await Qe(),T=F.map(N=>({path:i.join(v,N)})),B=await rt({tokenFiles:T,tokensOutputDirectory:v});if(B.length>0){const N=B.map(J=>` - ${J}`).join(`
55
- `);b.warn(f.yellow(`WARNING: The following token file(s) already exist in ${v} and will be OVERWRITTEN:
56
- ${f.dim(N)}`)),await Q("Continue?",!1)}const I=await xe();try{t=await ct(h,I,v)}catch(N){Z(`Failed to initialize starter kit: ${N instanceof Error?N.message:"Unknown error"}`),process.exit(1)}break}case"existing":t=await at({});break}ie("Step 2. Add style system");const o=await Xe();ie("Step 3. Add components");const s=await le();t.config.output.css.manageIndex=!1;let a,r,c;s!=="skip"&&(a=await Fe(),t.config.output.directories.components=i.relative(process.cwd(),a),c=await O(),c||(Z("Failed to fetch component list"),process.exit(1)),r=await je(c,s));const u=_e(await Se({config:t.config,cssOutputDirectory:t.config.output.directories.css}),r&&s!=="skip"&&a?await be({cssOutputDirectory:t.config.output.directories.css,selectedComponents:r,componentType:s,componentsOutputDirectory:a}):{designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},o?await ve({cssOutputDirectory:t.config.output.directories.css}):{designTokenCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]}),m=te(u);m&&(b.warn(m),await Q("Continue?",!1));try{if(!t.tokensDir)throw new g("Tokens directory is not defined");if(await re.mkdir(t.tokensDir,{recursive:!0}),await re.mkdir(t.config.output.directories.css,{recursive:!0}),n==="starter"){if(!t.tokenFiles||t.tokenFiles.length===0)throw new g("Failed to generate token content for starter kit");for(const d of t.tokenFiles)await re.writeFile(d.path,d.content)}}catch(d){const h=d instanceof Error?`: ${d.message}`:"";throw new g(`Failed to create project files${h}`)}let S=[];const{trees:w,resolved:k}=await G(t.config);S=await Te(w,k,t.config);let x=[];o&&(x=await lt(t.config.output.directories.css));let l=[];if(r&&s!=="skip"&&a){const d=oe();d.start("Installing components...");try{const h=await O();if(!h)throw new g("Failed to fetch component list");const{createdFiles:F,npmDependencies:v}=await Ce({registryIndex:h,selectedComponents:r,componentType:s,componentsOutputDirectory:a,cssOutputDirectory:t.config.output.directories.css});l=F,d.stop("Components installed successfully")}catch(h){throw d.stop("Installation failed"),h}}t.config.output.css.manageIndex&&await ne({cssOutputDirectory:t.config.output.directories.css,files:[...S.map(d=>d.path),...l.filter(d=>d.endsWith(".css")),...x]}),await fe(t.config),se({config:"sugarcube.config.json",tokens:n==="starter"?t.tokens:[],generated:[...S.map(d=>d.path),...x,...l,...t.config.output.css.manageIndex?["index.css"]:[]]}),L(f.greenBright("Success! Project initialized \u2728"))}catch(e){K(e)}}),mt=new z().name("validate").description("Validate design token files").argument("[paths...]","Token files or directories to validate (e.g., tokens.json or ./tokens)").action(async e=>{try{if(V(f.inverse(" Validate design tokens ")),j("sugarcube.config.json")&&!e.length){const s=await _();await G(s),L(f.greenBright("All tokens are valid \u2728"));return}if(!e.length)throw new g("No paths specified. Please provide files/directories to validate, or run this in a sugarcube project directory.");const n=e.map(s=>i.normalize(s));for(const s of n)if(!j(s))throw new g(`Path not found: ${s}
57
- Please check that the specified files or directories exist`);const t=await ge(n.map(s=>s.endsWith(".json")?s:i.join(s,"**/*.json")));if(t.length===0)throw new g(`No JSON files found in the specified paths
58
- Please ensure the paths contain .json files`);const o=j("sugarcube.config.json")?await _():{output:{directories:{tokens:".",css:"."},css:{separate:!1}}};await G({...o,tokens:{type:"custom",source:t.map(s=>i.relative(process.cwd(),s))}}),L(f.greenBright("All tokens are valid \u2728"))}catch(n){K(n)}});process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function dt(){const e=new z().name("sugarcube").description("CLI for scaffolding sugarcube projects").version(ze.version,"-v, --version","display the version number");e.addCommand(ut).addCommand(it).addCommand(mt).addCommand(st).addCommand(ot),e.parse()}p(dt,"main"),dt();
2
+ var Je=Object.defineProperty;var o=(e,t)=>Je(e,"name",{value:t,configurable:!0});import{Command as L}from"commander";import{relative as R,join as $,basename as x,resolve as Q,dirname as qe,normalize as ze}from"pathe";import c from"picocolors";import{existsSync as N,readFileSync as ye}from"node:fs";import Ze from"node-fetch";import{z as m}from"zod";import se,{mkdir as W,writeFile as X,readFile as Qe}from"node:fs/promises";import{execa as Xe}from"execa";import{loadAndResolveTokens as et,validateConfig as tt,configFileExists as v,loadInternalConfig as ee,loadUserConfig as nt,processAndConvertTokens as oe,generateCSSVariables as Te,writeCSSVariablesToDisk as Se,writeCSSUtilitiesToDisk as Ie,convertConfigToUnoRules as st,DEFAULT_STYLES_PATH as ot,DEFAULT_CONFIG as re,fillDefaults as rt}from"@sugarcube-org/core";import it from"is-unicode-supported";import ie,{resolve as at}from"node:path";import{select as ct,isCancel as ae,log as lt,multiselect as ut,confirm as ft,cancel as ke}from"@clack/prompts";import{getColumns as pt}from"@clack/core";import{wrapAnsi as dt}from"fast-wrap-ansi";import*as Ee from"node:readline";import be from"node:readline";import{createLogUpdate as Ce}from"log-update";import{detect as gt}from"@antfu/ni";import{getTsconfig as mt}from"get-tsconfig";import{createGenerator as ht}from"@unocss/core";import G from"fast-glob";var wt="0.0.0-alpha.17",yt={version:wt};const ce="fluid",$e="**/*.json",Re="@sugarcube-org/vite",Tt=["node_modules",".git",".next","dist","build"],St=5,A={INIT:"make-sugarcube init",COMPONENTS:"make-sugarcube components",GENERATE:"make-sugarcube generate",CUBE:"make-sugarcube cube"},It={INITIALIZATION:"https://sugarcube.sh/docs/getting-started/getting-started"},w={PROJECT_REQUIRED:`No sugarcube project detected. Please run ${c.cyan(A.INIT)} first.
3
+
4
+ For more information, visit: ${c.cyan(It.INITIALIZATION)}`,CONFIG_EXISTS:o(()=>`A sugarcube config file already exists in this projct.
5
+
6
+ To start over, remove it and run ${c.cyan(A.INIT)} again.`,"CONFIG_EXISTS"),PLUGIN_INSTALL_FAILED:o(e=>`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} add ${e.pluginToInstall}
13
+
14
+ If the problem continues, please open an issue at:
15
+ https://github.com/sugarcube-org/sugarcube/issues`,"PLUGIN_INSTALL_FAILED"),INITIALIZATION_INCOMPLETE:o(()=>`The initialization process was not completed properly.
16
+ This is an internal error that should not occur.
17
+ Try running the \`init\` command again.
18
+
19
+ If the problem persists, please report this issue at
20
+ https://github.com/sugarcube-org/sugarcube/issues`,"INITIALIZATION_INCOMPLETE"),CONFIG_WRITE_FAILED:o(()=>"Failed to write configuration file. Check permissions and try again.","CONFIG_WRITE_FAILED"),DIRECTORY_PATH_EMPTY:o(e=>`${e} cannot be empty. Please provide a valid directory path.`,"DIRECTORY_PATH_EMPTY"),DIRECTORY_PATH_RESERVED:o((e,t)=>`Option: ${e}
21
+ Value: "${t}"
22
+
23
+ ${e} cannot be in a reserved directory`,"DIRECTORY_PATH_RESERVED"),KIT_INCOMPLETE:o(()=>`The starter kit appears to be incomplete or corrupted.
24
+
25
+ This is likely a temporary issue. Please try running the command again or choose a different starter kit.`,"KIT_INCOMPLETE"),REGISTRY_AUTH_REQUIRED:o(e=>`Registry access denied: Authentication required
26
+ URL: ${c.cyan(e)}`,"REGISTRY_AUTH_REQUIRED"),REGISTRY_AUTH_INVALID:o(e=>`Registry access denied: Invalid or missing token
27
+ URL: ${c.cyan(e)}`,"REGISTRY_AUTH_INVALID"),REGISTRY_NOT_FOUND:o(e=>`Registry resource not found
28
+ URL: ${c.cyan(e)}`,"REGISTRY_NOT_FOUND"),REGISTRY_REQUEST_FAILED:o((e,t)=>`Registry request failed: ${e}
29
+ URL: ${c.cyan(t)}`,"REGISTRY_REQUEST_FAILED"),REGISTRY_NETWORK_ERROR:o(e=>`Failed to connect to registry
30
+
31
+ URL: ${c.cyan(e)}
32
+
33
+ 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:o(e=>`Invalid registry data received
34
+ URL: ${c.cyan(e)}`,"REGISTRY_INVALID_DATA"),REGISTRY_ITEM_NOT_FOUND:o((e,t,n)=>`${e==="tokens"?"Starter kit":e}'${c.cyan(t)} ' not found in registry
35
+ Available ${e==="tokens"?"starter kit":e}s: ${n.join(", ")}`,"REGISTRY_ITEM_NOT_FOUND"),REGISTRY_FILE_INVALID:o(e=>`Invalid file content received
36
+ File: ${c.cyan(e)}`,"REGISTRY_FILE_INVALID"),STARTER_KIT_UNAVAILABLE:o(e=>`Starter kit '${c.cyan(e)}' is currently unavailable.
37
+
38
+ Please try a different starter kit or run the command again in a few minutes.`,"STARTER_KIT_UNAVAILABLE"),TOKEN_LOAD_FAILED:o(e=>`Failed to load token files:
39
+
40
+ ${e.join(`
41
+ `)}
42
+
43
+ Please check your token files and try again.`,"TOKEN_LOAD_FAILED"),TOKEN_VALIDATION_FAILED:o(e=>{let t=`Token validation failed:
44
+
45
+ `;for(const[n,s]of e){t+=`Error(s) in ${c.cyan(n)}:
46
+ `;for(const r of s)t+=` - ${r}
47
+ `;t+=`
48
+ `}return t+=`See ${c.cyan("https://sugarcube.sh/docs/design-tokens")} for valid token formats`,t},"TOKEN_VALIDATION_FAILED"),TOKEN_FILE_INVALID_JSON:o(e=>`File ${e}: Invalid JSON syntax`,"TOKEN_FILE_INVALID_JSON"),TOKEN_FILE_INCOMPLETE_JSON:o(e=>`File ${e}: Incomplete JSON file`,"TOKEN_FILE_INCOMPLETE_JSON"),TOKEN_FILE_GENERIC_ERROR:o((e,t)=>`File ${e}: ${t}`,"TOKEN_FILE_GENERIC_ERROR"),DEPENDENCY_INSTALL_FAILED:o(e=>`Failed to install dependencies using ${e}.
49
+ Please check your package manager configuration and try again.`,"DEPENDENCY_INSTALL_FAILED"),VALIDATE_NO_PATH_SPECIFIED:o(()=>`No path specified.
50
+
51
+ Run ${c.cyan("make-sugarcube validate --help")} for more information.`,"VALIDATE_NO_PATH_SPECIFIED"),VALIDATE_PATH_NOT_FOUND:o(e=>`Path not found: ${e}
52
+
53
+ Please check that the specified path exists`,"VALIDATE_PATH_NOT_FOUND"),VALIDATE_NO_TOKEN_FILES:o(()=>`No token files found.
54
+
55
+ Please ensure the path contains .json token files`,"VALIDATE_NO_TOKEN_FILES"),COMPONENTS_FRAMEWORK_REQUIRED:o(()=>`Framework is required when specifying components. Use --framework to specify a framework (react, css-only) or run without arguments for interactive mode.
56
+
57
+ See ${c.cyan("https://sugarcube.sh/docs/cli/components")} for more information.`,"COMPONENTS_FRAMEWORK_REQUIRED"),COMPONENTS_INVALID_FRAMEWORK:o(()=>"Invalid framework. Must be one of: react, css-only.","COMPONENTS_INVALID_FRAMEWORK"),COMPONENTS_DIRECTORY_NOT_CONFIGURED:o(()=>"Components directory must be configured in non-interactive mode. Please run the 'components' command without arguments first.","COMPONENTS_DIRECTORY_NOT_CONFIGURED"),PLUGIN_DETECTED:o(e=>`Plugin detected: ${e}
58
+
59
+ The 'generate' command is for manual generation without plugins. Since you have a plugin installed, use your development server instead:
60
+
61
+ npm run dev # or your framework's dev command
62
+
63
+ The plugin will automatically generate CSS with hot module replacement.`,"PLUGIN_DETECTED")};class g extends Error{static{o(this,"CLIError")}constructor(t,n){super(t),this.name="CLIError",this.cause=n}}const le=m.enum(["react","web-components","css-only"]),_e=m.object({path:m.string(),type:m.string()}),kt=_e.extend({framework:le});m.object({themes:m.record(m.string(),m.array(m.string())).optional()}).strict();const Et=m.object({name:m.string(),type:m.string(),description:m.string().optional(),frameworks:m.array(m.string()).optional(),files:m.array(m.union([kt,_e])),tokens:m.record(m.object({type:m.string(),mapping:m.string()})).optional(),dependencies:m.record(le,m.array(m.string())).optional(),registryDependencies:m.record(le,m.array(m.string())).optional(),tokenDependencies:m.array(m.string()).optional()}),bt=m.array(Et),Ct=m.object({content:m.string()}),De=process.env.REGISTRY_URL??"https://sugarcube.sh/r";async function ve(e){try{const t=await Ze(e);if(!t.ok){if(t.status===401)throw new g(w.REGISTRY_AUTH_REQUIRED(e));if(t.status===403)throw new g(w.REGISTRY_AUTH_INVALID(e));if(t.status===404)throw new g(w.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 g(w.REGISTRY_REQUEST_FAILED(s,e))}return t.json()}catch(t){throw t instanceof g?t:new g(w.REGISTRY_NETWORK_ERROR(e))}}o(ve,"fetchRegistry");async function M(){const e=`${De}/index.json`,t=await ve(e);try{return bt.parse(t)}catch{throw new g(w.REGISTRY_INVALID_DATA(e))}}o(M,"getRegistryIndex");async function ue({type:e,name:t,framework:n}){const s=await M(),r=s.find(a=>a.type===e&&a.name===t);if(!r){const a=s.filter(l=>l.type===e).map(l=>l.name);throw new g(w.REGISTRY_ITEM_NOT_FOUND(e,t,a))}let i=r.files;e==="component"&&n&&(i=r.files.filter(a=>"framework"in a&&a.framework===n));const u=await Promise.all(i.map(async a=>{const l=`${De}/${a.path}.json`,f=await ve(l);try{const p=Ct.parse(f);return{path:a.path,type:a.type,framework:"framework"in a?a.framework:void 0,content:p.content}}catch{throw new g(w.REGISTRY_FILE_INVALID(a.path))}}));return{item:r,files:u}}o(ue,"getRegistryFiles");async function $t(e){const t=await ue({type:"tokens",name:e});if(!t.files[0])throw new g(w.STARTER_KIT_UNAVAILABLE(e));return t}o($t,"fetchStarterKit");async function fe(e,t,n){const s=[],r=new Set;async function i(u){if(r.has(u))return;r.add(u);const a=e.find(f=>f.name===u);if(!a){const f=e.filter(p=>p.type==="component").map(p=>p.name).join(", ");throw new g(`Component '${u}' not found in registry
64
+ Available components: ${f}`)}const l=a.registryDependencies?.[n]||[];for(const f of l)await i(f);s.push(a)}o(i,"resolveComponent");for(const u of t)await i(u);return s}o(fe,"resolveTree");async function Rt({selectedComponents:e,componentType:t,componentsOutputDirectory:n}){const s={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},r=await M(),u=(await fe(r,e,t)).map(p=>p.name),a=r.filter(p=>p.type==="component").filter(p=>u.includes(p.name)),l=a.flatMap(p=>p.files.filter(d=>(d.type==="tsx"||d.type==="astro"||d.type==="njk")&&"framework"in d&&d.framework===t).map(d=>R(process.cwd(),$(n,p.name,`${p.name}.${d.type}`))));s.componentFiles=l.filter(p=>N($(process.cwd(),p)));const f=a.map(p=>{const d=p.name;return R(process.cwd(),$(n,p.name,`${d}.css`))});return s.componentCSS=f.filter(p=>N($(process.cwd(),p))),s}o(Rt,"collectComponentOverwriteWarnings");async function _t({cubeDirectory:e}){const t={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},s=(await M()).filter(r=>r.type==="cube").flatMap(r=>r.files).map(r=>{const i=r.path.replace(/^styles\//,"");return R(process.cwd(),$(e,i))});return t.cubeCSS=s.filter(r=>N($(process.cwd(),r))),t}o(_t,"collectCubeOverwriteWarnings");function Ae(e){const t=[];if(e.variableCSS.length>0&&t.push(`CSS variables files:
65
+ ${e.variableCSS.map(s=>` - ${s}`).join(`
66
+ `)}`),e.utilityCSS.length>0&&t.push(`CSS utility files:
67
+ ${e.utilityCSS.map(s=>` - ${s}`).join(`
68
+ `)}`),e.cubeCSS.length>0&&t.push(`CUBE CSS files:
69
+ ${e.cubeCSS.map(s=>` - ${s}`).join(`
70
+ `)}`),e.componentFiles.length>0||e.componentCSS.length>0){const s=[...e.componentFiles,...e.componentCSS];t.push(`Component files:
71
+ ${s.map(r=>` - ${r}`).join(`
72
+ `)}`)}return e.indexFiles.length>0&&t.push(`Index files:
73
+ ${e.indexFiles.map(s=>` - ${s}`).join(`
74
+ `)}`),t.length===0?void 0:`The following file(s) already exist and will be overwritten:
75
+
76
+ ${t.join(`
77
+
78
+ `)}`}o(Ae,"formatOverwriteWarnings");async function pe(e,t,n){if(e.length===0)return;const s=n==="npm"?"install":"add";try{await Xe(n,[s,...e],{cwd:t})}catch{throw new g(w.DEPENDENCY_INSTALL_FAILED(n))}}o(pe,"installDependencies");async function Dt(e,t,n){const s=$(n,t.name);if(await W(s,{recursive:!0}),e.path.endsWith(".css")){const i=$(s,`${t.name}.css`);return await X(i,e.content),i}const r=$(s,x(e.path));return await X(r,e.content),r}o(Dt,"writeComponentFile");async function vt({registryIndex:e,selectedComponents:t,componentType:n,componentsOutputDirectory:s,packageManager:r}){const i=[],u=new Set;await W(s,{recursive:!0});const a=await fe(e,t,n);for(const l of a){const f=await ue({type:"component",name:l.name,framework:n});for(const d of f.files)if(d)try{const h=await Dt(d,l,s);h&&i.push(h)}catch(h){const E=h instanceof Error?`: ${h.message}`:"";throw new g(`Failed to write component file for "${l.name}"${E}`)}const p=l.dependencies?.[n]||[];for(const d of p)u.add(d)}if(u.size>0)try{await pe(Array.from(u),process.cwd(),r)}catch(l){const f=l instanceof Error?`: ${l.message}`:"";throw new g(`Failed to install component dependencies${f}`)}return{createdFiles:i,npmDependencies:u}}o(vt,"installComponents");async function At(e){const t=[],n=Q(process.cwd(),e);await W(n,{recursive:!0});const r=(await M()).filter(i=>i.type==="cube").map(i=>i.name);for(const i of r){const u=await ue({type:"cube",name:i});for(const a of u.files){if(!a)continue;const l=a.path.replace(/^styles\//,""),f=$(n,l),p=qe(f);try{await W(p,{recursive:!0}),await X(f,a.content),t.push(f)}catch(d){const h=d instanceof Error?`: ${d.message}`:"";throw new g(`Failed to write CUBE module "${i}"${h}`)}}}return t}o(At,"installCUBE");async function Ft(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}o(Ft,"writeTokenFiles");async function B(e,t){const n={type:"files",config:e},{trees:s,resolved:r,errors:i}=await et(n);if(i.load.length>0){const u=i.load.map(a=>{const l=a.file.split("/").pop()||"unknown file";let f=`File ${l}: `;return a.message.includes("Unexpected token")?f=w.TOKEN_FILE_INVALID_JSON(l):a.message.includes("Unexpected end")?f=w.TOKEN_FILE_INCOMPLETE_JSON(l):f=w.TOKEN_FILE_GENERIC_ERROR(l,a.message),f});throw new g(w.TOKEN_LOAD_FAILED(u))}if(i.validation.length>0||i.flatten.length>0||i.resolution.length>0){const u=[...i.flatten,...i.validation,...i.resolution],a=new Map;for(const l of u)if(l.source?.sourcePath){const f=a.get(l.source.sourcePath)||[];f.push(l.message),a.set(l.source.sourcePath,f)}throw new g(w.TOKEN_VALIDATION_FAILED(a))}return{trees:s,resolved:r}}o(B,"loadAndResolveTokensForCLI");function Nt(e,t){const n={...e};return Object.keys(t).length>0&&typeof n.tokens=="object"&&!Array.isArray(n.tokens)&&"source"in n.tokens&&(n.tokens.themes=t),tt(n)}o(Nt,"integrateThemesIntoConfig");const{hidden:gs}=c,Ot=it(),k=o((e,t)=>Ot?e:t,"unicodeOr"),Pt=k("\u25C7","o"),Fe=k("\u250C","T"),O=k("\u2502","|"),de=k("\u2514","\u2014"),Lt=k("\u2510","T"),Mt=k("\u2518","\u2014"),te=k("\u2500","-"),jt=k("\u256E","+"),Ut=k("\u256F","+"),xt=k("\u2570","+"),Wt=k("\u256D","+"),Gt=k("\u25CF","\u2022"),Bt=k("\u25C6","*"),Vt=k("\u25B2","!"),Kt=k("\u25A0","x"),V=o((e,t=c.bgGreen,n=c.black)=>t(` ${n(e)} `),"label"),K=o(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"),Y=o((e="",t)=>{process.stdout.write(`
79
+
80
+ ${c.gray(Fe)}${c.gray(te)} ${e}
81
+ `)},"intro"),ne=o((e="",t)=>{process.stdout.write(`${c.gray(O)}
82
+ ${c.gray(de)}${c.gray(te)} ${e}
83
+
84
+ `)},"outro");function Yt(...e){process.env.DEBUG==="true"&&process.stderr.write(`[sugarcube:debug] ${e.map(String).join(" ")}
85
+ `)}o(Yt,"debugLog");function j(e){return new Promise(t=>setTimeout(t,e))}o(j,"sleep");function Ht(e,t){const n={};if(e.themes)for(const[s,r]of Object.entries(e.themes))n[s]=r.map(i=>{const u=t[i];if(!u)throw new g(w.KIT_INCOMPLETE());return u});return n}o(Ht,"processKitThemes");const Jt=o(async(e,t,n)=>{const s=await $t(e),r=Q(process.cwd(),t),i=s.files.find(d=>x(d.path)==="config.json");let u={};if(i)try{u=JSON.parse(i.content)}catch(d){Yt(`Could not parse config.json for starter kit '${e}':`,d)}const a=s.files.filter(d=>x(d.path)!=="config.json").map(d=>({path:$(r,x(d.path)),content:d.content})),l=Object.fromEntries(a.map(d=>[x(d.path),R(process.cwd(),d.path)])),f=Ht(u,l);return{config:Nt(n,f),tokenFiles:a,tokensDir:r,createdTokenPaths:a.map(d=>R(process.cwd(),d.path))}},"prepareStarterKitForInstall");async function qt(e){const t=await Jt(e.starterKit??"",e.tokensDir,e.config),n=await Ft(t.tokenFiles,e.tokensDir),{trees:s,resolved:r}=await B(e.config);e.setupResult={config:t.config,createdTokenPaths:t.createdTokenPaths,trees:s,resolved:r,tokenFiles:t.tokenFiles,tokensDir:t.tokensDir},e.createdFiles.push(...n)}o(qt,"installFromStarterKit");async function Ne(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 ct({message:"Build with",options:t});return ae(n)&&process.exit(0),n==="web-components"?(lt.info(c.blue("Web components are coming soon! Please choose React or CSS Only for now.")),Ne(e)):n}o(Ne,"promptComponentFramework");async function zt(e,t){const n=e.filter(r=>r.type==="component"&&r.frameworks?.includes(t)),s=await ut({message:"Select components to add",options:n.map(r=>({label:r.name,value:r.name,hint:r.description})),required:!0});return ae(s)&&process.exit(0),s}o(zt,"promptComponentSelectionFiltered");async function Oe(e,t=!1){const n=await ft({message:e,initialValue:t});return(!n||ae(n))&&(ke(),process.exit(0)),!0}o(Oe,"confirmOverwrite");const Zt=[Wt,jt,xt,Ut],Qt=[Fe,Lt,de,Mt];function Pe(e,t,n,s){let r=n,i=n;return s==="center"?r=Math.floor((t-e)/2):s==="right"&&(r=t-e-n),i=t-r-e,[r,i]}o(Pe,"getPaddingForLine");const Xt=o(e=>e,"defaultFormatBorder"),ge=o((e="",t="",n)=>{const s=n?.output??process.stdout,r=pt(s),u=1*2,a=n?.titlePadding??1,l=n?.contentPadding??2,f=n?.width===void 0||n.width==="auto"?1:Math.min(1,n.width),p=n?.includePrefix?`${O} `:"",d=n?.formatBorder??Xt,h=(n?.rounded?Zt:Qt).map(d),E=d(te),b=d(O),T=r-p.length;let C=Math.floor(r*f)-p.length;if(n?.width==="auto"){const z=e.split(`
86
+ `);let U=K(t).length+a*2;for(const He of z){const we=K(He).length+l*2;we>U&&(U=we)}const Z=U+u;Z<C&&(C=Z)}C%2!==0&&(C<T?C++:C--);const I=C-u,F=I-a*2,y=K(t).length>F?`${t.slice(0,F-3)}...`:t,[_,D]=Pe(K(y).length,I,a,n?.titleAlign),P=dt(e,I-l*2,{hard:!0,trim:!1});s.write(`${p}${h[0]}${E.repeat(_)}${y}${E.repeat(D)}${h[1]}
87
+ `);const q=P.split(`
88
+ `);for(const z of q){const[U,Z]=Pe(K(z).length,I,l,n?.contentAlign);s.write(`${p}${b}${" ".repeat(U)}${z}${" ".repeat(Z)}${b}
89
+ `)}s.write(`${p}${h[2]}${E.repeat(I)}${h[3]}
90
+ `)},"box");function me(e,t={}){const n=`
91
+ ${e}`;ge(n,c.black(c.bgRed(" ERROR ")),{width:"auto",titlePadding:2,formatBorder:c.red,...t})}o(me,"errorBoxWithBadge");function Le(e,t={}){const n=`
92
+ ${e}`;ge(n,c.black(c.bgYellow(" WARNING ")),{width:"auto",titlePadding:2,formatBorder:c.yellow,...t})}o(Le,"warningBoxWithBadge");function en(e,t={}){const n=`
93
+ ${e}`;ge(n,c.black(c.bgCyan(" INFO ")),{width:"auto",titlePadding:2,formatBorder:c.cyan,...t})}o(en,"infoBoxWithBadge");const tn=o((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"),nn=o(async(e,t={})=>{const{sidebarSymbol:n=c.gray("\u2502"),clear:s=!1,stdin:r=process.stdin,stdout:i=process.stdout}=t,u=be.createInterface({input:r,escapeCodeTimeout:50}),a=Ce(i,{showCursor:!1});be.emitKeypressEvents(r,u);let l=0,f=!1;const p=o(async()=>{r.off("keypress",d),r.isTTY&&r.setRawMode(!1),u.close(),f=!0,l<e.length-1||s?a.clear():a.done()},"done"),d=o((h,E)=>{r.isTTY&&r.setRawMode(!0);const b=tn(E);if(b==="abort")return p(),process.exit(0);["up","down","left","right"].includes(b)||p()},"handleKeyPress");r.isTTY&&r.setRawMode(!0),r.on("keypress",d);for(const h of e){const E=Array.isArray(h)?h:h.split(" "),b=[];for(const I of[""].concat(E)){I&&b.push(I);const F=b.join(" ").replace(/sugarcube/g,c.cyan("sugarcube")),y=`${n} ${F}`;a(y),f||await new Promise(_=>setTimeout(_,Math.floor(Math.random()*126)+75))}f||await new Promise(I=>setTimeout(I,100));const C=(await Promise.all(E).then(I=>I.join(" "))).replace(/sugarcube/g,c.cyan("sugarcube"));a(`${n} ${C}`),f||await new Promise(I=>setTimeout(I,Math.floor(Math.random()*201)+1200)),l++}r.off("keypress",d),await new Promise(h=>setTimeout(h,100)),p(),r.isTTY&&r.setRawMode(!1),r.removeAllListeners("keypress")},"sayAnimatedInSidebar");function sn(){return Math.floor(Math.random()*551)+200}o(sn,"getRandomTaskDuration");async function on(e,{sidebarSymbol:t="\u2502",spacing:n=1,stdin:s=process.stdin,stdout:r=process.stdout,initialDelayMs:i=200,minDurationMs:u,successPauseMs:a=300,successMessage:l,successAsOutro:f=!1}={}){const p=o((y,_)=>{let D="";switch(_){case"start":D=`${c.cyan(`\u25B6 ${y.start}`)}`;break;case"pending":D=`${c.dim(`\u25A1 ${y.pending}`)}`;break;case"success":D=`${c.green(`\u2714 ${y.end}`)}`;break;case"end":D=`${c.dim(`\u25A0 ${y.end}`)}`;break}return`${t} ${D}`},"formatWithSidebar"),d=Array.from({length:e.length},()=>"");e.forEach((y,_)=>{d[_]=p(y,"pending")});const h=Ce(r),E=Ee.createInterface({input:s,escapeCodeTimeout:50});Ee.emitKeypressEvents(s,E);const b=o(y=>{y===""&&(h.clear(),E.close(),s.isTTY&&s.setRawMode(!1),process.exit(0)),s.isTTY&&s.setRawMode(!0)},"keypress");s.isTTY&&s.setRawMode(!0),s.on("keypress",b);const T=Array.from({length:Math.max(n,0)},()=>`${t}`),C=o(()=>[...T,...d].join(`
94
+ `),"renderContent");h(C()),await j(i);let I=0;for(const y of e){d[I]=p(y,"start"),h(C());const _=Date.now(),D=y.while();try{await D;const P=Date.now()-_,q=typeof u=="number"?u:sn();P<q&&await j(q-P),d[I]=p(y,"success"),h(C()),await j(a)}catch(P){throw d[I]=`${t} ${c.red(`\u2717 ${y.end} (failed)`)}`,h(C()),y.onError?.(P),s.removeListener("keypress",b),E.close(),s.isTTY&&s.setRawMode(!1),P}I++}const F=e.map(y=>p(y,"end"));if(l)if(f){const y=`${c.gray(de)}${c.gray(te)} ${c.green(l)}`;h([...T,...F,`${t}`,y].join(`
95
+ `))}else{const y=`${t} ${c.green(l)}`;h([...T,...F,`${t}`,y].join(`
96
+ `))}else h([...T,...F].join(`
97
+ `));await j(1e3),s.removeListener("keypress",b),s.isTTY&&s.setRawMode(!1),E.close(),h.done()}o(on,"executeTasksInSidebar");const rn=o(e=>process.stdout.write(`${e}
98
+ `),"rawLog"),S={message:o((e=[],{symbol:t=c.gray(O),secondarySymbol:n=c.gray(O),output:s=process.stdout,spacing:r=1}={})=>{const i=[];for(let a=0;a<r;a++)i.push(`${n}`);const u=Array.isArray(e)?e:e.split(`
99
+ `);if(u.length>0){const[a,...l]=u;a&&a.length>0?i.push(`${t} ${a}`):i.push(t);for(const f of l)f.length>0?i.push(`${n} ${f}`):i.push(n)}s.write(`${i.join(`
100
+ `)}
101
+ `)},"message"),info:o((e,t)=>{S.message(e,{...t,symbol:c.blue(Gt)})},"info"),success:o((e,t)=>{S.message(e,{...t,symbol:c.green(Bt)})},"success"),step:o((e,t)=>{S.message(e,{...t,symbol:c.green(Pt)})},"step"),warn:o((e,t)=>{S.message(e,{...t,symbol:c.yellow(Vt)})},"warn"),error:o((e,t)=>{S.message(e,{...t,symbol:c.red(Kt)})},"error"),animated:o(async(e,{secondarySymbol:t=c.gray(O),output:n=process.stdout,clear:s=!1,...r}={})=>nn(e,{sidebarSymbol:t,stdout:n,clear:s,...r}),"animated"),tasks:o(async(e,{spacing:t=1,secondarySymbol:n=c.gray(O),output:s=process.stdout,...r}={})=>on(e,{sidebarSymbol:n,spacing:t,stdout:s,...r}),"tasks"),space:o((e=1)=>{for(let t=0;t<e;t++)process.stdout.write(`${c.gray(O)}
102
+ `)},"space"),break:o((e=1)=>{for(let t=0;t<e;t++)process.stdout.write(`
103
+ `)},"break")};function H(e){if(e instanceof g)S.space(1),me(e.message,{});else{const t=`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
104
+
105
+ If this issue persists, please report it: ${c.cyan("https://github.com/sugarcube-org/sugarcube/issues")}`;S.space(1),me(t,{})}process.exit(0)}o(H,"handleError");function Me(e){return{absolute:Q(process.cwd(),e)}}o(Me,"resolveDirectoryFromFlag");async function je(e){if(v())try{const{config:t}=await ee(),n=an(t,e);return typeof n=="string"?Q(process.cwd(),n):void 0}catch{return}}o(je,"resolveDirectoryFromConfig");function an(e,t){const n=t.split(".");let s=e;for(const r of n){if(s==null||typeof s!="object")return;s=s[r]}return s}o(an,"getNestedValue");async function cn(e){if(e){const{absolute:t}=Me(e);return{directory:t,fromConfig:!1}}if(v())try{const t=await je("output.css");if(t)return{directory:t,fromConfig:!0}}catch{}throw new g(`A sugarcube config file was not found.
106
+
107
+ Either a config file or --styles-dir is required to run this command.
108
+
109
+ To use the cube command without a config file:
110
+ e.g. ${c.cyan(`${A.CUBE} --styles-dir src/styles`)}
111
+
112
+ To create a config file:
113
+ ${c.cyan(A.INIT)}
114
+
115
+ Stuck? ${c.cyan("https://sugarcube.sh")}`)}o(cn,"getCssDir");async function ln(e){if(e){const{absolute:t}=Me(e);return{directory:t,fromConfig:!1}}if(v())try{const t=await je("output.components");if(t)return{directory:t,fromConfig:!0}}catch{}throw new g(`A sugarcube config file was not found.
116
+
117
+ Either a config file or --components-dir is required to run this command.
118
+
119
+ To use the components command without a config file:
120
+ e.g. ${c.cyan(`${A.COMPONENTS} --components-dir src/components/ui`)}
121
+
122
+ To create a config file:
123
+ ${c.cyan(A.INIT)}
124
+
125
+ Stuck? ${c.cyan("https://sugarcube.sh")}`)}o(ln,"getComponentsDir");function J(e,t=process.cwd()){try{const n=at(t,"package.json");if(!N(n))return!1;const s=ye(n,"utf-8"),r=JSON.parse(s),i={...r.dependencies,...r.devDependencies,...r.peerDependencies};return e in i}catch{return!1}}o(J,"isPackageInstalled");async function Ue(e,{withFallback:t=!1}={}){const n=await gt({programmatic:!0,cwd:e});if(n?.startsWith("yarn@"))return"yarn";if(n?.startsWith("pnpm@"))return"pnpm";if(n==="bun")return"bun";if(!t)return n?.split("@")[0]??"npm";const s=process.env.npm_config_user_agent||"";return s.startsWith("yarn")?"yarn":s.startsWith("pnpm")?"pnpm":s.startsWith("bun")?"bun":"npm"}o(Ue,"getPackageManager");function un(e=process.cwd()){return mt(e)!==null}o(un,"isTypeScriptProject");async function xe(e=process.cwd()){return un(e)?"sugarcube.config.ts":"sugarcube.config.js"}o(xe,"getConfigFileName");function fn(e){return/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(e)}o(fn,"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?"[]":`[
126
+ ${e.map(r=>`${n} ${he(r,t+1)}`).join(`,
127
+ `)}
128
+ ${n}]`;if(typeof e=="object"){const s=Object.entries(e);return s.length===0?"{}":`{
129
+ ${s.map(([i,u])=>{const a=fn(i)?i:JSON.stringify(i);return`${n} ${a}: ${he(u,t+1)}`}).join(`,
130
+ `)}
131
+ ${n}}`}return JSON.stringify(e)}o(he,"formatValue");function pn(e,t){const n=he(e,0);return`${t?`import type { UserConfig } from "@sugarcube-org/core";
132
+
133
+ const config: UserConfig = `:`/**
134
+ * @type {import('@sugarcube-org/core').UserConfig}
135
+ */
136
+ const config = `}${n};
137
+
138
+ export default config;
139
+ `}o(pn,"formatConfigAsCode");async function We(e){try{const t=await xe(),n=t.endsWith(".ts"),s=pn(e,n);await X(t,s,"utf-8")}catch(t){const n=t instanceof Error?`: ${t.message}`:"";throw new g(`Failed to write config file${n}`)}}o(We,"writeUserConfig");function dn(e,t){return{...e,...t,output:{...e.output??{},...t.output??{}},transforms:{...e.transforms??{},...t.transforms??{}}}}o(dn,"mergeUserConfig");async function Ge(e){const{config:t}=await nt(),n=dn(t,e);await We(n)}o(Ge,"mergeConfigIntoFile");const gn=new L().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||Y(V(c.bgGreen(c.black("Components"))));const{directory:n,fromConfig:s}=await ln(t.componentsDir);let r=[],i;if(e.length>0||t.framework){if(!t.framework)throw new g(w.COMPONENTS_FRAMEWORK_REQUIRED());if(!["react","css-only"].includes(t.framework))throw new g(w.COMPONENTS_INVALID_FRAMEWORK());i=t.framework,r=e}else{i=await Ne(!1);const T=await M();T||(ke("Failed to fetch component list"),process.exit(1)),r=await zt(T,i)}const u=await Ue(process.cwd(),{withFallback:!0}),a=await M(),l=await fe(a,r,i),f=await Rt({selectedComponents:r,componentType:i,componentsOutputDirectory:n}),p=Ae(f);if(p&&!t.force&&!t.silent){const T=Le(p,{});S.space(1),await Oe("Continue?",!1)}const d=[],h=[],E=new Set;for(const T of l){const C=T.dependencies?.[i]||[];for(const I of C)E.add(I)}const b=Array.from(E).filter(T=>!J(T,process.cwd()));b.length>0&&d.push({pending:`Install ${b.length} dependencies`,start:`Installing ${b.join(", ")}...`,end:`Installed ${b.join(", ")}`,while:o(async()=>{await pe(b,process.cwd(),u)},"while")});for(const T of l)d.push({pending:`Write component files for ${T.name}`,start:`Writing component files for ${T.name}...`,end:`Wrote component files for ${T.name}`,while:o(async()=>{const C=await vt({registryIndex:a,selectedComponents:[T.name],componentType:i,componentsOutputDirectory:n,overwrite:t.overwrite||!1,packageManager:u});h.push(...C.createdFiles)},"while")});if(await S.tasks(d,{successMessage:"Components added successfully! \u{1F389} ",minDurationMs:0,successAsOutro:!0}),rn(""),!s&&v()){const T=R(process.cwd(),n);await Ge({output:{components:T}})}}catch(n){H(n)}}),mn=new L().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").option("-f, --force","Skip overwrite confirmation").option("--styles-dir <dir>","CSS output directory (e.g., 'src/styles')").action(async e=>{try{e.silent||Y(V("CUBE CSS"));const{directory:t,fromConfig:n}=await cn(e.stylesDir);try{await W(t,{recursive:!0})}catch(u){const a=u instanceof Error?`: ${u.message}`:"";throw new g(`Failed to create output directory${a}`)}const s=await _t({cubeDirectory:t}),r=Ae(s);if(r&&!e.force&&!e.silent){S.space(1);const u=Le(r,{});await Oe("Continue?",!1)}const i=await At(t);if(!e.silent){S.space(1);const u=i,f=[...new Set(u)].map(p=>R(process.cwd(),p)).map(p=>({pending:`Write ${p}`,start:`Writing ${p}`,end:`Wrote ${p}`,while:o(async()=>{},"while")}));await S.tasks(f,{spacing:0,minDurationMs:0,successPauseMs:100,successMessage:"\u{1F389} Files written!"}),ne(c.green("CUBE added successfully."))}if(!n&&v()){const u=R(process.cwd(),t);await Ge({output:{css:u}})}}catch(t){H(t)}});function hn(){return["**/*.{html,htm,js,ts,jsx,tsx,vue,svelte,astro,php,njk,liquid,pug,hbs,handlebars,twig,erb,ejs}","!node_modules/**","!dist/**","!build/**","!.next/**","!.nuxt/**","!.astro/**","!.git/**","!coverage/**","!*.config.{js,ts,mjs}"]}o(hn,"getDefaultScanPatterns");function wn(){return hn()}o(wn,"getScanPatterns");async function Be(e,t){const n={name:"sugarcube",rules:st(t.utilities??{},e),preflights:[]},s=await ht({presets:[n]}),r=wn(),i=await G(r,{dot:!0});if(i.length===0)return[];const a=(await Promise.all(i.map(f=>Qe(f,"utf8")))).join(`
140
+ `),{css:l}=await s.generate(a,{preflights:!1});return l?.trim()?[{path:`${t.output?.css||ot}/utilities/utilities.gen.css`,css:l,collection:"default"}]:[]}o(Be,"generateSugarcubeUtilities");async function yn(e,t,n){const s=[],r=await oe(e,t,n),i=await Te(r,n);await Se(i),s.push(...i);const u=await Be(r,n);return await Ie(u),s.push(...u),s}o(yn,"generateAllCSS");const Tn=new L().name("generate").description("Generate CSS from your design tokens").option("--force","Skip overwrite confirmation").option("-s, --silent","Suppress logs and prompts").action(async e=>{try{if(e.silent||Y(V("Generate CSS")),J("@sugarcube-org/vite"))throw new g("Sugarcube vite plugin detected. When using the plugin, CSS is generated automatically during your build process. Remove the plugin to use CLI generation instead.");if(!v())throw new g(`A sugarcube config file was not found. This command requires one.
141
+
142
+ Please run ${c.cyan(A.INIT)} (or manually create a config file).
143
+
144
+ Stuck? ${c.cyan("https://sugarcube.sh")}`);const{config:t}=await ee(),{trees:n,resolved:s}=await B(t),r=await yn(n,s,t);if(!e.silent){const i=r.map(f=>f.path),l=[...new Set(i)].map(f=>R(process.cwd(),f)).map(f=>({pending:`Write ${f}`,start:`Writing ${f}`,end:`Wrote ${f}`,while:o(async()=>{},"while")}));await S.tasks(l,{spacing:1,minDurationMs:0,successPauseMs:100,successMessage:"\u{1F389} Files written!"}),S.space(1),ne(c.green("CSS generated successfully."))}}catch(t){H(t)}});function Sn(e){return{source:[$(R(process.cwd(),e.actualTokensDir),$e)]}}o(Sn,"createSingleTokenCollection");async function In(e){return Sn(e)}o(In,"buildTokensConfig");async function kn(e){const t=await In({actualTokensDir:e.actualTokensDir}),n=R(process.cwd(),e.actualStylesDir),s=e.isSrcDir?re.output.components:re.output.components.replace(/^src\//,"");return{tokens:t,output:{css:n,components:s,separate:re.output.separate}}}o(kn,"buildUserConfig");function Ve(e,t=0){if(typeof e!="object"||e===null||t>St)return!1;for(const[n,s]of Object.entries(e))if(!n.startsWith("$")&&typeof s=="object"&&s!==null&&("$value"in s||Ve(s,t+1)))return!0;return!1}o(Ve,"hasAnyToken");async function En(e){try{const t=await G($e,{cwd:e,absolute:!0});for(const n of t)try{const s=await se.readFile(n,"utf-8"),r=JSON.parse(s);if(Ve(r))return!0}catch{}return!1}catch{return!1}}o(En,"detectExistingTokens");const Ke=["**/node_modules/**",".next","public","dist","build",".astro",".nuxt",".output",".svelte-kit"];function bn(e){try{const t=ie.resolve(e,"package.json");if(!N(t))return null;const n=ye(t,"utf-8");return JSON.parse(n)}catch{return null}}o(bn,"getPackageJson");async function Cn(e){const[t,n,s]=await Promise.all([G.glob("**/{next,vite,astro,nuxt,svelte,remix,eleventy}.config.*|.eleventy.js",{cwd:e,deep:3,ignore:Ke}),N(ie.resolve(e,"src")),bn(e)]),r=n?"src/design-tokens":"design-tokens",i=n?"src/styles":"styles",u=n?"src/components":"components";let a="none";return t.find(l=>l.startsWith("next.config."))?.length?a=N(ie.resolve(e,`${n?"src/":""}app`))?"next-app":"next-pages":t.find(l=>l.startsWith("astro.config."))?.length?a="astro":t.find(l=>l.startsWith("nuxt.config."))?.length?a="nuxt":t.find(l=>l.startsWith("svelte.config."))?.length?a="sveltekit":Object.keys(s?.dependencies??{}).find(l=>l.startsWith("@remix-run/"))?a="remix":t.find(l=>l.startsWith("eleventy.config.")||l.startsWith(".eleventy."))?.length?a="eleventy":t.find(l=>l.startsWith("vite.config."))?.length&&(a="vite"),{framework:a,isSrcDir:n,tokensDir:r,stylesDir:i,componentDir:u}}o(Cn,"getProjectInfo");async function $n(e,t){return!!((await G.glob("vite.config.*",{cwd:e,deep:1,ignore:Ke})).length>0||["vite","astro","nuxt","sveltekit","remix"].includes(t))}o($n,"shouldInstallVitePlugin");const Rn=o(async e=>{S.space(2),await j(200);let t="Next steps";if(e.pluginToInstall===Re)t+=`
145
+
146
+ `,t+=`1. Import the generated CSS
147
+ `,t+=` ${c.cyan("import 'virtual:uno.css'")}`;else{const n=`${e.stylesDir}/global/tokens.variables.gen.css`;t+=`
148
+
149
+ `,t+=`1. Import the generated CSS
150
+ `,t+=` ${c.cyan(`import './${n}'`)}`}t+=`
151
+
152
+ `,t+=`2. (Optional) Add CUBE CSS
153
+ `,t+=` ${c.cyan(A.CUBE)}`,t+=`
154
+
155
+ `,t+=`3. (Optional) Add components
156
+ `,t+=` ${c.cyan(A.COMPONENTS)}`,t+=`
157
+
158
+ `,t+=`Docs: ${c.cyan("https://sugarcube.sh")}`,en(t,{width:.75}),await j(200),S.break(1)},"nextSteps");async function _n(e){await Rn(e)}o(_n,"next");const Dn=o(async()=>{const e=["Welcome to sugarcube \u2014 the toolkit for seriously sweet frontends!"];S.space(1),await S.animated(e,{clear:!1})},"welcome");function Ye(e,t){if(!e||e.trim()==="")throw new g(w.DIRECTORY_PATH_EMPTY(t));const s=ze(e).split("/")[0];if(s&&Tt.includes(s))throw new g(w.DIRECTORY_PATH_RESERVED(t,e))}o(Ye,"validateDirectoryPath");function vn(e){e.tokensDir&&Ye(e.tokensDir,"tokens-dir"),e.stylesDir&&Ye(e.stylesDir,"styles-dir")}o(vn,"validateOptions");async function An(){v()&&(me(w.CONFIG_EXISTS(),{}),process.exit(0))}o(An,"preflightInit");async function Fn(e){const t=await Cn(process.cwd()),n=e.tokensDir||t.tokensDir,s=e.stylesDir||t.stylesDir,r=await En(n);return{tokensDir:n,stylesDir:s,isSrcDir:t.isSrcDir,hasExistingTokens:r,framework:t.framework}}o(Fn,"initializeProjectContext");async function Nn(e,t,n){const s=t?null:e.kit||ce;if((e.skip||[]).includes("plugin"))return{starterKit:s,pluginToInstall:null};const i=await On(n);return{starterKit:s,pluginToInstall:i}}o(Nn,"determineInstallationTargets");async function On(e){return await $n(process.cwd(),e)?Re:null}o(On,"determinePlugin");async function Pn(e,t,n,s,r){const i=await Ue(process.cwd(),{withFallback:!0});return{options:e,...t,isSrcDir:t.isSrcDir,config:n,userConfig:s,...r,packageManager:i,createdFiles:[],createdDirectories:[],installedDependencies:[],tasks:[]}}o(Pn,"buildInitContext");async function Ln(e){const{trees:t,resolved:n}=await B(e.config);e.setupResult={config:e.config,createdTokenPaths:[],trees:t,resolved:n,tokenFiles:[],tokensDir:e.tokensDir}}o(Ln,"processExistingTokens");async function Mn(e){!e.hasExistingTokens&&e.starterKit?await qt(e):await Ln(e)}o(Mn,"setupDesignTokens");async function jn(e){if(!e.setupResult)throw new g(w.INITIALIZATION_INCOMPLETE());const{trees:t,resolved:n}=e.setupResult,s=await oe(t,n,e.config),r=await Te(s,e.config);await Se(r)}o(jn,"writeCSSVariables");async function Un(e){if(!e.setupResult)throw new g(w.INITIALIZATION_INCOMPLETE());const{trees:t,resolved:n}=e.setupResult,s=await oe(t,n,e.config),r=await Be(s,e.config);r.length&&await Ie(r)}o(Un,"writeCSSUtilities");async function xn(e){if(e.pluginToInstall&&!J(e.pluginToInstall))try{await pe([e.pluginToInstall],process.cwd(),e.packageManager),e.installedDependencies.push(e.pluginToInstall)}catch{throw new g(w.PLUGIN_INSTALL_FAILED({pluginToInstall:e.pluginToInstall,packageManager:e.packageManager}))}}o(xn,"installPlugins");async function Wn(e){try{await We(e.userConfig);const t=await xe();e.createdFiles.push(t)}catch{throw new g(w.CONFIG_WRITE_FAILED())}}o(Wn,"finalize");function Gn(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} ${k("\u2192","->")} using them`,while:o(async()=>{},"while")}):e.starterKit&&t.push({pending:"Looking for existing tokens",start:"Looking for existing tokens...",end:`No existing tokens detected ${k("\u2192","->")} adding starter kit`,while:o(async()=>{},"while")}),e.pluginToInstall){const n="Vite";J(e.pluginToInstall)?t.push({pending:`Checking for ${n} compatibility`,start:`Checking for ${n} compatibility...`,end:`${n} plugin already installed ${k("\u2192","->")} skipping plugin installation`,while:o(async()=>{},"while")}):t.push({pending:"Checking for Vite compatibility",start:"Checking for Vite compatibility...",end:`Vite detected ${k("\u2192","->")} plugin will be installed`,while:o(async()=>{},"while")})}else{const n=e.options.skip?.includes("plugin");t.push({pending:"Checking for Vite compatibility",start:"Checking for Vite compatibility...",end:n?`Plugin skipped ${k("\u2192","->")} CSS will be generated as file(s)`:`No Vite detected ${k("\u2192","->")} CSS will be generated as file(s)`,while:o(async()=>{},"while")})}return t}o(Gn,"buildDetectionTasks");async function Bn(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:o(async()=>{await Mn(e)},"while")}),!e.pluginToInstall)e.tasks.push({pending:"Generate CSS variables",start:"Generating CSS variables...",end:"CSS variables generated",while:o(async()=>{await jn(e)},"while")}),e.tasks.push({pending:"Generate CSS utilities",start:"Generating CSS utilities...",end:"CSS utilities generated",while:o(async()=>{await Un(e)},"while")});else if(e.pluginToInstall&&!J(e.pluginToInstall)){const t="Vite";e.tasks.push({pending:`Install ${t} plugin`,start:`Installing ${t} plugin...`,end:`${t} plugin installed`,while:o(async()=>{await xn(e)},"while")})}e.tasks.push({pending:"Write configuration file",start:"Writing configuration file...",end:"Configuration file written",while:o(async()=>{await Wn(e)},"while")})}o(Bn,"buildExecutionTasks");const Vn=new L().name("init").description("Initialize a new sugarcube project").option("--kit <kit>",`Starter kit to use (default: ${ce})`,ce).option("--tokens-dir <dir>","Design tokens directory (e.g., 'src/design-tokens')").option("--styles-dir <dir>","Styles output directory (e.g., 'src/styles')").option("--with <items...>","Install optional items").option("--skip <items...>","Skip installation of specific items (e.g., plugin)").action(async e=>{let t;try{vn(e),await An();const n=await Fn(e),s=await kn({actualTokensDir:n.tokensDir,actualStylesDir:n.stylesDir,isSrcDir:n.isSrcDir}),r=rt(s),i=await Nn(e,n.hasExistingTokens,n.framework);t=await Pn(e,n,r,s,i),Y(V("sugarcube")),await Dn();const u=Gn(t);u.length>0&&(S.message("Detecting project\u2026"),await S.tasks(u,{minDurationMs:1e3})),t.tasks=[],await Bn(t),t.tasks.length>0&&(S.message("Setting things up\u2026"),await S.tasks(t.tasks,{successMessage:"\u{1F389} Tasks completed successfully!"})),await _n(t)}catch(n){H(n)}}),Kn=new L().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(Y(V("Validate")),v()&&!e.length){const{config:s}=await ee();await B(s),ne(c.greenBright("All tokens valid \u2728"));return}if(!e.length)throw new g(w.VALIDATE_NO_PATH_SPECIFIED());for(const s of e)if(!N(s))throw new g(w.VALIDATE_PATH_NOT_FOUND(s));const t=await G(e.map(s=>s.endsWith(".json")?s:$(s,"**/*.json")));if(t.length===0)throw new g(w.VALIDATE_NO_TOKEN_FILES());const n=v()?(await ee()).config:{tokens:{source:[]},output:{tokens:".",css:".",separate:!1},transforms:{fluid:{min:320,max:1200},colorFallbackStrategy:"native"},build:{}};await B({...n,tokens:{source:t.map(s=>R(process.cwd(),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 Yn(){const e=new L().name("sugarcube").description("CLI for scaffolding sugarcube projects").version(yt.version,"-v, --version","display the version number");e.addCommand(Vn).addCommand(Tn).addCommand(Kn).addCommand(gn).addCommand(mn),e.parse()}o(Yn,"main"),Yn();
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@sugarcube-org/cli",
3
- "version": "0.0.0-alpha.15",
3
+ "version": "0.0.0-alpha.17",
4
4
  "publishConfig": {
5
- "access": "public"
5
+ "access": "public",
6
+ "provenance": false
6
7
  },
7
8
  "description": "A CLI for scaffolding sugarcube applications",
8
- "license": "AGPL-3.0",
9
+ "license": "SEE LICENSE IN LICENSE.md",
9
10
  "author": "Mark Tomlinson",
10
11
  "repository": {
11
12
  "type": "git",
@@ -36,26 +37,33 @@
36
37
  "sugarcube": "./dist/index.mjs"
37
38
  },
38
39
  "dependencies": {
39
- "@antfu/ni": "^23.3.0",
40
- "@clack/prompts": "^0.9.1",
41
- "commander": "^12.1.0",
42
- "cross-env": "^7.0.3",
43
- "execa": "^9.5.2",
44
- "fast-glob": "^3.3.2",
45
- "node-fetch": "^3.3.0",
46
- "picocolors": "^1.1.1",
47
- "zod": "^3.24.2",
48
- "@sugarcube-org/core": "0.0.1-alpha.5"
40
+ "@antfu/ni": "23.3.0",
41
+ "@clack/core": "1.0.0-alpha.3",
42
+ "@clack/prompts": "1.0.0-alpha.3",
43
+ "@sugarcube-org/core": "0.0.1-alpha.7",
44
+ "@unocss/core": "66.5.2",
45
+ "commander": "12.1.0",
46
+ "execa": "9.5.2",
47
+ "fast-glob": "3.3.2",
48
+ "fast-wrap-ansi": "0.1.3",
49
+ "get-tsconfig": "4.7.2",
50
+ "is-unicode-supported": "2.1.0",
51
+ "log-update": "6.1.0",
52
+ "node-fetch": "3.3.0",
53
+ "pathe": "2.0.3",
54
+ "picocolors": "1.1.1",
55
+ "zod": "3.21.4"
49
56
  },
50
57
  "devDependencies": {
51
- "pkgroll": "^2.5.1",
52
- "tsx": "^4.19.2"
58
+ "cross-env": "7.0.3",
59
+ "pkgroll": "2.5.1",
60
+ "tsx": "4.19.2"
53
61
  },
54
62
  "engines": {
55
63
  "node": ">=18.0.0"
56
64
  },
57
65
  "scripts": {
58
- "build": "pkgroll --minify",
66
+ "build": "tsc --noEmit && pkgroll --minify",
59
67
  "dev": "cross-env REGISTRY_URL=http://localhost:4321/r tsx src/index.ts",
60
68
  "test": "vitest run",
61
69
  "test:watch": "vitest",