@sugarcube-org/cli 0.0.0-alpha.2 → 0.0.0-alpha.20

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,50 +1,159 @@
1
1
  #!/usr/bin/env node
2
- var je=Object.defineProperty;var p=(e,n)=>je(e,"name",{value:n,configurable:!0});import{Command as O}from"commander";import{validationPipeline as Ce,generationPipeline as Fe}from"@sugarcube-org/core";import{z as l}from"zod";import g from"picocolors";import h from"path";import X,{readFile as le,writeFile as A,mkdir as P}from"fs/promises";import{existsSync as D}from"fs";import{text as M,isCancel as b,select as W,multiselect as ee,confirm as z,log as k,spinner as te,intro as B,note as V,cancel as ne,outro as L}from"@clack/prompts";import Ee from"node-fetch";import ue from"fast-glob";import{execa as Ie}from"execa";import{detect as De}from"@antfu/ni";import se from"node:fs/promises";const oe=l.enum(["react","astro","nunjucks"]),pe=l.object({path:l.string(),type:l.string()}),Ne=pe.extend({framework:oe}),Pe=l.object({name:l.string(),type:l.string(),description:l.string().optional(),frameworks:l.array(l.string()).optional(),files:l.array(l.union([Ne,pe])),tokens:l.record(l.object({type:l.string(),mapping:l.string()})).optional(),dependencies:l.record(oe,l.array(l.string())).optional(),registryDependencies:l.record(oe,l.array(l.string())).optional(),tokenDependencies:l.array(l.string()).optional()}),Te=l.array(Pe),Re=l.object({content:l.string()}),re=l.object({tokens:l.union([l.object({source:l.array(l.string()),type:l.enum(["starter-kit","custom"]),themes:l.record(l.array(l.string())).optional()}),l.record(l.string(),l.object({source:l.array(l.string()),type:l.enum(["starter-kit","custom"]),themes:l.record(l.array(l.string())).optional()}))]),options:l.object({fluid:l.object({min:l.number(),max:l.number()}).optional(),prefix:l.string().optional(),color:l.enum(["hex","rgb","rgba","hsl","hsla","oklch","p3"]).optional()}).optional(),output:l.object({directories:l.object({tokens:l.string(),components:l.string().optional(),css:l.string()}),css:l.object({separate:l.boolean(),manageIndex:l.boolean().optional(),format:l.enum(["css","scss","less"]).optional()})})}),v={error:g.red,warn:g.yellow,info:g.cyan,success:g.green,bold:g.bold,path:g.cyan},S={error(...e){console.log(v.error(e.join(" ")))},warn(...e){console.log(v.warn(e.join(" ")))},info(...e){console.log(v.info(e.join(" ")))},success(...e){console.log(v.success(e.join(" ")))},log(...e){console.log(e.join(" "))},break(){console.log("")}};class d extends Error{static{p(this,"CLIError")}constructor(n,t){super(n),this.name="CLIError",this.cause=t}}async function G(e,n={type:"files",paths:e}){const{trees:t,resolved:o,errors:s}=await Ce(e,{loader:n});if(s.load.length>0)throw new d(`Failed to load token files:
3
- ${s.load.map(i=>`${i.file}: ${i.message}`).join(`
4
- `)}`);if(s.validation.length>0||s.flatten.length>0||s.resolution.length>0){S.break();const i=[...s.flatten,...s.validation,...s.resolution],c=new Map;throw i.forEach(a=>{if(a.source?.sourcePath){const r=c.get(a.source.sourcePath)||[];r.push(a.message),c.set(a.source.sourcePath,r)}}),c.forEach((a,r)=>{S.error(`Error(s) in ${v.path(r)}:`),a.forEach(u=>{S.error(` - ${u}`)}),S.break()}),new d(`Token validation failed. See ${v.info("https://docs.sugarcube.sh/w3c-token-format")} for help`)}return{trees:t,resolved:o}}p(G,"validateTokens");async function fe(e="./src/styles"){const n=await M({message:"Save CSS to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return b(n)&&process.exit(0),n}p(fe,"promptCSSOutputDirectory");async function Oe(e="./src/design-tokens"){const n=await M({message:"Save tokens to",placeholder:e,validate:p(t=>{if(!t.trim())return"Please provide a path"},"validate")});return b(n)&&process.exit(0),n}p(Oe,"promptTokensDirectory");async function Ae(){const e=await W({message:"Which kit?",options:[{label:"Responsive",value:"starter-fluid",hint:"Tokens with fluid typography and spacing (recommended)"},{label:"Static",value:"starter-static",hint:"Tokens with fixed typography and spacing"}]});return b(e)&&process.exit(0),e}p(Ae,"promptStarterKit");async function me(e="./src/components"){const n=await M({message:"Save components to",placeholder:e,validate:p(t=>{if(t.trim().replace(/['"]/g,"").length===0)return"Output directory cannot be empty"},"validate")});return b(n)&&process.exit(0),n}p(me,"promptComponentDirectory");async function de(e=!0){const n=[{label:"React",value:"react",hint:".tsx"},{label:"Astro",value:"astro",hint:".astro"},{label:"Nunjucks",value:"nunjucks",hint:".njk"}];e&&n.push({label:"Skip",value:"skip",hint:"continue without components"});const t=await W({message:"Build with",options:n});return b(t)&&process.exit(0),t}p(de,"promptComponentFramework");async function ge(e,n){const t=e.filter(s=>s.type==="component"&&s.frameworks?.includes(n)),o=await ee({message:"Select components to add",options:t.map(s=>({label:s.name,value:s.name,hint:s.description})),required:!0});return b(o)&&process.exit(0),o}p(ge,"promptComponentSelectionFiltered");async function Me(){const n=await W({message:"Set up tokens with",options:[{label:"Starter kit",value:"starter"},{label:"Own tokens",value:"existing"}]});return b(n)&&process.exit(0),n}p(Me,"promptTokenSetup");function Le(e,n,t,o){return e.output=e.output||{},e.output.directories={tokens:h.relative(process.cwd(),t),css:h.relative(process.cwd(),h.resolve(process.cwd(),n))},e.tokens||(e.tokens={type:"starter-kit",source:[]}),e}p(Le,"updateConfigWithTokenDirs");async function K(e,n=!1){const t=await z({message:e,initialValue:n});return(!t||b(t))&&process.exit(0),!0}p(K,"confirmOverwrite");async function Ue(){const e=await z({message:"Install CUBE CSS?",active:"Yes",inactive:"No",initialValue:!0});return b(e)&&process.exit(0),e}p(Ue,"promptInstallCube");async function We(){const e=await M({message:"Path to tokens?",placeholder:"./src/design-tokens",validate:p(n=>{if(n.trim().replace(/['"]/g,"").length===0)return"Path cannot be empty"},"validate")});return b(e)&&process.exit(0),e}p(We,"promptExistingTokensPath");async function ze(){const e=await z({message:"Generate separate CSS file for each token file?"});return b(e)&&process.exit(0),e}p(ze,"promptSeparateCSSFiles");async function Be(){const e=await W({message:"How would you like to organize your tokens?",options:[{value:"simple",label:"Simple (all tokens in one place)"},{value:"collections",label:"Collections (group related tokens together)"}]});return b(e)&&process.exit(0),e}p(Be,"promptCollectionOrganization");async function he(e,n=!1){if(e.length===0)return null;const t=await ee({message:`Select files for your ${n?"first":"next"} collection (including any theme files)`,options:e.map(o=>({label:o,value:o}))});return b(t)&&process.exit(0),t.length===0?null:t}p(he,"promptFilesForCollection");async function ie(e){const n=e.map(o=>h.dirname(o).split(h.sep)).reduce((o,s)=>o?o.filter((i,c)=>i===s[c]):s).pop(),t=await M({message:"Name this collection:",placeholder:n||"collection"});return b(t)&&process.exit(0),t}p(ie,"promptCollectionName");async function Ge(e){if(e.length<=1)return null;const n=await z({message:"Are any of these theme files?",initialValue:!1});if(b(n)&&process.exit(0),!n)return null;const t=[];let o=[...e];for(;o.length>0;){const s=await ee({message:t.length===0?"Select files for first theme:":"Select files for another theme (or Enter to finish):",options:o.map(c=>({label:c,value:c}))});if(b(s)&&process.exit(0),s.length===0)break;const i=await M({message:"Name this theme:",placeholder:"light"});if(b(i)&&process.exit(0),t.push({name:i,files:s}),o=o.filter(c=>!s.includes(c)),o.length>0){const c=await z({message:"Create another theme?",initialValue:!0});if(b(c)&&process.exit(0),!c)break}}return t.length>0?t:null}p(Ge,"promptIdentifyThemeFiles");async function we(e,n,t){const{output:o}=await Fe(e,n,t),s=o.map(i=>i.name).filter(i=>D(i));if(s.length>0){const i=s.map(c=>` - ${c}`).join(`
5
- `);k.warn(g.yellow(`The following files will be regenerated:
6
- ${g.dim(i)}`)),await K("Continue?",!0)}for(const i of o)try{await X.mkdir(h.dirname(i.name),{recursive:!0}),await X.writeFile(i.name,i.content,"utf-8")}catch(c){const a=c instanceof Error?`: ${c.message}`:"";throw new d(`Failed to write CSS file ${i.name}${a}`)}return o}p(we,"generateAndWriteCSSVars");function Y(e){const t=[...e.config?[e.config]:[],...e.tokens||[],...e.generated].map(s=>h.relative(process.cwd(),s)),o=te();o.start(`Generating ${t.length} files:`),o.stop(`Generated ${t.length} files:`),t.forEach(s=>{S.log(` - ${s}`)}),S.break()}p(Y,"showSummary");const ye=process.env.REGISTRY_URL??"https://registry.sugarcube.sh/registry";async function ke(e){try{const n=await Ee(e);if(!n.ok){if(n.status===401)throw new d(`Registry access denied: Authentication required
7
- URL: ${v.info(e)}`);if(n.status===403)throw new d(`Registry access denied: Invalid or missing token
8
- URL: ${v.info(e)}`);if(n.status===404)throw new d(`Registry resource not found
9
- URL: ${v.info(e)}`);const t=await n.json().catch(()=>null),o=t&&typeof t=="object"&&"error"in t?t.error:n.statusText;throw new d(`Registry request failed: ${o}
10
- URL: ${v.info(e)}`)}return n.json()}catch(n){throw n instanceof d?n:new d(`Failed to connect to registry
11
- URL: ${v.info(e)}
12
- Check your internet connection`)}}p(ke,"fetchRegistry");async function U(){const e=`${ye}/index.json`,n=await ke(e);try{return Te.parse(n)}catch{throw new d(`Invalid registry data received
13
- URL: ${v.info(e)}`)}}p(U,"getRegistryIndex");async function Z({type:e,name:n,framework:t}){const o=await U(),s=o.find(a=>a.type===e&&a.name===n);if(!s){const a=o.filter(r=>r.type===e).map(r=>r.name);throw new d(`${e} '${v.info(n)}' not found in registry
14
- Available ${e}s: ${a.join(", ")}`)}let i=s.files;e==="component"&&t&&(i=s.files.filter(a=>"framework"in a&&a.framework===t));const c=await Promise.all(i.map(async a=>{const r=`${ye}/${a.path}.json`,u=await ke(r);try{const f=Re.parse(u);return{path:a.path,type:a.type,framework:"framework"in a?a.framework:void 0,content:f.content}}catch{throw new d(`Invalid file content received
15
- File: ${v.info(a.path)}`)}}));return{item:s,files:c.filter(Boolean)}}p(Z,"getRegistryFiles");async function _e(e,n,t){const o=[],s=new Set;async function i(c){if(s.has(c))return;s.add(c);const a=e.find(u=>u.name===c);if(!a){const u=e.filter(f=>f.type==="component").map(f=>f.name).join(", ");throw new d(`Component '${c}' not found in registry
16
- Available components: ${u}`)}const r=a.registryDependencies?.[t]||[];for(const u of r)await i(u);o.push(a)}p(i,"resolveComponent");for(const c of n)await i(c);return o}p(_e,"resolveTree");const Je=p(async(e,n,t)=>{const o=await Z({type:"tokens",name:e});if(!o.files[0])throw new d(`Starter kit '${e}' does not contain any token files`);const s=h.resolve(process.cwd(),t),i=`${e}.json`,c=h.join(s,i),a={tokens:{source:[h.relative(process.cwd(),c)],type:"starter-kit"},options:e==="starter-fluid"?{fluid:{min:320,max:1200}}:void 0,output:{directories:{tokens:h.relative(process.cwd(),s),css:n},css:{separate:!1,manageIndex:!0}}};try{const r=re.parse(a),{trees:u,resolved:f}=await G(r,{type:"memory",data:{[c]:{collection:"default",content:o.files[0].content}}});return{config:r,tokens:[],trees:u,resolved:f,tokenContent:o.files[0].content,tokenPath:c,tokensDir:s}}catch(r){throw r instanceof l.ZodError?new d(`Invalid starter kit configuration: ${r.message}`):r}},"initializeFromStarterKit"),qe=p(async e=>{const n=await We(),t=await ue("**/*.json",{cwd:n,absolute:!0});if(t.length===0)throw new d(`No JSON files found in ${n}`);const o=[];for(const m of t)try{const w=await le(m,"utf-8");JSON.parse(w),o.push(m)}catch{k.warn(g.yellow(`Skipping invalid JSON file: ${m}`));continue}if(o.length===0)throw new d(`No valid JSON files found in ${n}
17
- Ensure files contain valid JSON`);const s=o.map(m=>h.relative(process.cwd(),m)),i=h.resolve(process.cwd(),n),c=await fe();let a=await Be();const r=new Map;s.forEach(m=>{const w=h.basename(m),y=r.get(w)||[];r.set(w,[...y,m])});const u=Array.from(r.entries()).filter(([m,w])=>w.length>1).map(([m,w])=>({name:m,files:w}));if(a==="simple"&&u.length>0){const m=u.map(({name:w,files:y})=>{const $=y.map(x=>` - ${x}`).join(`
18
- `);return`
19
- ${w} appears in:
20
- ${g.dim($)}`}).join(`
21
- `);k.warn(g.yellow(`Simple organization cannot have duplicate filenames:
22
- ${m}`)),k.message(g.cyan("Switching to collections to help organize these files...")),a="collections"}if(a==="simple"){const m={type:"custom",source:s};e.tokens=m,k.message(g.cyan("Token organization complete"))}else{const m={},w=new Set;let y=[...s],$=!0;for(;y.length>0;){let x=await he(y,$);if(!x){k.message(g.cyan("No files selected, skipping collection creation..."));break}let j=await ie(x);if(!j){k.message(g.cyan("No collection name provided, skipping collection creation..."));break}let R=!1;for(;!R;)try{if(w.has(j)){k.warn(g.yellow(`Collection name "${j}" is already in use.`));const F=await ie(x);if(!F){k.message(g.cyan("No collection name provided, skipping collection creation..."));break}j=F;continue}const C={type:"custom",source:x};m[j]=C;const N=await Ge(x);if(N&&N.length>0){const F=N.flatMap(I=>I.files),E=new Set;let T=!1;for(const I of N){if(E.has(I.name)){k.warn(g.yellow(`Theme name "${I.name}" is already used in this collection.`)),k.message(g.cyan("Starting theme selection over to avoid conflicts...")),T=!0;break}E.add(I.name)}if(T)continue;C.source=x.filter(I=>!F.includes(I)),C.themes=N.reduce((I,q)=>({...I,[q.name]:q.files}),{})}const Q=new Map;C.source.forEach(F=>{const E=h.basename(F),T=Q.get(E)||[];Q.set(E,[...T,F])});const ce=Array.from(Q.entries()).filter(([F,E])=>E.length>1).map(([F,E])=>({name:F,files:E}));if(ce.length>0){const F=ce.map(({name:I,files:q})=>{const xe=q.map($e=>` - ${$e}`).join(`
23
- `);return`
24
- ${I} appears in:
25
- ${g.dim(xe)}`}).join(`
26
- `);k.warn(g.yellow(`Found duplicate filenames in collection "${j}":
27
- ${F}`)),k.message(g.cyan("Please either split these files into different collections or mark some as theme files."));const E=await he(y,$);if(!E){k.message(g.cyan("No files selected, skipping collection creation..."));break}x=E;const T=await ie(x);if(!T){k.message(g.cyan("No collection name provided, skipping collection creation..."));break}j=T;continue}R=!0,w.add(j)}catch(C){if(C instanceof d){k.error(`${C.message}`),k.message(g.cyan("Let's try again..."));continue}throw C}if(!R){k.message(g.cyan("Skipping collection creation..."));break}y=y.filter(C=>!x.includes(C)),y.length>0&&k.message(g.cyan(`Remaining files to organize: ${y.length}`)),$=!1}y.length>0?k.warn(g.yellow(`Warning: ${y.length} files were not assigned to any collection`)):k.message(g.cyan("Token organization complete")),e.tokens=m}const f=s.length>1?await ze():!1;e.output={directories:{tokens:h.relative(process.cwd(),i),css:c},css:{separate:f,manageIndex:!0}},e.options={fluid:{min:320,max:1200}};try{if(typeof e.tokens=="object"&&!Array.isArray(e.tokens)){const $=e.tokens,x=new Set;for(const[j,R]of Object.entries($)){if(x.has(j))throw new d(`Configuration Error: Duplicate collection name "${j}". Collection names must be unique.`);if(x.add(j),R.themes){const C=new Set;for(const N of Object.keys(R.themes)){if(C.has(N))throw new d(`Configuration Error: Duplicate theme name "${N}" in collection "${j}". Theme names must be unique within a collection.`);C.add(N)}}}}const m=re.parse(e),{trees:w,resolved:y}=await G(m);return{config:m,tokens:s,trees:w,resolved:y,tokenPath:n,tokensDir:i,tokenContent:void 0}}catch(m){throw m instanceof l.ZodError?new d(`Invalid configuration: ${m.message}`):m}},"initializeFromExistingTokens");async function Ve(){if(D("sugarcube.config.json")){const e=await W({message:"A sugarcube.config.json already exists in this project",options:[{label:"Overwrite existing config (start from scratch)",value:"overwrite"},{label:"Cancel initialization",value:"cancel"}]});return b(e)&&process.exit(0),{shouldProceed:e==="overwrite"}}return{shouldProceed:!0}}p(Ve,"preflightInit");async function _(){let e;try{e=await X.readFile("sugarcube.config.json","utf-8")}catch{throw new d("Cannot read config file - check file permissions")}let n;try{n=JSON.parse(e)}catch{throw new d("Invalid JSON in config file - check for syntax errors")}const t=re.safeParse(n);if(!t.success){const o=t.error.errors.map(s=>{const i=s.path.join(".");return i?`${i}: ${s.message}`:s.message}).join(`
28
- `);throw new d(`Invalid configuration:
29
- ${o}
30
- See ${v.info("https://docs.sugarcube.sh/configuration")} for help.`)}if(typeof t.data.tokens=="object")for(const[o,s]of Object.entries(t.data.tokens)){if(!s.source?.length)continue;const i=new Map;s.source.forEach(a=>{const r=h.basename(a),u=i.get(r)||[];i.set(r,[...u,a])});const c=Array.from(i.entries()).filter(([a,r])=>r.length>1).map(([a,r])=>({name:a,files:r}));if(c.length>0){const a=c.map(({name:r,files:u})=>{const f=u.map(m=>` - ${m}`).join(`
31
- `);return`
32
- ${r} appears in:
33
- ${f}`}).join(`
34
- `);throw new d(`Duplicate filenames found in collection "${o}":
35
- ${a}
36
-
37
- To fix this:
38
- 1. Use unique filenames for source files
39
- 2. Or move some files to a different collection
40
- 3. Or mark some files as theme files
41
- See ${v.info("https://docs.sugarcube.sh")} to learn more.`)}}return t.data}p(_,"validateAndLoadConfig");async function ae(e){const n={$schema:"https://sugarcube.style/schema.json",...e};try{const t=JSON.stringify(n,null,2);await A("sugarcube.config.json",t)}catch(t){const o=t instanceof Error?`: ${t.message}`:"";throw new d(`Failed to write config file${o}`)}}p(ae,"writeConfig");function Ke(e){const n=e.split("/"),t=n.findIndex(s=>s==="variables");if(t===-1||t===n.length-1)return"default";const o=n[t+1];return!o||o.endsWith(".css")?"default":o}p(Ke,"getCollectionFromPath");function be(e,n){if(e.includes("/variables/")){const t=Ke(e),o=n.variables.get(t)??[];o.push(e),n.variables.set(t,o)}else e.startsWith("global/")?n.global.push(e):e.startsWith("compositions/")?n.compositions.push(e):e.startsWith("utilities/")&&n.utilities.push(e)}p(be,"groupFile");async function Ye(e,n,t="merge"){const o={variables:new Map,global:[],compositions:[],utilities:[]},s=h.join(n,"index.css");t==="merge"&&D(s)&&(await le(s,"utf-8")).split(`
42
- `).filter(f=>f.trim().startsWith("@import")).map(f=>f.match(/'([^']+)'/)?.[1]).filter(f=>f!==void 0).forEach(f=>be(f,o)),e.filter(r=>r.endsWith(".css")).forEach(r=>{const u=h.relative(n,r).replace(/\\/g,"/");be(u,o)});const i=["reset.css","fonts.css","global-styles.css"];o.global.sort((r,u)=>{const f=i.findIndex(w=>r.endsWith(w)),m=i.findIndex(w=>u.endsWith(w));return f-m});const c=Array.from(o.variables.entries()).sort(([r,u],[f,m])=>r==="default"?-1:f==="default"?1:r.localeCompare(f)).flatMap(([r,u])=>u.sort((f,m)=>f.endsWith("tokens.variables.css")?-1:m.endsWith("tokens.variables.css")?1:f.localeCompare(m))),a=[...new Set([...c,...o.global,...o.compositions.sort(),...o.utilities.sort()])].map(r=>`@import '${r}';`);return await A(s,a.join(`
43
- `)),s}p(Ye,"generateIndexFile");const Ze=p(()=>{B(g.inverse(" Welcome to sugarcube. The toolkit for seriously sweet front ends "))},"welcome");async function He(e,{withFallback:n=!1}={}){const t=await De({programmatic:!0,cwd:e});if(t==="yarn@berry")return"yarn";if(t==="pnpm@6")return"pnpm";if(t==="bun")return"bun";if(!n)return t??"npm";const o=process.env.npm_config_user_agent||"";return o.startsWith("yarn")?"yarn":o.startsWith("pnpm")?"pnpm":o.startsWith("bun")?"bun":"npm"}p(He,"getPackageManager");async function Qe(e,n){const t=await He(n,{withFallback:!0}),o=t==="npm"?["install",...e]:["add",...e];await Ie(t,o,{cwd:n})}p(Qe,"installDependencies");async function ve({registryIndex:e,selectedComponents:n,componentType:t,componentsOutputDirectory:o,cssOutputDirectory:s}){const i=[],c=new Set;await P(o,{recursive:!0});const a=h.join(s,"global","variables");await P(h.join(s,"global"),{recursive:!0}),await P(a,{recursive:!0});const r=await _e(e,n,t);for(const u of r){const f=await Z({type:"component",name:u.name,framework:t});for(const w of f.files)if(w)try{if(w.path.endsWith(".variables.css")){const y=h.join(a,`${u.name}.variables.css`);await A(y,w.content),i.push(y)}else{const y=h.join(o,u.name);await P(y,{recursive:!0});const $=h.join(y,h.basename(w.path));await A($,w.content),i.push($)}}catch(y){const $=y instanceof Error?`: ${y.message}`:"";throw new d(`Failed to write component file for "${u.name}"${$}`)}(u.dependencies?.[t]||[]).forEach(w=>c.add(w))}if(c.size>0)try{await Qe(Array.from(c),process.cwd())}catch(u){const f=u instanceof Error?`: ${u.message}`:"";throw new d(`Failed to install component dependencies${f}`)}return{createdFiles:i,npmDependencies:c}}p(ve,"installComponents");async function Xe(e){const n=[],t=h.resolve(process.cwd(),e);await P(t,{recursive:!0});const s=(await U()).filter(i=>i.type==="cube").map(i=>i.name);for(const i of s){const c=await Z({type:"cube",name:i});for(const a of c.files){if(!a)continue;const r=a.path.replace(/^styles\//,""),u=h.join(t,r),f=h.dirname(u);try{await P(f,{recursive:!0}),await A(u,a.content),n.push(u)}catch(m){const w=m instanceof Error?`: ${m.message}`:"";throw new d(`Failed to write CUBE module "${i}"${w}`)}}}return n}p(Xe,"installCUBE");function et(e){switch(e){case"react":return"tsx";case"astro":return"astro";case"nunjucks":return"njk";default:return"tsx"}}p(et,"getExtension");function Se({components:e,componentType:n,componentsOutputDirectory:t}){return e.filter(o=>{const s=h.join(t,o,`${o}.${et(n)}`);return D(s)})}p(Se,"checkComponentExists");async function H({mode:e,cssOutputDirectory:n,files:t,config:o}){if(!o.output.css.manageIndex)return;const s=t.filter(a=>a.endsWith(".css"));if(s.length===0)return;const i=h.join(n,"index.css"),c=D(i);if(!(e==="create"&&c&&(k.warn(g.yellow(`The following file will be overwritten:
44
- ${g.dim(" - index.css")}`)),!await K("Continue?",!1))))try{return await Ye(s,n,e)}catch(a){const r=a instanceof Error?`: ${a.message}`:"";throw new d(`Failed to ${e} CSS index file${r}`)}}p(H,"manageCSSIndex");function J(e){if(S.break(),e instanceof d){const n=e.message.split(`
45
- `);n.length>1?(S.error(n[0]),S.break(),n.slice(1).forEach(t=>{S.error(` ${t.trim()}`)})):S.error(e.message),process.env.DEBUG&&e.cause&&S.info(`
46
- Caused by:`,e.cause)}else S.error(`An unexpected error occurred: ${e instanceof Error?e.message:String(e)}
47
- If this issue persists, please report it: ${g.cyanBright("https://github.com/sugarcube-org/sugarcube/issues")}`),process.env.DEBUG&&S.info(`
48
- Error details:`,e);S.break(),process.exit(0)}p(J,"handleError");const tt=new O().name("init").description("Initialize a new project").action(async()=>{try{Ze(),(await Ve()).shouldProceed||process.exit(0),V("Step 1. Set up tokens");const n=await Me();let t;switch(n){case"starter":const r=await Ae(),u=await fe(),f=await Oe();try{t=await Je(r,u,f),t.config=Le(t.config||{},u,f,r)}catch(m){ne(`Failed to initialize starter kit: ${m instanceof Error?m.message:"Unknown error"}`),process.exit(1)}break;case"existing":t=await qe({});break}V("Step 2. Add style system");const o=await Ue();V("Step 3. Add components");const s=await de();let i=[];if(s!=="skip"){const r=await U();r||(ne("Failed to fetch component list"),process.exit(1));const u=await ge(r,s),f=await me(),m=await Se({components:u,componentType:s,componentsOutputDirectory:f});if(m.length>0){const w=m.join(", ");await K(`The following components already exist and will be overwritten: ${w}. Continue?`,!1)}if(u.length>0){const w=te();w.start("Installing components...");try{const{createdFiles:y,npmDependencies:$}=await ve({registryIndex:r,selectedComponents:u,componentType:s,componentsOutputDirectory:f,cssOutputDirectory:t.config.output.directories.css});i=y,w.stop("Components installed successfully")}catch(y){throw w.stop("Installation failed"),y}}}V("Step 4. Generating files");try{if(await se.mkdir(t.tokensDir,{recursive:!0}),await se.mkdir(t.config.output.directories.css,{recursive:!0}),n==="starter"){if(!t.tokenContent)throw new d("Failed to generate token content for starter kit");await se.writeFile(t.tokenPath,t.tokenContent)}}catch(r){const u=r instanceof Error?`: ${r.message}`:"";throw new d(`Failed to create project files${u}`)}let c=[];c=await we(t.trees,t.resolved,t.config);let a=[];o&&(a=await Xe(t.config.output.directories.css)),await H({mode:"create",cssOutputDirectory:t.config.output.directories.css,files:[...c.map(r=>r.name),...i.filter(r=>r.endsWith(".css")),...a],config:t.config}),await ae(t.config),Y({config:"sugarcube.config.json",tokens:n==="starter"?t.tokens:[],generated:[...c.map(r=>r.name),...a,...i,...t.config.output.css.manageIndex?["index.css"]:[]]}),L(g.greenBright("Success! Project initialized \u2728"))}catch(e){J(e)}}),nt=new O().name("generate").description("Generate CSS from your design tokens").option("--force","Skip confirmation when deleting stale files").action(async e=>{try{if(B(g.inverse(" Generate CSS variables from your design tokens ")),!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");const n=await _(),{trees:t,resolved:o}=await G(n),s=await we(t,o,n);n.output.css.manageIndex&&await H({mode:"merge",cssOutputDirectory:n.output.directories.css,files:s.map(i=>i.name),config:n}),Y({generated:[...s.map(i=>i.name),...n.output.css.manageIndex?["index.css"]:[]]}),L(g.greenBright("Success! CSS variables generated successfully. \u2728"))}catch(n){J(n)}}),st=new O().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(B(g.inverse(" Validate design tokens ")),D("sugarcube.config.json")&&!e.length){const s=await _();await G(s),L(g.greenBright("All tokens are valid \u2728"));return}if(!e.length)throw new d("No paths specified. Please provide files/directories to validate, or run this in a Sugarcube project directory.");const n=e.map(s=>h.normalize(s));for(const s of n)if(!D(s))throw new d(`Path not found: ${s}
49
- Please check that the specified files or directories exist`);const t=await ue(n.map(s=>s.endsWith(".json")?s:h.join(s,"**/*.json")));if(t.length===0)throw new d(`No JSON files found in the specified paths
50
- Please ensure the paths contain .json files`);const o=D("sugarcube.config.json")?await _():{output:{directories:{tokens:".",css:"."},css:{separate:!1}}};await G({...o,tokens:{type:"custom",source:t.map(s=>h.relative(process.cwd(),s))}}),L(g.greenBright("All tokens are valid \u2728"))}catch(n){J(n)}}),ot=new O().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, nunjucks)").option("-s, --silent","Suppress logs and prompts").action(async(e,n)=>{try{if(n.silent||B(g.inverse(" Add components ")),!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");let t=await _(),o,s=[],i;if(e.length>0){if(!n.framework)throw new d("Framework must be specified in non-interactive mode (--framework)");const r=["react","astro","nunjucks"];if(!r.includes(n.framework))throw new d(`Invalid framework. Must be one of: ${r.join(", ")}`);if(i=n.framework,s=e,!t.output.directories.components)throw new d("Components directory must be configured in non-interactive mode. Please run without arguments first.");o=h.resolve(process.cwd(),t.output.directories.components)}else{i=await de(!1);const r=await U();if(r||(ne("Failed to fetch component list"),process.exit(1)),s=await ge(r,i),t.output.directories.components)o=h.resolve(process.cwd(),t.output.directories.components);else{const u=await me();o=h.resolve(process.cwd(),u),t.output.directories.components=h.relative(process.cwd(),o),await ae(t)}}const c=await Se({components:s,componentType:i,componentsOutputDirectory:o});if(c.length>0&&!n.silent){const r=c.join(", ");await K(`The following components already exist and will be overwritten: ${r}. Continue?`,!1)}let a;n.silent||(a=te(),a.start("Installing components..."));try{const r=await U(),{createdFiles:u,npmDependencies:f}=await ve({registryIndex:r,selectedComponents:s,componentType:i,componentsOutputDirectory:o,cssOutputDirectory:t.output.directories.css});await H({mode:"merge",cssOutputDirectory:t.output.directories.css,files:u,config:t}),n.silent||(a?.stop("Components installed successfully"),Y({generated:u}),L(g.greenBright("Success! Components installed \u2728")))}catch(r){throw n.silent||a?.stop("Installation failed"),r}}catch(t){J(t)}}),rt=new O().name("cube").description("Add CUBE CSS to your project").option("-s, --silent","Suppress logs and prompts").action(async e=>{const n=[];try{if(!D("sugarcube.config.json"))throw new d("This command requires a sugarcube project. Run 'npx make-sugarcube init' first.");e.silent||B(g.inverse(" Add CUBE CSS "));const t=await _(),o=h.resolve(process.cwd(),t.output.directories.css);try{await P(o,{recursive:!0})}catch(c){const a=c instanceof Error?`: ${c.message}`:"";throw new d(`Failed to create output directory${a}`)}const i=(await U()).filter(c=>c.type==="cube").map(c=>c.name);for(const c of i){const a=await Z({type:"cube",name:c});for(const r of a.files){if(!r)continue;const u=r.path.replace(/^styles\//,""),f=h.join(o,u),m=h.dirname(f);try{await P(m,{recursive:!0}),await A(f,r.content),n.push(f)}catch(w){const y=w instanceof Error?`: ${w.message}`:"";throw new d(`Failed to write CUBE CSS file ${f}${y}`)}}}await H({mode:"merge",cssOutputDirectory:o,files:n,config:t}),await ae(t),!e.silent&&n.length>0&&(Y({generated:n}),L(g.greenBright("Success! CUBE CSS added successfully. \u2728")))}catch(t){J(t)}});var it="@sugarcube-org/cli",at="0.0.0-alpha.2",ct={access:"restricted"},lt="A CLI for scaffolding sugarcube applications",ut="UNLICENSED",pt="Mark Tomlinson",ft={type:"git",url:"https://github.com/sugarcube-org/sugarcube"},mt={url:"https://github.com/sugarcube-org/sugarcube/issues"},dt=["cli","design-system","components","CUBE CSS","react","sugarcube"],gt=["dist","README.md","LICENSE.md"],ht="module",wt={sugarcube:"./dist/index.mjs"},yt={build:"pkgroll --minify",dev:"cross-env REGISTRY_URL=http://localhost:8787/registry tsx src/index.ts",test:"vitest","type-check":"tsc --noEmit",start:"cross-env REGISTRY_URL=https://sugarcube-registry.mark-tomlinson3.workers.dev/registry tsx src/index.ts",prepublishOnly:"pnpm up @sugarcube-org/core --filter @sugarcube-org/cli && pnpm build"},kt={"@antfu/ni":"^23.3.0","@clack/prompts":"^0.9.1","@sugarcube-org/core":"workspace:*",commander:"^12.1.0","cross-env":"^7.0.3",execa:"^9.5.2","fast-glob":"^3.3.2","fs-extra":"^11.2.0","lucide-react":"^0.468.0","node-fetch":"^3.3.0",picocolors:"^1.1.1",prompts:"^2.4.2",zod:"^3.23.8"},bt={"@types/fs-extra":"^11.0.4","@types/prompts":"^2.4.9",pkgroll:"^2.5.1",tsx:"^4.19.2"},vt={name:it,version:at,publishConfig:ct,description:lt,license:ut,author:pt,repository:ft,bugs:mt,keywords:dt,files:gt,type:ht,bin:wt,scripts:yt,dependencies:kt,devDependencies:bt};process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function St(){const e=new O().name("sugarcube").description("CLI for scaffolding sugarcube applications").version(vt.version,"-v, --version","display the version number");e.addCommand(tt).addCommand(nt).addCommand(st).addCommand(ot).addCommand(rt),e.parse()}p(St,"main"),St();
2
+ var qe=Object.defineProperty;var o=(e,t)=>qe(e,"name",{value:t,configurable:!0});import{Command as M}from"commander";import{relative as $,join as R,basename as G,resolve as L,dirname as ze,normalize as Ze}from"pathe";import c from"picocolors";import{existsSync as F,readFileSync as Te}from"node:fs";import Qe from"node-fetch";import{z as m}from"zod";import se,{mkdir as B,writeFile as X,readFile as Xe}from"node:fs/promises";import{execa as et}from"execa";import{loadAndResolveTokens as tt,validateConfig as nt,configFileExists as A,loadInternalConfig as ee,loadUserConfig as st,processAndConvertTokens as oe,generateCSSVariables as Se,writeCSSVariablesToDisk as Ie,writeCSSUtilitiesToDisk as ke,convertConfigToUnoRules as ot,DEFAULT_STYLES_PATH as rt,DEFAULT_CONFIG as re,fillDefaults as it}from"@sugarcube-org/core";import at from"is-unicode-supported";import ie,{resolve as ct}from"node:path";import{select as lt,isCancel as ae,log as ut,multiselect as ft,confirm as pt,cancel as Ee}from"@clack/prompts";import{getColumns as dt}from"@clack/core";import{wrapAnsi as gt}from"fast-wrap-ansi";import*as be from"node:readline";import Ce from"node:readline";import{createLogUpdate as $e}from"log-update";import{detect as mt}from"@antfu/ni";import{getTsconfig as ht}from"get-tsconfig";import{createGenerator as wt}from"@unocss/core";import V from"fast-glob";var yt="0.0.0-alpha.20",Tt={version:yt};const ce="fluid",Re="**/*.json",le="@sugarcube-org/vite",St=["node_modules",".git",".next","dist","build"],It=5,v={INIT:"make-sugarcube init",COMPONENTS:"make-sugarcube components",GENERATE:"make-sugarcube generate",CUBE:"make-sugarcube cube"},_e={INITIALIZATION:"https://sugarcube.sh/docs/setup",CONFIGURATION:"https://sugarcube.sh/docs/configuration"},w={PROJECT_REQUIRED:`No sugarcube project detected. Please run ${c.cyan(v.INIT)} first.
3
+
4
+ For more information, visit: ${c.cyan(_e.INITIALIZATION)}`,CONFIG_EXISTS:o(()=>`A sugarcube config file already exists in this projct.
5
+
6
+ To start over, remove it and run ${c.cyan(v.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 ue=m.enum(["react","web-components","css-only"]),De=m.object({path:m.string(),type:m.string()}),kt=De.extend({framework:ue});m.object({modes:m.record(m.string(),m.array(m.string())).optional(),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,De])),tokens:m.record(m.object({type:m.string(),mapping:m.string()})).optional(),dependencies:m.record(ue,m.array(m.string())).optional(),registryDependencies:m.record(ue,m.array(m.string())).optional(),tokenDependencies:m.array(m.string()).optional()}),bt=m.array(Et),Ct=m.object({content:m.string()}),Ae=process.env.REGISTRY_URL??"https://sugarcube.sh/r";async function ve(e){try{const t=await Qe(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 j(){const e=`${Ae}/index.json`,t=await ve(e);try{return bt.parse(t)}catch{throw new g(w.REGISTRY_INVALID_DATA(e))}}o(j,"getRegistryIndex");async function fe({type:e,name:t,framework:n}){const s=await j(),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=`${Ae}/${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(fe,"getRegistryFiles");async function $t(e){const t=await fe({type:"tokens",name:e});if(!t.files[0])throw new g(w.STARTER_KIT_UNAVAILABLE(e));return t}o($t,"fetchStarterKit");async function pe(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(pe,"resolveTree");async function Rt({selectedComponents:e,componentType:t,componentsOutputDirectory:n}){const s={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},r=await j(),u=(await pe(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=>$(process.cwd(),R(n,p.name,`${p.name}.${d.type}`))));s.componentFiles=l.filter(p=>F(R(process.cwd(),p)));const f=a.map(p=>{const d=p.name;return $(process.cwd(),R(n,p.name,`${d}.css`))});return s.componentCSS=f.filter(p=>F(R(process.cwd(),p))),s}o(Rt,"collectComponentOverwriteWarnings");async function _t({cubeDirectory:e}){const t={variableCSS:[],utilityCSS:[],componentFiles:[],componentCSS:[],cubeCSS:[],indexFiles:[]},s=(await j()).filter(r=>r.type==="cube").flatMap(r=>r.files).map(r=>{const i=r.path.replace(/^styles\//,"");return $(process.cwd(),R(e,i))});return t.cubeCSS=s.filter(r=>F(R(process.cwd(),r))),t}o(_t,"collectCubeOverwriteWarnings");function Ne(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(Ne,"formatOverwriteWarnings");async function de(e,t,n){if(e.length===0)return;const s=n==="npm"?"install":"add";try{await et(n,[s,...e],{cwd:t})}catch{throw new g(w.DEPENDENCY_INSTALL_FAILED(n))}}o(de,"installDependencies");async function Dt(e,t,n){const s=R(n,t.name);if(await B(s,{recursive:!0}),e.path.endsWith(".css")){const i=R(s,`${t.name}.css`);return await X(i,e.content),i}const r=R(s,G(e.path));return await X(r,e.content),r}o(Dt,"writeComponentFile");async function At({registryIndex:e,selectedComponents:t,componentType:n,componentsOutputDirectory:s,packageManager:r}){const i=[],u=new Set;await B(s,{recursive:!0});const a=await pe(e,t,n);for(const l of a){const f=await fe({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 de(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(At,"installComponents");function vt(e,t){const n=L(e),s=L(t);return n.startsWith(`${s}/`)||n===s}o(vt,"isWithinDirectory");async function Nt(e){const t=[],n=L(process.cwd(),e);await B(n,{recursive:!0});const r=(await j()).filter(i=>i.type==="cube").map(i=>i.name);for(const i of r){const u=await fe({type:"cube",name:i});for(const a of u.files){if(!a)continue;const l=a.path.replace(/^styles\//,""),f=L(n,l);if(!vt(f,n))throw new g(`Invalid file path detected in CUBE module "${i}": path escapes target directory`);const p=ze(f);try{await B(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(Nt,"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 K(e,t){const n={type:"files",config:e},{trees:s,resolved:r,errors:i}=await tt(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(K,"loadAndResolveTokensForCLI");function Ot(e,t){const n={...e},s=t.modes&&Object.keys(t.modes).length>0,r=t.themes&&Object.keys(t.themes).length>0;return(s||r)&&typeof n.tokens=="object"&&!Array.isArray(n.tokens)&&"source"in n.tokens&&(s&&(n.tokens.modes=t.modes),r&&(n.tokens.themes=t.themes)),nt(n)}o(Ot,"integrateVariantsIntoConfig");const{hidden:ms}=c,Pt=at(),k=o((e,t)=>Pt?e:t,"unicodeOr"),Lt=k("\u25C7","o"),Fe=k("\u250C","T"),O=k("\u2502","|"),ge=k("\u2514","\u2014"),Mt=k("\u2510","T"),jt=k("\u2518","\u2014"),te=k("\u2500","-"),Ut=k("\u256E","+"),xt=k("\u256F","+"),Wt=k("\u2570","+"),Gt=k("\u256D","+"),Bt=k("\u25CF","\u2022"),Vt=k("\u25C6","*"),Kt=k("\u25B2","!"),Yt=k("\u25A0","x"),Y=o((e,t=c.bgGreen,n=c.black)=>t(` ${n(e)} `),"label"),H=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"),J=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(ge)}${c.gray(te)} ${e}
83
+
84
+ `)},"outro");function Ht(...e){process.env.DEBUG==="true"&&process.stderr.write(`[sugarcube:debug] ${e.map(String).join(" ")}
85
+ `)}o(Ht,"debugLog");function U(e){return new Promise(t=>setTimeout(t,e))}o(U,"sleep");function Jt(e,t){const n={},s={};if(e.modes)for(const[r,i]of Object.entries(e.modes))n[r]=i.map(u=>{const a=t[u];if(!a)throw new g(w.KIT_INCOMPLETE());return a});if(e.themes)for(const[r,i]of Object.entries(e.themes))s[r]=i.map(u=>{const a=t[u];if(!a)throw new g(w.KIT_INCOMPLETE());return a});return{modes:n,themes:s}}o(Jt,"processKitVariants");const qt=o(async(e,t,n)=>{const s=await $t(e),r=L(process.cwd(),t),i=s.files.find(d=>G(d.path)==="config.json");let u={};if(i)try{u=JSON.parse(i.content)}catch(d){Ht(`Could not parse config.json for starter kit '${e}':`,d)}const a=s.files.filter(d=>G(d.path)!=="config.json").map(d=>({path:R(r,G(d.path)),content:d.content})),l=Object.fromEntries(a.map(d=>[G(d.path),$(process.cwd(),d.path)])),f=Jt(u,l);return{config:Ot(n,f),tokenFiles:a,tokensDir:r,createdTokenPaths:a.map(d=>$(process.cwd(),d.path))}},"prepareStarterKitForInstall");async function zt(e){const t=await qt(e.starterKit??"",e.tokensDir,e.config),n=await Ft(t.tokenFiles,e.tokensDir),{trees:s,resolved:r}=await K(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(zt,"installFromStarterKit");async function Oe(e=!0){const t=[{label:"React",value:"react",hint:".tsx"},{label:"CSS Only",value:"css-only",hint:".css"},{label:c.dim("Web components"),value:"web-components",hint:"Coming soon!"}];e&&t.push({label:"Skip",value:"skip",hint:"continue without components"});const n=await lt({message:"Build with",options:t});return ae(n)&&process.exit(0),n==="web-components"?(ut.info(c.blue("Web components are coming soon! Please choose React or CSS Only for now.")),Oe(e)):n}o(Oe,"promptComponentFramework");async function Zt(e,t){const n=e.filter(r=>r.type==="component"&&r.frameworks?.includes(t)),s=await ft({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 Pe(e,t=!1){const n=await pt({message:e,initialValue:t});return(!n||ae(n))&&(Ee(),process.exit(0)),!0}o(Pe,"confirmOverwrite");const Qt=[Gt,Ut,Wt,xt],Xt=[Fe,Mt,ge,jt];function Le(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(Le,"getPaddingForLine");const en=o(e=>e,"defaultFormatBorder"),me=o((e="",t="",n)=>{const s=n?.output??process.stdout,r=dt(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??en,h=(n?.rounded?Qt:Xt).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 W=H(t).length+a*2;for(const Je of Z){const ye=H(Je).length+l*2;ye>W&&(W=ye)}const Q=W+u;Q<C&&(C=Q)}C%2!==0&&(C<T?C++:C--);const I=C-u,N=I-a*2,y=H(t).length>N?`${t.slice(0,N-3)}...`:t,[_,D]=Le(H(y).length,I,a,n?.titleAlign),P=gt(e,I-l*2,{hard:!0,trim:!1});s.write(`${p}${h[0]}${E.repeat(_)}${y}${E.repeat(D)}${h[1]}
87
+ `);const z=P.split(`
88
+ `);for(const Z of z){const[W,Q]=Le(H(Z).length,I,l,n?.contentAlign);s.write(`${p}${b}${" ".repeat(W)}${Z}${" ".repeat(Q)}${b}
89
+ `)}s.write(`${p}${h[2]}${E.repeat(I)}${h[3]}
90
+ `)},"box");function he(e,t={}){const n=`
91
+ ${e}`;me(n,c.black(c.bgRed(" ERROR ")),{width:"auto",titlePadding:2,formatBorder:c.red,...t})}o(he,"errorBoxWithBadge");function Me(e,t={}){const n=`
92
+ ${e}`;me(n,c.black(c.bgYellow(" WARNING ")),{width:"auto",titlePadding:2,formatBorder:c.yellow,...t})}o(Me,"warningBoxWithBadge");function tn(e,t={}){const n=`
93
+ ${e}`;me(n,c.black(c.bgCyan(" INFO ")),{width:"auto",titlePadding:2,formatBorder:c.cyan,...t})}o(tn,"infoBoxWithBadge");const nn=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"),sn=o(async(e,t={})=>{const{sidebarSymbol:n=c.gray("\u2502"),clear:s=!1,stdin:r=process.stdin,stdout:i=process.stdout}=t,u=Ce.createInterface({input:r,escapeCodeTimeout:50}),a=$e(i,{showCursor:!1});Ce.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=nn(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 N=b.join(" ").replace(/sugarcube/g,c.cyan("sugarcube")),y=`${n} ${N}`;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 on(){return Math.floor(Math.random()*551)+200}o(on,"getRandomTaskDuration");async function rn(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=$e(r),E=be.createInterface({input:s,escapeCodeTimeout:50});be.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 U(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()-_,z=typeof u=="number"?u:on();P<z&&await U(z-P),d[I]=p(y,"success"),h(C()),await U(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 N=e.map(y=>p(y,"end"));if(l)if(f){const y=`${c.gray(ge)}${c.gray(te)} ${c.green(l)}`;h([...T,...N,`${t}`,y].join(`
95
+ `))}else{const y=`${t} ${c.green(l)}`;h([...T,...N,`${t}`,y].join(`
96
+ `))}else h([...T,...N].join(`
97
+ `));await U(1e3),s.removeListener("keypress",b),s.isTTY&&s.setRawMode(!1),E.close(),h.done()}o(rn,"executeTasksInSidebar");const an=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(Bt)})},"info"),success:o((e,t)=>{S.message(e,{...t,symbol:c.green(Vt)})},"success"),step:o((e,t)=>{S.message(e,{...t,symbol:c.green(Lt)})},"step"),warn:o((e,t)=>{S.message(e,{...t,symbol:c.yellow(Kt)})},"warn"),error:o((e,t)=>{S.message(e,{...t,symbol:c.red(Yt)})},"error"),animated:o(async(e,{secondarySymbol:t=c.gray(O),output:n=process.stdout,clear:s=!1,...r}={})=>sn(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}={})=>rn(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 q(e){if(e instanceof g)S.space(1),he(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),he(t,{})}process.exit(0)}o(q,"handleError");function je(e){return{absolute:L(process.cwd(),e)}}o(je,"resolveDirectoryFromFlag");async function Ue(e){if(A())try{const{config:t}=await ee(),n=cn(t,e);return typeof n=="string"?L(process.cwd(),n):void 0}catch{return}}o(Ue,"resolveDirectoryFromConfig");function cn(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(cn,"getNestedValue");async function ln(e){if(e){const{absolute:t}=je(e);return{directory:t,fromConfig:!1}}if(A())try{const t=await Ue("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(`${v.CUBE} --styles-dir src/styles`)}
111
+
112
+ To create a config file:
113
+ ${c.cyan(v.INIT)}
114
+
115
+ Stuck? ${c.cyan("https://sugarcube.sh")}`)}o(ln,"getCssDir");async function un(e){if(e){const{absolute:t}=je(e);return{directory:t,fromConfig:!1}}if(A())try{const t=await Ue("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(`${v.COMPONENTS} --components-dir src/components/ui`)}
121
+
122
+ To create a config file:
123
+ ${c.cyan(v.INIT)}
124
+
125
+ Stuck? ${c.cyan("https://sugarcube.sh")}`)}o(un,"getComponentsDir");function x(e,t=process.cwd()){try{const n=ct(t,"package.json");if(!F(n))return!1;const s=Te(n,"utf-8"),r=JSON.parse(s),i={...r.dependencies,...r.devDependencies,...r.peerDependencies};return e in i}catch{return!1}}o(x,"isPackageInstalled");async function xe(e,{withFallback:t=!1}={}){const n=await mt({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(xe,"getPackageManager");function fn(e=process.cwd()){return ht(e)!==null}o(fn,"isTypeScriptProject");async function We(e=process.cwd()){return fn(e)?"sugarcube.config.ts":"sugarcube.config.js"}o(We,"getConfigFileName");function pn(e){return/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(e)}o(pn,"isValidIdentifier");function we(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} ${we(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=pn(i)?i:JSON.stringify(i);return`${n} ${a}: ${we(u,t+1)}`}).join(`,
130
+ `)}
131
+ ${n}}`}return JSON.stringify(e)}o(we,"formatValue");function dn(e,t,n){const s=we(e,0);let r;return n?r=t?`import type { UserConfig } from "@sugarcube-org/vite";
132
+
133
+ const config: UserConfig = `:`/**
134
+ * @type {import('@sugarcube-org/vite').UserConfig}
135
+ */
136
+ const config = `:r=`// Configuration reference: ${_e.CONFIGURATION}
137
+ const config = `,`${r}${s};
138
+
139
+ export default config;
140
+ `}o(dn,"formatConfigAsCode");async function Ge(e,t){try{const n=await We(),s=n.endsWith(".ts"),r=dn(e,s,t);await X(n,r,"utf-8")}catch(n){const s=n instanceof Error?`: ${n.message}`:"";throw new g(`Failed to write config file${s}`)}}o(Ge,"writeUserConfig");function gn(e,t){return{...e,...t,output:{...e.output??{},...t.output??{}},transforms:{...e.transforms??{},...t.transforms??{}}}}o(gn,"mergeUserConfig");async function Be(e){const{config:t}=await st(),n=gn(t,e),s=x(le);await Ge(n,s)}o(Be,"mergeConfigIntoFile");const mn=new M().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||J(Y(c.bgGreen(c.black("Components"))));const{directory:n,fromConfig:s}=await un(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 Oe(!1);const T=await j();T||(Ee("Failed to fetch component list"),process.exit(1)),r=await Zt(T,i)}const u=await xe(process.cwd(),{withFallback:!0}),a=await j(),l=await pe(a,r,i),f=await Rt({selectedComponents:r,componentType:i,componentsOutputDirectory:n}),p=Ne(f);if(p&&!t.force&&!t.silent){const T=Me(p,{});S.space(1),await Pe("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=>!x(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 de(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 At({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}),an(""),!s&&A()){const T=$(process.cwd(),n);await Be({output:{components:T}})}}catch(n){q(n)}}),hn=new M().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||J(Y("CUBE CSS"));const{directory:t,fromConfig:n}=await ln(e.stylesDir);try{await B(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=Ne(s);if(r&&!e.force&&!e.silent){S.space(1);const u=Me(r,{});await Pe("Continue?",!1)}const i=await Nt(t);if(!e.silent){S.space(1);const u=i,f=[...new Set(u)].map(p=>$(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&&A()){const u=$(process.cwd(),t);await Be({output:{css:u}})}}catch(t){q(t)}});function wn(){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(wn,"getDefaultScanPatterns");function yn(){return wn()}o(yn,"getScanPatterns");async function Ve(e,t){const n={name:"sugarcube",rules:ot(t.utilities??{},e),preflights:[]},s=await wt({presets:[n]}),r=yn(),i=await V(r,{dot:!0});if(i.length===0)return[];const a=(await Promise.all(i.map(f=>Xe(f,"utf8")))).join(`
141
+ `),{css:l}=await s.generate(a,{preflights:!1});return l?.trim()?[{path:`${t.output?.css||rt}/utilities/utilities.gen.css`,css:l,collection:"default"}]:[]}o(Ve,"generateSugarcubeUtilities");async function Tn(e,t,n){const s=[],r=await oe(e,t,n),i=await Se(r,n);await Ie(i),s.push(...i);const u=await Ve(r,n);return await ke(u),s.push(...u),s}o(Tn,"generateAllCSS");const Sn=new M().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||J(Y("Generate CSS")),x("@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(!A())throw new g(`A sugarcube config file was not found. This command requires one.
142
+
143
+ Please run ${c.cyan(v.INIT)} (or manually create a config file).
144
+
145
+ Stuck? ${c.cyan("https://sugarcube.sh")}`);const{config:t}=await ee(),{trees:n,resolved:s}=await K(t),r=await Tn(n,s,t);if(!e.silent){const i=r.map(f=>f.path),l=[...new Set(i)].map(f=>$(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){q(t)}});function In(e){return{source:[R($(process.cwd(),e.actualTokensDir),Re)]}}o(In,"createSingleTokenCollection");async function kn(e){return In(e)}o(kn,"buildTokensConfig");async function En(e){const t=await kn({actualTokensDir:e.actualTokensDir}),n=$(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(En,"buildUserConfig");function Ke(e,t=0){if(typeof e!="object"||e===null||t>It)return!1;for(const[n,s]of Object.entries(e))if(!n.startsWith("$")&&typeof s=="object"&&s!==null&&("$value"in s||Ke(s,t+1)))return!0;return!1}o(Ke,"hasAnyToken");async function bn(e){try{const t=await V(Re,{cwd:e,absolute:!0});for(const n of t)try{const s=await se.readFile(n,"utf-8"),r=JSON.parse(s);if(Ke(r))return!0}catch{}return!1}catch{return!1}}o(bn,"detectExistingTokens");const Ye=["**/node_modules/**",".next","public","dist","build",".astro",".nuxt",".output",".svelte-kit"];function Cn(e){try{const t=ie.resolve(e,"package.json");if(!F(t))return null;const n=Te(t,"utf-8");return JSON.parse(n)}catch{return null}}o(Cn,"getPackageJson");async function $n(e){const[t,n,s]=await Promise.all([V.glob("**/{next,vite,astro,nuxt,svelte,remix,eleventy}.config.*|.eleventy.js",{cwd:e,deep:3,ignore:Ye}),F(ie.resolve(e,"src")),Cn(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=F(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($n,"getProjectInfo");async function Rn(e,t){return!!((await V.glob("vite.config.*",{cwd:e,deep:1,ignore:Ye})).length>0||["vite","astro","nuxt","sveltekit","remix"].includes(t))}o(Rn,"shouldInstallVitePlugin");const _n=o(async e=>{S.space(2),await U(200);let t="Next steps";if(e.pluginToInstall===le)t+=`
146
+
147
+ `,t+=`1. Import the generated CSS
148
+ `,t+=` ${c.cyan("import 'virtual:sugarcube.css'")}`;else{const n=`${e.stylesDir}/global/tokens.variables.gen.css`;t+=`
149
+
150
+ `,t+=`1. Import the generated CSS
151
+ `,t+=` ${c.cyan(`import './${n}'`)}`}t+=`
152
+
153
+ `,t+=`2. (Optional) Add CUBE CSS
154
+ `,t+=` ${c.cyan(v.CUBE)}`,t+=`
155
+
156
+ `,t+=`3. (Optional) Add components
157
+ `,t+=` ${c.cyan(v.COMPONENTS)}`,t+=`
158
+
159
+ `,t+=`Docs: ${c.cyan("https://sugarcube.sh")}`,tn(t,{width:.75}),await U(200),S.break(1)},"nextSteps");async function Dn(e){await _n(e)}o(Dn,"next");const An=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 He(e,t){if(!e||e.trim()==="")throw new g(w.DIRECTORY_PATH_EMPTY(t));const s=Ze(e).split("/")[0];if(s&&St.includes(s))throw new g(w.DIRECTORY_PATH_RESERVED(t,e))}o(He,"validateDirectoryPath");function vn(e){e.tokensDir&&He(e.tokensDir,"tokens-dir"),e.stylesDir&&He(e.stylesDir,"styles-dir")}o(vn,"validateOptions");async function Nn(){A()&&(he(w.CONFIG_EXISTS(),{}),process.exit(0))}o(Nn,"preflightInit");async function Fn(e){const t=await $n(process.cwd()),n=e.tokensDir||t.tokensDir,s=e.stylesDir||t.stylesDir,r=await bn(n);return{tokensDir:n,stylesDir:s,isSrcDir:t.isSrcDir,hasExistingTokens:r,framework:t.framework}}o(Fn,"initializeProjectContext");async function On(e,t,n){const s=t?null:e.kit||ce;if((e.skip||[]).includes("plugin"))return{starterKit:s,pluginToInstall:null};const i=await Pn(n);return{starterKit:s,pluginToInstall:i}}o(On,"determineInstallationTargets");async function Pn(e){return await Rn(process.cwd(),e)?le:null}o(Pn,"determinePlugin");async function Ln(e,t,n,s,r){const i=await xe(process.cwd(),{withFallback:!0});return{options:e,...t,isSrcDir:t.isSrcDir,config:n,userConfig:s,...r,packageManager:i,createdFiles:[],createdDirectories:[],installedDependencies:[],tasks:[]}}o(Ln,"buildInitContext");async function Mn(e){const{trees:t,resolved:n}=await K(e.config);e.setupResult={config:e.config,createdTokenPaths:[],trees:t,resolved:n,tokenFiles:[],tokensDir:e.tokensDir}}o(Mn,"processExistingTokens");async function jn(e){!e.hasExistingTokens&&e.starterKit?await zt(e):await Mn(e)}o(jn,"setupDesignTokens");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 Se(s,e.config);await Ie(r)}o(Un,"writeCSSVariables");async function xn(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 Ve(s,e.config);r.length&&await ke(r)}o(xn,"writeCSSUtilities");async function Wn(e){if(e.pluginToInstall&&!x(e.pluginToInstall))try{await de([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(Wn,"installPlugins");async function Gn(e){try{const t=!!e.pluginToInstall;await Ge(e.userConfig,t);const n=await We();e.createdFiles.push(n)}catch{throw new g(w.CONFIG_WRITE_FAILED())}}o(Gn,"finalize");function Bn(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";x(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(Bn,"buildDetectionTasks");async function Vn(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 jn(e)},"while")}),!e.pluginToInstall)e.tasks.push({pending:"Generate CSS variables",start:"Generating CSS variables...",end:"CSS variables generated",while:o(async()=>{await Un(e)},"while")}),e.tasks.push({pending:"Generate CSS utilities",start:"Generating CSS utilities...",end:"CSS utilities generated",while:o(async()=>{await xn(e)},"while")});else if(e.pluginToInstall&&!x(e.pluginToInstall)){const t="Vite";e.tasks.push({pending:`Install ${t} plugin`,start:`Installing ${t} plugin...`,end:`${t} plugin installed`,while:o(async()=>{await Wn(e)},"while")})}e.tasks.push({pending:"Write configuration file",start:"Writing configuration file...",end:"Configuration file written",while:o(async()=>{await Gn(e)},"while")})}o(Vn,"buildExecutionTasks");const Kn=new M().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 Nn();const n=await Fn(e),s=await En({actualTokensDir:n.tokensDir,actualStylesDir:n.stylesDir,isSrcDir:n.isSrcDir}),r=it(s),i=await On(e,n.hasExistingTokens,n.framework);t=await Ln(e,n,r,s,i),J(Y("sugarcube")),await An();const u=Bn(t);u.length>0&&(S.message("Detecting project\u2026"),await S.tasks(u,{minDurationMs:1e3})),t.tasks=[],await Vn(t),t.tasks.length>0&&(S.message("Setting things up\u2026"),await S.tasks(t.tasks,{successMessage:"\u{1F389} Tasks completed successfully!"})),await Dn(t)}catch(n){q(n)}}),Yn=new M().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(J(Y("Validate")),A()&&!e.length){const{config:s}=await ee();await K(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(!F(s))throw new g(w.VALIDATE_PATH_NOT_FOUND(s));const t=await V(e.map(s=>s.endsWith(".json")?s:R(s,"**/*.json")));if(t.length===0)throw new g(w.VALIDATE_NO_TOKEN_FILES());const n=A()?(await ee()).config:{tokens:{source:[]},output:{css:".",separate:!1,modeAttribute:"data-mode",themeAttribute:"data-theme"},transforms:{fluid:{min:320,max:1200},colorFallbackStrategy:"native"}};await K({...n,tokens:{source:t.map(s=>$(process.cwd(),s))}}),ne(c.greenBright("All tokens valid \u2728"))}catch(t){q(t)}});process.on("SIGINT",()=>process.exit(0)),process.on("SIGTERM",()=>process.exit(0));async function Hn(){const e=new M().name("sugarcube").description("CLI for scaffolding sugarcube projects").version(Tt.version,"-v, --version","display the version number");e.addCommand(Kn).addCommand(Sn).addCommand(Yn).addCommand(mn).addCommand(hn),e.parse()}o(Hn,"main"),Hn();
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@sugarcube-org/cli",
3
- "version": "0.0.0-alpha.2",
3
+ "version": "0.0.0-alpha.20",
4
4
  "publishConfig": {
5
- "access": "restricted"
5
+ "access": "public",
6
+ "provenance": false
6
7
  },
7
8
  "description": "A CLI for scaffolding sugarcube applications",
8
- "license": "UNLICENSED",
9
+ "license": "SEE LICENSE IN LICENSE.md",
9
10
  "author": "Mark Tomlinson",
10
11
  "repository": {
11
12
  "type": "git",
@@ -28,35 +29,45 @@
28
29
  "LICENSE.md"
29
30
  ],
30
31
  "type": "module",
32
+ "main": "./dist/index.mjs",
33
+ "exports": {
34
+ ".": "./dist/index.mjs"
35
+ },
31
36
  "bin": {
32
37
  "sugarcube": "./dist/index.mjs"
33
38
  },
34
39
  "dependencies": {
35
- "@antfu/ni": "^23.3.0",
36
- "@clack/prompts": "^0.9.1",
37
- "commander": "^12.1.0",
38
- "cross-env": "^7.0.3",
39
- "execa": "^9.5.2",
40
- "fast-glob": "^3.3.2",
41
- "fs-extra": "^11.2.0",
42
- "lucide-react": "^0.468.0",
43
- "node-fetch": "^3.3.0",
44
- "picocolors": "^1.1.1",
45
- "prompts": "^2.4.2",
46
- "zod": "^3.23.8",
47
- "@sugarcube-org/core": "0.0.1-alpha.3"
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.9",
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"
48
56
  },
49
57
  "devDependencies": {
50
- "@types/fs-extra": "^11.0.4",
51
- "@types/prompts": "^2.4.9",
52
- "pkgroll": "^2.5.1",
53
- "tsx": "^4.19.2"
58
+ "cross-env": "7.0.3",
59
+ "pkgroll": "2.5.1",
60
+ "tsx": "4.19.2"
61
+ },
62
+ "engines": {
63
+ "node": ">=18.0.0"
54
64
  },
55
65
  "scripts": {
56
- "build": "pkgroll --minify",
57
- "dev": "cross-env REGISTRY_URL=http://localhost:8787/registry tsx src/index.ts",
58
- "test": "vitest",
66
+ "build": "tsc --noEmit && pkgroll --minify",
67
+ "dev": "cross-env REGISTRY_URL=http://localhost:4321/r tsx src/index.ts",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
59
70
  "type-check": "tsc --noEmit",
60
- "start": "cross-env REGISTRY_URL=https://sugarcube-registry.mark-tomlinson3.workers.dev/registry tsx src/index.ts"
71
+ "start": "cross-env REGISTRY_URL=https://sugarcube.sh/r tsx src/index.ts"
61
72
  }
62
73
  }