hugoblox 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +54 -46
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import $ from 'node:fs/promises';
|
|
4
4
|
import E from 'node:path';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import Ge from 'ora';
|
|
6
|
+
import rt from 'yaml';
|
|
7
7
|
import { execa } from 'execa';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
8
|
+
import Ne from 'node:os';
|
|
9
|
+
import St from 'node:dns/promises';
|
|
10
|
+
import ze from 'prompts';
|
|
11
|
+
import ye, { randomUUID } from 'node:crypto';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
13
|
import { promisify } from 'node:util';
|
|
14
14
|
import F from 'node:fs';
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
|
-
import
|
|
17
|
-
import
|
|
16
|
+
import M from 'semver';
|
|
17
|
+
import ve from 'chalk';
|
|
18
18
|
import { Buffer as Buffer$1 } from 'node:buffer';
|
|
19
19
|
|
|
20
|
-
var
|
|
21
|
-
\u{1F3A8} Themes installed successfully!`),(!C||!
|
|
20
|
+
var N=class extends Error{constructor(e,t="HBX_ERROR",r){super(e),this.name="HbxError",this.code=t,this.details=r;}},u=class extends N{constructor(e,t){super(e,"HBX_INPUT_ERROR",t);}},ee=class extends N{constructor(e="Operation cancelled by user"){super(e,"HBX_ABORTED");}},xe=class extends N{constructor(e,t){super(e,"HBX_CONFIG_ERROR",t);}};function ut(n){return !!(n&&typeof n=="object"&&"code"in n)}async function v(n){try{return await $.access(n),!0}catch{return false}}async function _(n){await $.mkdir(n,{recursive:true});}async function Pe(n){if(!await v(n)){await _(n);return}if((await $.readdir(n)).length>0)throw new Error(`Directory ${n} is not empty`)}async function R(n,e){await _(E.dirname(n)),await $.writeFile(n,e);}var ke="hbx",G="HBX_DEBUG",te="HBX_LICENSE_TOKEN",ft="HBX_TELEMETRY_DISABLED",Ve=E.join(Ne.homedir(),".hbx"),Ee=E.join(Ve,"config.json"),Nn=E.join(Ne.homedir(),".cache","hbx"),ne=E.join(Nn,"templates"),gt="HBX_UPDATE_CHECK_DISABLED",re="https://api.github.com",ht=`${re}/repos/HugoBlox/hugo-blox-builder/contents/templates`,yt="https://github.com/HugoBlox/hugo-blox-builder.git",wt="HBX_TEMPLATES_DIR",X="https://cli-api.hugoblox.com",bt=`${X}/api/usage-insights`,Te="hugoblox",vt=1e3*60*60*24,xt=1e3*60*60*12;var We=[{id:"academic-cv",name:"Academic CV",description:"Publish your academic CV and showcase your research.",repoPath:"templates/academic-cv",slug:"academic-cv",tags:["academic","cv"],source:"oss"},{id:"startup",name:"Startup",description:"Marketing site for SaaS and startups.",repoPath:"templates/startup",slug:"startup",tags:["business"],source:"oss"},{id:"folio",name:"Portfolio",description:"Minimal portfolio for creatives.",repoPath:"templates/folio",slug:"folio",tags:["portfolio"],source:"oss"}];var Ae="hbx.blocks.json";async function D(n=process.cwd()){let e=n,{root:t}=E.parse(n);for(;;){if((await Promise.all([v(E.join(e,"config","_default")),v(E.join(e,"hugoblox.yaml"))])).some(Boolean))return {root:e,manifestPath:E.join(e,Ae)};if(e===t)return;e=E.dirname(e);}}async function Ct(n){let e=E.join(n,"hugoblox.yaml");if(await v(e))try{let t=await $.readFile(e,"utf8"),r=rt.parse(t);if(!r)return;let o=r.template??{},i=r.build??{};return {templateId:o.id,templateName:o.name,requiredHugoVersion:i.hugo_version}}catch(t){throw new u("Failed to parse hugoblox.yaml",{error:t})}}async function Pt(){try{let{stdout:n}=await execa("hugo",["version"]);return Vn(n)}catch{return}}function Vn(n){let e=n.match(/v(\d+\.\d+\.\d+)/i);return e?e[1]:n.match(/(\d+\.\d+\.\d+)/)?.[1]}var q=class extends Error{constructor(t,r){super(t);this.cause=r;this.name="NetworkError";}};async function ie(n,e={}){let{timeout:t=15e3,retries:r=3,backoff:o=500,...i}=e,s=0;for(;s<=r;){let c=new AbortController,a=setTimeout(()=>c.abort(),t);try{let l=await fetch(n,{...i,signal:c.signal});if(clearTimeout(a),l.status===429||l.status>=500&&l.status<600)throw new q(`Server error: ${l.status}`);return l}catch(l){clearTimeout(a),s++;let m=l.name==="AbortError";if(s>r)throw m?new q(`Request timed out after ${t}ms`,l):l instanceof q?l:new q("Network request failed",l);let w=o*2**(s-1);await new Promise(d=>setTimeout(d,w));}}throw new q("Unreachable")}async function kt(){try{return await St.lookup("google.com"),!0}catch{try{return await St.lookup("1.1.1.1"),!0}catch{return false}}}async function B(n,e={}){if(e.ci){if(typeof e.initial=="string")return e.initial;throw new u(`Option required in CI mode: ${n}`)}return (await ze({type:"text",name:"value",message:n,initial:e.initial},{onCancel:()=>{throw new ee}})).value}async function he(n,e,t={}){if(t.ci){if(typeof t.initial=="string")return t.initial;throw new u(`Option required in CI mode: ${n}`)}return (await ze({type:"select",name:"value",message:n,choices:e,initial:0},{onCancel:()=>{throw new ee}})).value}async function H(n,e={}){if(e.ci){if(typeof e.initial=="boolean")return e.initial;throw new u(`Confirmation required in CI mode: ${n}`)}return (await ze({type:"confirm",name:"value",message:n,initial:e.initial??true},{onCancel:()=>{throw new ee}})).value}function At(n){let e=n.match(/github\.com[/:]([\w-]+)\/([\w-]+?)(?:\.git)?$/i);return e?{owner:e[1],repo:e[2]}:null}function Wn(n){return At(n)!==null}async function zn(n,e){let t=`https://api.github.com/repos/${n}/${e}/contents/hugoblox/themes`;try{let r=await ie(t,{headers:{"User-Agent":"hbx-cli",Accept:"application/vnd.github.v3+json"}});if(!r.ok)throw r.status===404?new u(`Repository does not contain a 'hugoblox/themes' directory. Please check the repository structure at https://github.com/${n}/${e}`):new u(`Failed to fetch themes from GitHub (status ${r.status})`);let i=(await r.json()).filter(s=>s.type==="file"&&s.name.toLowerCase().endsWith(".yaml"));if(i.length===0)throw new u(`No theme files found in hugoblox/themes directory at https://github.com/${n}/${e}`);return i.map(s=>({name:s.name,downloadUrl:s.download_url}))}catch(r){throw r instanceof u?r:new u(`Failed to access GitHub repository: ${r instanceof Error?r.message:String(r)}`)}}async function Gn(n,e){let t=await ie(n,{headers:{"User-Agent":"hbx-cli"}});if(!t.ok)throw new u(`Failed to download theme file (status ${t.status})`);let r=await t.text();await R(e,r);}async function Xn(n,e){let t=E.join(n,"config","_default","params.yaml");if(!await v(t))throw new u(`params.yaml not found at ${t}. Please ensure you're in a HugoBlox site.`);let r=await $.readFile(t,"utf8"),o=rt.parse(r),i=typeof o=="object"&&o!==null?o:{};(typeof i.hugoblox!="object"||i.hugoblox===null)&&(i.hugoblox={});let s=i.hugoblox;(typeof s.theme!="object"||s.theme===null)&&(s.theme={}),s.theme.pack=e;let c=rt.stringify(i);await $.writeFile(t,c,"utf8");}function U(n){return n.toLowerCase().replace(/\.yaml$/i,"")}function _t(n,e){n.command("theme").description("Add theme pack(s) from a GitHub repository").option("--repo <url>","GitHub repository URL containing themes").option("--theme <name>","Specific theme filename to download (without .yaml), or 'all' for all themes").option("--set-active","Set the downloaded theme as active in params.yaml").option("--no-set-active","Skip setting theme as active").option("--ci","Run in non-interactive mode").action(async(t,r)=>{let{logger:o,telemetry:i}=e,s=!!r.optsWithGlobals().json;try{let c=await D();if(!c)throw new u("Not in a HugoBlox site. Please run this command from within a HugoBlox site directory (must contain hugoblox.yaml)");let a=c.root,l=t.repo;if(!l){if(t.ci)throw new u("--repo is required when running with --ci");l=await B("Enter the GitHub repository URL containing themes (e.g., https://github.com/username/themes-repo):");}if(l=l.trim(),!Wn(l))throw new u("Invalid GitHub repository URL. Please provide a valid GitHub URL (e.g., https://github.com/owner/repo)");let m=At(l);if(!m)throw new u("Failed to parse GitHub URL");let{owner:p,repo:w}=m,d=p,g=Ge("Fetching available themes...").start(),h;try{h=await zn(p,w),g.succeed(`Found ${h.length} theme(s)`);}catch(S){throw g.fail("Failed to fetch themes"),S}let f,b=t.theme;if(!b)if(t.ci)b="all";else {let S=[{title:"All themes",value:"all"},...h.map(T=>({title:U(T.name),value:T.name}))];b=await he("Which theme(s) do you want to download?",S);}if(b.toLowerCase()==="all")f=h;else {let S=U(b),k=h.find(T=>U(T.name)===S);if(!k)throw new u(`Theme '${b}' not found. Available themes: ${h.map(T=>T.name).join(", ")}`);f=[k];}let P=E.join(a,"data","themes",d);await _(P);let x=Ge(`Downloading ${f.length} theme(s)...`).start();try{for(let S of f){let k=E.join(P,S.name);await Gn(S.downloadUrl,k);}x.succeed(`\u2705 Downloaded ${f.length} theme(s) to data/themes/${d}/`);}catch(S){throw x.fail("Failed to download themes"),S}let C=!1,j=null;if((t.setActive||t.setActive!==!1&&!t.noSetActive)&&(t.ci?f.length===1&&(C=!0,j=U(f[0].name)):(C=await H("Do you want to set one of these themes as active?",{initial:f.length===1}),C&&(f.length===1?j=U(f[0].name):j=await he("Which theme do you want to activate?",f.map(k=>({title:U(k.name),value:U(k.name)})))))),C&&j){let S=`${d}/${j}`,k=Ge("Updating params.yaml...").start();try{await Xn(a,S),k.succeed(`\u2705 Set active theme to: ${S}`);}catch(T){throw k.fail("Failed to update params.yaml"),T}}if(await i.track({name:"add-theme",payload:{vendor:d,themesCount:f.length,activated:C,ci:!!t.ci}}),s){o.json({status:"success",vendor:d,themes:f.map(S=>S.name),activated:j?`${d}/${j}`:null});return}o.success(`
|
|
21
|
+
\u{1F3A8} Themes installed successfully!`),(!C||!j)&&(o.info(`
|
|
22
22
|
\u{1F4DD} To use a theme, update your config/_default/params.yaml:`),o.info(`
|
|
23
|
-
hugoblox:`),o.info(" theme:"),o.info(` pack: "${u}/${U(g[0].name)}"`));}catch(c){if(s){o.json({status:"error",message:c instanceof Error?c.message:String(c)});return}throw c}});}function Ct(r,e){let t=r.command("add").description("Add resources (themes)");xt(t,e);}function Pt(r,e){r.command("block").argument("<id>","Block identifier").description("Create a new HugoBlox block").option("--example <slug>","Include sample content for the block").option("--dry-run","Print the actions without writing files").option("--yes","Overwrite files when they already exist").action((t,n,o)=>{let{logger:i}=e,s=!!o.optsWithGlobals().json,c="Block creation is coming soon. Follow Discord for updates or to preview it early.";if(s){i.json({status:"pending",message:c});return}i.info(c);});}var We="com.hugoblox.cli",$r=1,_r=createRequire(import.meta.url),Hr=promisify(pe.scrypt),M=null;try{M=_r("keytar");}catch{M=null;}async function St(r,e,t,n,o){let i=`device:${t}`,s,c;if(M)await M.setPassword(We,i,n);else {let a=await Dr(n,e);s=a.payload,c=a.salt;}r.setDeviceInfo({id:t,label:o,secretAlias:M?i:void 0,secretFallback:s,secretFallbackSalt:c,secretFallbackVersion:s?$r:void 0}),await r.save();}async function kt(r,e){let t=r.getDeviceInfo();if(!t?.id)return;let n;if(t.secretAlias&&M&&(n=await M.getPassword(We,t.secretAlias)),!n&&t.secretFallback&&t.secretFallbackSalt)try{let{key:o}=await Et(e,t.secretFallbackSalt);n=Rr(t.secretFallback,o);}catch{n=void 0;}if(n)return {id:t.id,secret:n,label:t.label}}async function ze(r){let e=r.getDeviceInfo();e?.secretAlias&&M&&await M.deletePassword(We,e.secretAlias),r.setDeviceInfo(void 0),await r.save();}function jr(r,e){let t=pe.randomBytes(12),n=pe.createCipheriv("aes-256-gcm",e.subarray(0,32),t),o=Buffer.concat([n.update(r,"utf8"),n.final()]),i=n.getAuthTag();return Buffer.concat([t,i,o]).toString("base64")}function Rr(r,e){let t=Buffer.from(r,"base64"),n=t.subarray(0,12),o=t.subarray(12,28),i=t.subarray(28),s=pe.createDecipheriv("aes-256-gcm",e.subarray(0,32),n);return s.setAuthTag(o),Buffer.concat([s.update(i),s.final()]).toString("utf8")}async function Et(r,e){let t=Buffer.from(e,"base64");return {key:await Hr(r,t,32,{N:32768,r:8,p:1,maxmem:64*1024*1024}),salt:e}}async function Dr(r,e){let t=pe.randomBytes(16).toString("base64"),{key:n}=await Et(e,t);return {payload:jr(r,n),salt:t}}async function L(r,e={}){let t=r.config.getLicense();if(!t)throw new d("Set HBX_LICENSE_TOKEN or run 'hbx login' to access Pro content.");let n=await r.config.ensureTelemetryId();if(e.force)await ze(r.config);else {let s=await kt(r.config,n);if(s)return {id:s.id,secret:s.secret}}let o=e.label??De.hostname(),i=await Lr(r.config,t,n,o);return await St(r.config,n,i.deviceId,i.deviceSecret,o),r.logger.debug(`Registered device ${i.deviceId}`),{id:i.deviceId,secret:i.deviceSecret}}async function Tt(r){await ze(r);}async function Lr(r,e,t,n){let o=await fetch(`${X}/api/license/devices/register`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json","x-telemetry-id":t},body:JSON.stringify({deviceLabel:n})}),i=await Nr(o);if(!o.ok)throw i?.code==="license_device_limit"?new d("This license has reached the maximum number of devices. Revoke an existing device and try again."):o.status===401||o.status===403?new d(i?.error??"Unable to register device"):new d(i?.error??`Device registration failed (status ${o.status})`);if(!i?.deviceId||!i?.deviceSecret)throw new d("Device registration response was missing credentials");return i}async function Nr(r){try{return await r.json()}catch{return}}function Or(r){return r.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}async function V(r){let{logger:e}=r,t=await Mr(e),n=await Fr(r);return t.length||n.length?[...n,...t]:Me}async function Mr(r){try{let e=await fetch(ct,{headers:{"User-Agent":"hbx-cli"}});if(!e.ok)throw new Error(`GitHub responded with status ${e.status}`);return (await e.json()).filter(o=>o.type==="dir").map(o=>({id:o.name,name:Or(o.name),description:`Starter template ${o.name}`,repoPath:o.path,slug:o.name,source:"oss"}))}catch(e){return r?.debug?.(`Falling back to offline starter metadata: ${String(e)}`),Me}}async function Fr(r){let{logger:e,config:t}=r,n=new Headers({"User-Agent":"hbx-cli"});try{let c=await t.ensureTelemetryId();n.set("x-telemetry-id",c);}catch{}let o,i=t.getLicense();if(i)try{let c=await L(r);o=new Headers(n),o.set("Authorization",`Bearer ${i}`),o.set("X-HBX-Device-Id",c.id),o.set("X-HBX-Device-Secret",c.secret);}catch(c){e?.debug?.(`Skipping device-auth headers for Pro templates: ${String(c)}`);}let s=[];o&&s.push({label:"with auth",headers:o}),s.push({label:o?"without auth":"anonymous",headers:n});for(let c of s)try{let a=await fetch(`${X}/api/pro-templates`,{headers:c.headers});if(!a.ok)throw new Error(`catalog responded with status ${a.status}`);return (await a.json()).templates.map(m=>({id:m.id,name:`${m.name} (Pro)`,description:m.description??void 0,repoPath:void 0,slug:m.slug??m.id,source:"pro",version:m.version,sizeBytes:m.sizeBytes,updatedAt:m.updatedAt,commitHash:m.commitHash,downloadEndpoint:m.downloadUrl}))}catch(a){e.debug(`Unable to fetch Pro template catalog (${c.label}): ${String(a)}`);}return []}async function Se(r,e){try{await execa("git",["init"],{cwd:r}),await execa("git",["add","."],{cwd:r}),await execa("git",["commit","-m","chore: initialize site"],{cwd:r,reject:!1}),e.success(`Initialized git repository in ${E.relative(process.cwd(),r)||"."}`);}catch(t){e.warn(`Git initialization skipped: ${String(t)}`);}}async function Xe(r,e,t={},n=0){let o=r.config.getLicense();if(!o)throw new d("A HugoBlox Pro license key is required before accessing Pro templates.");let i=await r.config.ensureTelemetryId(),s=await L(r,{force:n>0}),c=new Headers(t.headers??{});c.set("Authorization",`Bearer ${o}`),c.set("X-HBX-Device-Id",s.id),c.set("X-HBX-Device-Secret",s.secret),c.set("X-Telemetry-Id",i);let a=await fetch(`${X}${e}`,{...t,headers:c});if((a.status===401||a.status===403)&&n===0)return await L(r,{force:true}),Xe(r,e,t,n+1);if(!a.ok){let l=await Vr(a);throw l?.code==="license_device_limit"?new d("This license has reached the maximum number of devices. Revoke an existing device and try again."):a.status===401||a.status===403?new d(l?.error??"Device authentication failed."):new d(l?.error??`Request failed (${a.status})`)}return a}async function Vr(r){try{return await r.json()}catch{return}}var Wr=3;async function $t(r,e,t,n){if(e.source==="pro"){await Jr(r,e,t,n);return}let o=process.env[mt];if(o){await zr(e,o,t),n.debug(`Hydrated template ${e.id} from local override`);return}let i=await Xr(e,n),s=i!==void 0?E.join(te,e.id,i):void 0;if(s&&await v(s)){await q(s,t),n.debug(`Hydrated template ${e.id} from cache (${i})`);return}let c=await T.mkdtemp(E.join(De.tmpdir(),"hbx-template-")),a=E.join(c,"repo");try{await execa("git",["clone","--depth","1",lt,a],{stdio:"ignore"});let l=await Gr(a,e);s?(await $(E.dirname(s)),await T.rm(s,{recursive:!0,force:!0}),await T.cp(l,s,{recursive:!0}),await _t(E.join(te,e.id)),await q(s,t),n.debug(`Hydrated template ${e.id} from fresh cache (${i})`)):(await q(l,t),n.debug(`Hydrated template ${e.id} from repository`));}catch(l){throw new d("Failed to clone HugoBlox templates. Ensure git is installed and accessible.",{error:l})}finally{await T.rm(c,{recursive:true,force:true});}}async function zr(r,e,t){let n=E.join(e,r.id);try{await T.access(n);}catch(o){throw new d(`Local template not found at ${n}`,{error:o})}await q(n,t);}async function Gr(r,e){let t=e.repoPath??"",n=E.join(r,t);return await T.access(n),n}async function q(r,e){await T.rm(e,{recursive:true,force:true}),await $(E.dirname(e)),await T.cp(r,e,{recursive:true}),await T.rm(E.join(e,".git"),{recursive:true,force:true});}async function _t(r){if(!await v(r))return;let e=await T.readdir(r,{withFileTypes:true}),t=await Promise.all(e.filter(n=>n.isDirectory()).map(async n=>{let o=E.join(r,n.name),i=await T.stat(o);return {path:o,mtimeMs:i.mtimeMs}}));t.sort((n,o)=>o.mtimeMs-n.mtimeMs);for(let n of t.slice(Wr))await T.rm(n.path,{recursive:true,force:true});}async function Xr(r,e){let t=encodeURIComponent(r.repoPath??""),n=`${re}/repos/HugoBlox/hugo-blox-builder/commits?path=${t}&per_page=1`;try{let o=await fetch(n,{headers:{"User-Agent":"hbx-cli"}});if(!o.ok)throw new Error(`GitHub responded with status ${o.status}`);return (await o.json())[0]?.sha}catch(o){e.debug(`Unable to determine latest template commit for ${r.id}: ${String(o)}`);return}}async function Jr(r,e,t,n){let o=e.version?E.join(te,e.id,e.version):void 0;if(o&&await v(o)){await q(o,t),n.debug(`Hydrated Pro template ${e.id} from cache (${e.version})`);return}let i=await T.mkdtemp(E.join(De.tmpdir(),"hbx-pro-template-")),s=E.join(i,"template.tgz"),c=E.join(i,"extract");await $(c);try{let a=await qr(r,e,s);await execa("tar",["-xzf",s,"-C",c]);let l=await Kr(c,e.slug),m=e.version??a.version??void 0,f=m!==void 0?E.join(te,e.id,m):void 0;f?(await $(E.dirname(f)),await T.rm(f,{recursive:!0,force:!0}),await T.cp(l,f,{recursive:!0}),await _t(E.join(te,e.id)),await q(f,t),n.debug(`Hydrated Pro template ${e.id} from fresh cache (${m})`)):(await q(l,t),n.debug(`Hydrated Pro template ${e.id} from archive`));}catch(a){throw new d(`Failed to download Pro template ${e.name}. Ensure your license is valid and try again.`,{error:a})}finally{await T.rm(i,{recursive:true,force:true});}}async function qr(r,e,t){let n=e.downloadEndpoint??`/api/pro-templates/${encodeURIComponent(e.id)}/download`,o=await Xe(r,n),i=await Yr(o);if(!i?.url)throw new d("Pro template download URL was missing");let s=await fetch(i.url);if(!s.ok)throw new d(`Pro template archive download failed (${s.status})`);let c=Buffer.from(await s.arrayBuffer());return await T.writeFile(t,c),{version:i.version}}async function Kr(r,e){let t=await T.readdir(r,{withFileTypes:true}),n=t.find(i=>i.isDirectory()&&i.name===e);if(n)return E.join(r,n.name);let o=t.filter(i=>i.isDirectory());return o.length===1?E.join(r,o[0].name):r}async function Yr(r){try{return await r.json()}catch{return}}var Ht="https://hugoblox.com/discord",jt="https://docs.hugoblox.com",Rt="https://hugoblox.com/pro";function z(r){return r.trim().toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-{2,}/g,"-").replace(/^-+|-+$/g,"").slice(0,64)}async function ke(r,e,t,n){let{logger:o}=r;await $t(r,t,e,o),await Zr(e,t,n),n.sampleContent||await tn(e,t);}async function Ee(r,e,t){t.info(`\u{1F4E6} Installing dependencies with ${e}...`);let n={...process.env},o=["install"],i=!t.isJsonMode();e==="pnpm"&&(n.PNPM_WORKSPACE_DIR=r,n.PNPM_IGNORE_WORKSPACE_ROOT_CHECK="1",await Qr(r),o.push("--no-link-workspace-packages"));try{return await execa(e,o,{cwd:r,stdio:i?"ignore":"inherit",env:n}),t.success("\u2705 Dependencies installed"),!0}catch(s){return i?t.warn(`\u26A0\uFE0F Failed to install dependencies automatically. Run ${e} install inside ${r}`):t.warn(`\u26A0\uFE0F Failed to install dependencies automatically: ${String(s)}`),false}}async function Qr(r){let e=E.join(r,"pnpm-workspace.yaml");if(await v(e))return;await j(e,`packages:
|
|
23
|
+
hugoblox:`),o.info(" theme:"),o.info(` pack: "${d}/${U(f[0].name)}"`));}catch(c){if(s){o.json({status:"error",message:c instanceof Error?c.message:String(c)});return}throw c}});}function $t(n,e){let t=n.command("add").description("Add resources (themes)");_t(t,e);}function It(n,e){n.command("block").argument("<id>","Block identifier").description("Create a new HugoBlox block").option("--example <slug>","Include sample content for the block").option("--dry-run","Print the actions without writing files").option("--yes","Overwrite files when they already exist").action((t,r,o)=>{let{logger:i}=e,s=!!o.optsWithGlobals().json,c="Block creation is coming soon. Follow Discord for updates or to preview it early.";if(s){i.json({status:"pending",message:c});return}i.info(c);});}var qe="com.hugoblox.cli",Kn=1,Yn=createRequire(import.meta.url),Qn=promisify(ye.scrypt),O=null;try{O=Yn("keytar");}catch{O=null;}async function Ht(n,e,t,r,o){let i=`device:${t}`,s,c;if(O)await O.setPassword(qe,i,r);else {let a=await tr(r,e);s=a.payload,c=a.salt;}n.setDeviceInfo({id:t,label:o,secretAlias:O?i:void 0,secretFallback:s,secretFallbackSalt:c,secretFallbackVersion:s?Kn:void 0}),await n.save();}async function jt(n,e){let t=n.getDeviceInfo();if(!t?.id)return;let r;if(t.secretAlias&&O&&(r=await O.getPassword(qe,t.secretAlias)),!r&&t.secretFallback&&t.secretFallbackSalt)try{let{key:o}=await Rt(e,t.secretFallbackSalt);r=er(t.secretFallback,o);}catch{r=void 0;}if(r)return {id:t.id,secret:r,label:t.label}}async function Je(n){let e=n.getDeviceInfo();e?.secretAlias&&O&&await O.deletePassword(qe,e.secretAlias),n.setDeviceInfo(void 0),await n.save();}function Zn(n,e){let t=ye.randomBytes(12),r=ye.createCipheriv("aes-256-gcm",e.subarray(0,32),t),o=Buffer.concat([r.update(n,"utf8"),r.final()]),i=r.getAuthTag();return Buffer.concat([t,i,o]).toString("base64")}function er(n,e){let t=Buffer.from(n,"base64"),r=t.subarray(0,12),o=t.subarray(12,28),i=t.subarray(28),s=ye.createDecipheriv("aes-256-gcm",e.subarray(0,32),r);return s.setAuthTag(o),Buffer.concat([s.update(i),s.final()]).toString("utf8")}async function Rt(n,e){let t=Buffer.from(e,"base64");return {key:await Qn(n,t,32,{N:32768,r:8,p:1,maxmem:64*1024*1024}),salt:e}}async function tr(n,e){let t=ye.randomBytes(16).toString("base64"),{key:r}=await Rt(e,t);return {payload:Zn(n,r),salt:t}}async function L(n,e={}){let t=n.config.getLicense();if(!t)throw new u("Set HBX_LICENSE_TOKEN or run 'hbx login' to access Pro content.");let r=await n.config.ensureTelemetryId();if(e.force)await Je(n.config);else {let s=await jt(n.config,r);if(s)return {id:s.id,secret:s.secret}}let o=e.label??Ne.hostname(),i=await rr(n.config,t,r,o);return await Ht(n.config,r,i.deviceId,i.deviceSecret,o),n.logger.debug(`Registered device ${i.deviceId}`),{id:i.deviceId,secret:i.deviceSecret}}async function Dt(n){await Je(n);}async function rr(n,e,t,r){let o=await fetch(`${X}/api/license/devices/register`,{method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json","x-telemetry-id":t},body:JSON.stringify({deviceLabel:r})}),i=await or(o);if(!o.ok)throw i?.code==="license_device_limit"?new u("This license has reached the maximum number of devices. Revoke an existing device and try again."):o.status===401||o.status===403?new u(i?.error??"Unable to register device"):new u(i?.error??`Device registration failed (status ${o.status})`);if(!i?.deviceId||!i?.deviceSecret)throw new u("Device registration response was missing credentials");return i}async function or(n){try{return await n.json()}catch{return}}function ir(n){return n.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}async function V(n){let{logger:e}=n,t=await sr(e),r=await ar(n);return t.length||r.length?[...r,...t]:We}async function sr(n){try{let e=await fetch(ht,{headers:{"User-Agent":"hbx-cli"}});if(!e.ok)throw new Error(`GitHub responded with status ${e.status}`);return (await e.json()).filter(o=>o.type==="dir").map(o=>({id:o.name,name:ir(o.name),description:`Starter template ${o.name}`,repoPath:o.path,slug:o.name,source:"oss"}))}catch(e){return n?.debug?.(`Falling back to offline starter metadata: ${String(e)}`),We}}async function ar(n){let{logger:e,config:t}=n,r=new Headers({"User-Agent":"hbx-cli"});try{let c=await t.ensureTelemetryId();r.set("x-telemetry-id",c);}catch{}let o,i=t.getLicense();if(i)try{let c=await L(n);o=new Headers(r),o.set("Authorization",`Bearer ${i}`),o.set("X-HBX-Device-Id",c.id),o.set("X-HBX-Device-Secret",c.secret);}catch(c){e?.debug?.(`Skipping device-auth headers for Pro templates: ${String(c)}`);}let s=[];o&&s.push({label:"with auth",headers:o}),s.push({label:o?"without auth":"anonymous",headers:r});for(let c of s)try{let a=await fetch(`${X}/api/pro-templates`,{headers:c.headers});if(!a.ok)throw new Error(`catalog responded with status ${a.status}`);return (await a.json()).templates.map(m=>({id:m.id,name:`${m.name} (Pro)`,description:m.description??void 0,repoPath:void 0,slug:m.slug??m.id,source:"pro",version:m.version,sizeBytes:m.sizeBytes,updatedAt:m.updatedAt,commitHash:m.commitHash,downloadEndpoint:m.downloadUrl}))}catch(a){e.debug(`Unable to fetch Pro template catalog (${c.label}): ${String(a)}`);}return []}async function _e(n,e){try{await execa("git",["init"],{cwd:n}),await execa("git",["add","."],{cwd:n}),await execa("git",["commit","-m","chore: initialize site"],{cwd:n,reject:!1}),e.success(`Initialized git repository in ${E.relative(process.cwd(),n)||"."}`);}catch(t){e.warn(`Git initialization skipped: ${String(t)}`);}}async function Ye(n,e,t={},r=0){let o=n.config.getLicense();if(!o)throw new u("A HugoBlox Pro license key is required before accessing Pro templates.");let i=await n.config.ensureTelemetryId(),s=await L(n,{force:r>0}),c=new Headers(t.headers??{});c.set("Authorization",`Bearer ${o}`),c.set("X-HBX-Device-Id",s.id),c.set("X-HBX-Device-Secret",s.secret),c.set("X-Telemetry-Id",i);let a=await fetch(`${X}${e}`,{...t,headers:c});if((a.status===401||a.status===403)&&r===0)return await L(n,{force:true}),Ye(n,e,t,r+1);if(!a.ok){let l=await lr(a);throw l?.code==="license_device_limit"?new u("This license has reached the maximum number of devices. Revoke an existing device and try again."):a.status===401||a.status===403?new u(l?.error??"Device authentication failed."):new u(l?.error??`Request failed (${a.status})`)}return a}async function lr(n){try{return await n.json()}catch{return}}var mr=3;async function Mt(n,e,t,r){if(e.source==="pro"){await fr(n,e,t,r);return}let o=process.env[wt];if(o){await dr(e,o,t),r.debug(`Hydrated template ${e.id} from local override`);return}let i=await pr(e,r),s=i!==void 0?E.join(ne,e.id,i):void 0;if(s&&await v(s)){await J(s,t),r.debug(`Hydrated template ${e.id} from cache (${i})`);return}let c=await $.mkdtemp(E.join(Ne.tmpdir(),"hbx-template-")),a=E.join(c,"repo");try{await execa("git",["clone","--depth","1",yt,a],{stdio:"ignore"});let l=await ur(a,e);s?(await _(E.dirname(s)),await $.rm(s,{recursive:!0,force:!0}),await $.cp(l,s,{recursive:!0}),await Nt(E.join(ne,e.id)),await J(s,t),r.debug(`Hydrated template ${e.id} from fresh cache (${i})`)):(await J(l,t),r.debug(`Hydrated template ${e.id} from repository`));}catch(l){throw new u("Failed to clone HugoBlox templates. Ensure git is installed and accessible.",{error:l})}finally{await $.rm(c,{recursive:true,force:true});}}async function dr(n,e,t){let r=E.join(e,n.id);try{await $.access(r);}catch(o){throw new u(`Local template not found at ${r}`,{error:o})}await J(r,t);}async function ur(n,e){let t=e.repoPath??"",r=E.join(n,t);return await $.access(r),r}async function J(n,e){await $.rm(e,{recursive:true,force:true}),await _(E.dirname(e)),await $.cp(n,e,{recursive:true}),await $.rm(E.join(e,".git"),{recursive:true,force:true});}async function Nt(n){if(!await v(n))return;let e=await $.readdir(n,{withFileTypes:true}),t=await Promise.all(e.filter(r=>r.isDirectory()).map(async r=>{let o=E.join(n,r.name),i=await $.stat(o);return {path:o,mtimeMs:i.mtimeMs}}));t.sort((r,o)=>o.mtimeMs-r.mtimeMs);for(let r of t.slice(mr))await $.rm(r.path,{recursive:true,force:true});}async function pr(n,e){let t=encodeURIComponent(n.repoPath??""),r=`${re}/repos/HugoBlox/hugo-blox-builder/commits?path=${t}&per_page=1`;try{let o=await fetch(r,{headers:{"User-Agent":"hbx-cli"}});if(!o.ok)throw new Error(`GitHub responded with status ${o.status}`);return (await o.json())[0]?.sha}catch(o){e.debug(`Unable to determine latest template commit for ${n.id}: ${String(o)}`);return}}async function fr(n,e,t,r){let o=e.version?E.join(ne,e.id,e.version):void 0;if(o&&await v(o)){await J(o,t),r.debug(`Hydrated Pro template ${e.id} from cache (${e.version})`);return}let i=await $.mkdtemp(E.join(Ne.tmpdir(),"hbx-pro-template-")),s=E.join(i,"template.tgz"),c=E.join(i,"extract");await _(c);try{let a=await gr(n,e,s);await execa("tar",["-xzf",s,"-C",c]);let l=await hr(c,e.slug),m=e.version??a.version??void 0,p=m!==void 0?E.join(ne,e.id,m):void 0;p?(await _(E.dirname(p)),await $.rm(p,{recursive:!0,force:!0}),await $.cp(l,p,{recursive:!0}),await Nt(E.join(ne,e.id)),await J(p,t),r.debug(`Hydrated Pro template ${e.id} from fresh cache (${m})`)):(await J(l,t),r.debug(`Hydrated Pro template ${e.id} from archive`));}catch(a){throw new u(`Failed to download Pro template ${e.name}. Ensure your license is valid and try again.`,{error:a})}finally{await $.rm(i,{recursive:true,force:true});}}async function gr(n,e,t){let r=e.downloadEndpoint??`/api/pro-templates/${encodeURIComponent(e.id)}/download`,o=await Ye(n,r),i=await yr(o);if(!i?.url)throw new u("Pro template download URL was missing");let s=await fetch(i.url);if(!s.ok)throw new u(`Pro template archive download failed (${s.status})`);let c=Buffer.from(await s.arrayBuffer());return await $.writeFile(t,c),{version:i.version}}async function hr(n,e){let t=await $.readdir(n,{withFileTypes:true}),r=t.find(i=>i.isDirectory()&&i.name===e);if(r)return E.join(n,r.name);let o=t.filter(i=>i.isDirectory());return o.length===1?E.join(n,o[0].name):n}async function yr(n){try{return await n.json()}catch{return}}var Ot="https://hugoblox.com/discord",Ft="https://docs.hugoblox.com",Ut="https://hugoblox.com/pro";function z(n){return n.trim().toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-{2,}/g,"-").replace(/^-+|-+$/g,"").slice(0,64)}async function $e(n,e,t,r){let{logger:o}=n;await Mt(n,t,e,o),await br(e,t,r),r.sampleContent||await xr(e,t);}async function Ie(n,e,t){t.info(`\u{1F4E6} Installing dependencies with ${e}...`);let r={...process.env},o=["install"],i=!t.isJsonMode();e==="pnpm"&&(r.PNPM_WORKSPACE_DIR=n,r.PNPM_IGNORE_WORKSPACE_ROOT_CHECK="1",await wr(n),o.push("--no-link-workspace-packages"));try{return await execa(e,o,{cwd:n,stdio:i?"ignore":"inherit",env:r}),t.success("\u2705 Dependencies installed"),!0}catch(s){return i?t.warn(`\u26A0\uFE0F Failed to install dependencies automatically. Run ${e} install inside ${n}`):t.warn(`\u26A0\uFE0F Failed to install dependencies automatically: ${String(s)}`),false}}async function wr(n){let e=E.join(n,"pnpm-workspace.yaml");if(await v(e))return;await R(e,`packages:
|
|
24
24
|
- './*'
|
|
25
|
-
`);}async function
|
|
25
|
+
`);}async function zt(n,e,t){t.info("\u{1F525} Starting dev server with Hugo (press Ctrl+C to exit)...");let r={...process.env};e==="pnpm"&&(r.PNPM_WORKSPACE_DIR=n);try{await execa(e,["dev"],{cwd:n,stdio:"inherit",env:r}),t.success("\u2705 Dev server stopped");}catch(o){let i=o;if(i.signal==="SIGINT"||i.signal==="SIGTERM"){t.info("\u2705 Dev server stopped");return}if(o?.code==="ENOENT"||/[hH]ugo/.test(String(i.stderr))){t.error("Hugo executable not found. Install Hugo (https://docs.hugoblox.com/start/cli) or deploy with the Copilot at https://hugoblox.com/templates/");return}throw t.error(`Dev server exited with an error: ${String(o)}`),o}}async function br(n,e,t){let r=z(E.basename(n))||e.slug;await vr(n,r);let o={"README.md":`# ${e.name}
|
|
26
26
|
|
|
27
27
|
This site was created with the HugoBlox CLI.
|
|
28
28
|
`,".gitignore":`node_modules
|
|
@@ -33,8 +33,8 @@ public
|
|
|
33
33
|
modules/_vendor
|
|
34
34
|
`};t.includeEnv&&(o[".env"]=`# HBX environment variables
|
|
35
35
|
HBX_LICENSE_TOKEN=
|
|
36
|
-
`);for(let[i,s]of Object.entries(o)){let c=E.join(
|
|
37
|
-
title: "${
|
|
36
|
+
`);for(let[i,s]of Object.entries(o)){let c=E.join(n,i);await v(c)||await R(c,s);}}async function vr(n,e){let t=E.join(n,"package.json"),r={name:e,private:true,scripts:{dev:"hugo server -D",build:"hugo --gc --minify",lint:"echo 'TODO: add lint script'"},dependencies:{}};if(!await v(t)){await R(t,JSON.stringify(r,null,2));return}try{let o=await $.readFile(t,"utf8"),i=JSON.parse(o),s={...r,...i,name:e,scripts:{...r.scripts,...i.scripts},dependencies:{...r.dependencies,...i.dependencies}};await R(t,JSON.stringify(s,null,2));}catch{await R(t,JSON.stringify(r,null,2));}}async function xr(n,e){let t=E.join(n,"content");await $.rm(t,{recursive:true,force:true}),await _(E.dirname(E.join(t,"_index.md"))),await R(E.join(t,"_index.md"),Cr(e));}function Cr(n){return `---
|
|
37
|
+
title: "${n.name}"
|
|
38
38
|
type: landing
|
|
39
39
|
design:
|
|
40
40
|
spacing: "5rem"
|
|
@@ -43,18 +43,18 @@ sections:
|
|
|
43
43
|
- block: hero
|
|
44
44
|
content:
|
|
45
45
|
eyebrow: "You're live on HugoBlox"
|
|
46
|
-
title: "Great job launching ${
|
|
46
|
+
title: "Great job launching ${n.name}"
|
|
47
47
|
text: "Start customizing blocks to launch your next experience."
|
|
48
48
|
primary_action:
|
|
49
49
|
text: "Join our Discord"
|
|
50
|
-
url: "${
|
|
50
|
+
url: "${Ot}"
|
|
51
51
|
icon: "chat-bubble-left-right"
|
|
52
52
|
secondary_action:
|
|
53
53
|
text: "Upgrade to Pro"
|
|
54
|
-
url: "${
|
|
54
|
+
url: "${Ut}"
|
|
55
55
|
tertiary_action:
|
|
56
56
|
text: "View Docs"
|
|
57
|
-
url: "${
|
|
57
|
+
url: "${Ft}"
|
|
58
58
|
design:
|
|
59
59
|
css_class: "bg-gradient-to-r from-blue-600 to-indigo-600 text-white"
|
|
60
60
|
spacing:
|
|
@@ -63,47 +63,55 @@ sections:
|
|
|
63
63
|
content:
|
|
64
64
|
title: "Your next steps"
|
|
65
65
|
text: |
|
|
66
|
-
1. Join the community on [Discord](${
|
|
67
|
-
2. Explore the [documentation](${
|
|
68
|
-
3. [Upgrade to Pro](${
|
|
66
|
+
1. Join the community on [Discord](${Ot}) for support and inspiration.
|
|
67
|
+
2. Explore the [documentation](${Ft}) to learn how to add blocks, deploy, and automate.
|
|
68
|
+
3. [Upgrade to Pro](${Ut}) to unlock premium blocks, design systems, and automation-ready packages.
|
|
69
69
|
4. Share feedback and showcase your build to help the ecosystem grow.
|
|
70
|
-
`}function
|
|
70
|
+
`}function Qe(n){return n?n.length<=6?"***":`${n.slice(0,3)}***${n.slice(-2)}`:"(none)"}function He(n,e){let t=n??e;return E.resolve(process.cwd(),t)}async function Gt(n=process.cwd()){let e=E.join(n,"pnpm-lock.yaml"),t=E.join(n,"yarn.lock"),r=E.join(n,"package-lock.json");return F.existsSync(e)?"pnpm":F.existsSync(t)?"yarn":F.existsSync(r)?"npm":"pnpm"}async function je(n){try{let e=E.resolve(n);if(n.includes("\0")||/[<>:"|?*]/.test(n))return {valid:!1,exists:!1,isEmpty:!1,writable:!1,error:"Path contains invalid characters"};let t=!1,r=!1,o=!1;try{let i=F.statSync(e);if(t=!0,i.isDirectory()){r=F.readdirSync(e).length===0;try{F.accessSync(e,F.constants.W_OK),o=!0;}catch{o=!1;}}else return {valid:!1,exists:!0,isEmpty:!1,writable:!1,error:"Path exists but is not a directory"}}catch{let s=E.dirname(e);try{F.accessSync(s,F.constants.W_OK),o=!0;}catch{return {valid:!1,exists:!1,isEmpty:!1,writable:!1,error:"Parent directory is not writable"}}}return {valid:!0,exists:t,isEmpty:r,writable:o}}catch(e){return {valid:false,exists:false,isEmpty:false,writable:false,error:e instanceof Error?e.message:"Unknown error"}}}function Pr(n,e){if(!e)return;let t=e.toLowerCase(),r=n.find(o=>{let i=o.id.toLowerCase(),s=o.slug?.toLowerCase();return i===t||s===t});if(r)return r;if(e.startsWith("http")||e.startsWith("git@"))return {id:e,name:"Custom template",description:`External template: ${e}`,repoPath:e,slug:"custom",source:"custom"}}function Jt(n,e){n.command("site").description("Create a new HugoBlox site").argument("[dir]","Target directory (defaults to template slug, e.g., new-site)").option("--template <id>","Starter template ID").option("--dir <path>","Target directory").option("--package-manager <name>","Package manager","pnpm").option("--no-install","Skip dependency installation").option("--git","Initialize a git repository").option("--ci","Run in non-interactive mode").option("--sample-content","Force include sample content").option("--no-sample-content","Skip sample content").option("--pro","Mark the project as Pro ready").option("--preview","Automatically start the dev server after setup").option("--no-preview","Skip the dev server prompt").action(async(t,r,o)=>{let{logger:i,config:s,telemetry:c}=e,l=!!o.optsWithGlobals().json,m=Ge({text:"Fetching templates...",spinner:"dots"}).start(),p=await V(e).finally(()=>{m.succeed("\u2728 Templates ready");}),d=Pr(p,r.template);if(!d){if(r.ci)throw new u("Template must be specified when running with --ci");let k=await he("Select a starter",p.map(T=>({title:T.name,description:T.description,value:T.id})));d=p.find(T=>T.id===k);}if(!d)throw new u("Unable to determine template");let g=d.source==="pro",h=await kr(r,t,d),f=He(h,d.slug);await Pe(f);let b=typeof r.sampleContent=="boolean"?r.sampleContent:typeof r.noSampleContent=="boolean"?!r.noSampleContent:r.ci?false:await H("Include sample content? (recommended)",{initial:true}),P=g;if(!g)P=typeof r.pro=="boolean"?r.pro:r.ci?false:await H("Do you have a HugoBlox Pro license?",{initial:!!s.getLicense()});else if(!s.getLicense()){if(r.ci)throw new u(`"${d.name}" is a HugoBlox Pro template. Set HBX_LICENSE_TOKEN with your license key before running in CI.`);if(i.info(`"${d.name}" is part of HugoBlox Pro. Purchase a license at https://hugoblox.com/pro to receive your key via email (powered by Lemon Squeezy).`),!await H("Do you have a HugoBlox Pro license key to enter now?",{initial:true}))throw new u("Pro templates require an active license. Purchase at https://hugoblox.com/pro and rerun this command after running 'hbx login' or setting HBX_LICENSE_TOKEN.");let T=await qt(s.getLicense());s.setLicense(T),await s.save();}if(!g&&P&&!s.getLicense()){if(r.ci)throw new u("Set HBX_LICENSE_TOKEN before running --ci when enabling Pro features.");let k=await qt(s.getLicense());s.setLicense(k),await s.save();}P&&await L(e);let x=Ge(`Creating site in ${E.relative(process.cwd(),f)||"."}...`).start();try{await $e(e,f,d,{sampleContent:b,includeEnv:!0,packageManager:r.packageManager??"pnpm"}),x.succeed("Files generated");}catch(k){throw x.fail("Failed to scaffold site"),k}let C=false;r.install!==false?C=await Ie(f,r.packageManager??"pnpm",i):i.info("Skipping dependency installation"),r.git&&await _e(f,i);let j={status:"success",template:d.id,path:f,pro:P,manifest:E.join(f,Ae)};!C&&r.preview?i.warn("\u26A0\uFE0F Cannot start the dev server because dependencies failed to install."):r.install===false&&r.preview&&i.warn("\u26A0\uFE0F Install dependencies first (skip --no-install) to start the dev server automatically.");let S=false;if(C&&(S=await Sr(r,l)),await c.track({name:"new-site",payload:{template:d.id,sample:b,pro:P,ci:!!r.ci,packageManager:r.packageManager??"pnpm",install:r.install!==false,dependenciesReady:C,preview:S}}),S){await zt(f,r.packageManager??"pnpm",i);return}if(l){i.json(j);return}i.success(`\u2705 Site created at ${f}`),i.info("\u{1F680} Next steps:"),i.info(` \u{1F449} cd ${E.relative(process.cwd(),f)||f}`),r.install===false&&i.info(` \u{1F449} ${r.packageManager??"pnpm"} install`),i.info(" \u{1F449} pnpm dev");});}async function Sr(n,e){return e||n.ci?false:typeof n.preview=="boolean"?n.preview:n.noPreview?false:H("Start the dev server now?",{initial:true})}async function kr(n,e,t){if(n.dir)return n.dir;if(e)return e;if(n.ci)return t.slug;let o=(await B("Project folder name",{initial:t.slug})).trim();return o?Er(o)?o:z(o)||t.slug:t.slug}function Er(n){return /[\\/]/.test(n)||n.includes(":")}async function qt(n){let t=(await B("Enter your HugoBlox Pro license key (from your purchase confirmation email)",{initial:n??""})).trim();if(!t)throw new u("A HugoBlox Pro license key is required to continue. Check your purchase email or visit https://hugoblox.com/pro.");return t}var $r=fileURLToPath(import.meta.url),et=E.dirname($r);function Ir(){return et.endsWith("dist")?E.join(et,"lib","templates","minimal-theme.yaml"):E.resolve(et,"..","lib","templates","minimal-theme.yaml")}var Kt=Ir();function Hr(n){return /^[a-zA-Z0-9_-]+$/.test(n)}async function jr(){try{return await $.readFile(Kt,"utf8")}catch(n){throw new u(`Failed to load theme template: ${Kt}`,{error:n})}}function Rr(n,e,t,r){let o=n.split(`
|
|
71
71
|
`),i=[],s=false,c=0;for(let a of o){if(a.trim()==="meta:"){s=true,c=a.indexOf("meta:"),i.push(a),i.push(' format: "hugoblox-theme@1"'),i.push(` name: "${t}"`),i.push(` vendor: "${e}"`),i.push(' version: "0.0.1"'),i.push(' license: "MIT"'),i.push(' description: "Created via HugoBlox CLI"');continue}if(s){a.trim()&&!a.startsWith(" ".repeat(c+2))&&a.indexOf(":")>0&&(s=false,i.push(a));continue}i.push(a);}return i.join(`
|
|
72
|
-
`)}function
|
|
72
|
+
`)}function Yt(n,e){n.command("theme").description("Scaffold a new theme pack").argument("[name]","Theme slug/filename (will be converted to kebab-case)").option("--vendor <namespace>","Vendor namespace (e.g., GitHub username)").option("--theme-name <name>","Human-readable theme name (defaults to slug)").option("--git","Initialize a git repository").option("--ci","Run in non-interactive mode").action(async(t,r,o)=>{let{logger:i,telemetry:s}=e,c=!!o.optsWithGlobals().json;try{let a=r.vendor;if(!a){if(r.ci)throw new u("--vendor is required when running with --ci");a=await B("What is your GitHub username? (This will be your vendor namespace)");}if(a=a.trim(),!a)throw new u("Vendor namespace is required");if(!Hr(a))throw new u("Vendor namespace must contain only alphanumeric characters, hyphens, and underscores");let l=t;if(!l){if(r.ci)throw new u("Theme slug is required when running with --ci");l=await B("What do you want to name your theme? (e.g., cyberpunk-neon)",{initial:"my-theme"});}if(l=l.trim(),!l)throw new u("Theme slug is required");let m=z(l),p=r.themeName;p||(r.ci?p=l:p=await B("Human-readable theme name?",{initial:l})),p=p.trim()||l;let w=E.join(process.cwd(),"data","themes",a),d=E.join(w,`${m}.yaml`);if(await v(d)){if(r.ci)throw new u(`Theme file already exists: ${d}`);if(!await H(`Theme file ${m}.yaml already exists. Overwrite?`,{initial:!1})){i.info("Theme creation cancelled");return}}let g=Ge("Creating theme...").start();try{await _(w);let f=await jr(),b=Rr(f,a,p,m);await R(d,b),g.succeed("\u2705 Theme created successfully!");}catch(f){throw g.fail("Failed to create theme"),f}await s.track({name:"create-theme",payload:{vendor:a,themeFilename:m,ci:!!r.ci}});let h=E.relative(process.cwd(),d);if(c){i.json({status:"success",path:d,vendor:a,themeFilename:m,themeName:p});return}i.success(`
|
|
73
73
|
Theme created at: ${h}`),i.info(`
|
|
74
74
|
\u{1F4DD} To use this theme, update your params.yaml:`),i.info(`
|
|
75
|
-
hugoblox:`),i.info(" theme:"),i.info(` pack: "${a}/${m}"`),
|
|
75
|
+
hugoblox:`),i.info(" theme:"),i.info(` pack: "${a}/${m}"`),r.ci||await H(`
|
|
76
76
|
\u{1F30D} Would you like to share this theme with the community?`,{initial:!1})&&(i.info(`
|
|
77
77
|
\u2728 Great! Here's how to publish your theme:`),i.info(`
|
|
78
78
|
1\uFE0F\u20E3 Create a new GitHub repository`),i.info("2\uFE0F\u20E3 In your repo, create a folder structure: hugoblox/themes/"),i.info(`3\uFE0F\u20E3 Copy your theme file to: hugoblox/themes/${m}.yaml`),i.info("4\uFE0F\u20E3 Commit and push to GitHub"),i.info(`
|
|
79
79
|
\u{1F4E2} Once published, others can install it with:
|
|
80
80
|
hbx add theme --repo https://github.com/${a}/your-repo-name
|
|
81
|
-
`),i.info("\u{1F4A1} Tip: You can add multiple themes to the same repository!"));}catch(a){if(c){i.json({status:"error",message:a instanceof Error?a.message:String(a)});return}throw a}});}function
|
|
82
|
-
`),await
|
|
81
|
+
`),i.info("\u{1F4A1} Tip: You can add multiple themes to the same repository!"));}catch(a){if(c){i.json({status:"error",message:a instanceof Error?a.message:String(a)});return}throw a}});}function Qt(n,e){let t=n.command("create").description("Create resources (site, theme, block)");Jt(t,e),Yt(t,e),It(t,e);}function en(n,e){Br(n,e),Lr(n,e);}function Br(n,e){n.command("dev [hugoArgs...]").description("Start the Hugo development server (hugo server)").option("--path <dir>","Project directory (defaults to cwd)").option("--no-default-flags","Disable automatic --disableFastRender flag").action(async(t,r,o)=>{let{logger:i,telemetry:s}=e,a=!!o.optsWithGlobals().json,l=await tn(r.path),m=["server"];r.defaultFlags!==false&&m.push("--disableFastRender"),m.push(...t),await nn(m,l,i,{allowSignalExit:true,label:"dev server"}),await s.track({name:"dev",payload:{customPath:!!r.path,defaultFlags:r.defaultFlags!==false,args:t}}),a&&i.json({status:"success"});});}function Lr(n,e){n.command("build [hugoArgs...]").description("Run a production Hugo build (hugo --gc --minify)").option("--path <dir>","Project directory (defaults to cwd)").option("--no-default-flags","Disable automatic --gc/--minify flags").action(async(t,r,o)=>{let{logger:i,telemetry:s}=e,a=!!o.optsWithGlobals().json,l=await tn(r.path),m=[];r.defaultFlags!==false&&m.push("--gc","--minify"),m.push(...t),await nn(m,l,i,{allowSignalExit:false,label:"build"}),await s.track({name:"build",payload:{customPath:!!r.path,defaultFlags:r.defaultFlags!==false,args:t}}),a&&i.json({status:"success"});});}async function tn(n){let e=n?E.resolve(n):E.resolve(process.cwd()),t=await D(e);if(!t)throw new u("Unable to locate a HugoBlox project. Run this inside a project or pass --path.");return t.root}async function nn(n,e,t,r){t.info(`Running: hugo ${n.join(" ")}`);try{await execa("hugo",n,{cwd:e,stdio:"inherit"}),t.success(`Hugo ${r.label} finished`);}catch(o){let i=o;if(r.allowSignalExit&&(i.signal==="SIGINT"||i.signal==="SIGTERM")){t.info("Hugo process stopped");return}throw new u(`Hugo ${r.label} failed: ${i.shortMessage??i.message}`,{error:i})}}var Nr=["github.com/HugoBlox/kit/modules","github.com/HugoBlox/hugo-blox-builder","github.com/wowchemy/wowchemy-hugo-themes"],sn=[{from:"github.com/HugoBlox/hugo-blox-builder/modules/blox-tailwind",to:"github.com/HugoBlox/kit/modules/blox"},{from:"github.com/HugoBlox/hugo-blox-builder/modules/blox-analytics",to:"github.com/HugoBlox/kit/modules/analytics"},{from:"github.com/HugoBlox/hugo-blox-builder/modules/blox-plugin-netlify",to:"github.com/HugoBlox/kit/modules/integrations/netlify"},{from:"github.com/HugoBlox/hugo-blox-builder/modules/blox-plugin-reveal",to:"github.com/HugoBlox/kit/modules/slides"}],K="github.com/HugoBlox/hugo-blox-builder/",an="github.com/HugoBlox/kit/";async function De(n){let e=E.join(n,"go.mod"),t;try{t=await $.readFile(e,"utf8");}catch{return []}let o=Fr(t).map(s=>({...s,path:tt(s.path)})).filter(s=>Nr.some(c=>s.path.startsWith(c)));return await Promise.all(o.map(async s=>{try{let c=await Or(s.path);return {path:s.path,current:s.version,latest:c}}catch(c){return {path:s.path,current:s.version,latest:void 0,error:c.message}}}))}async function Or(n){let e=tt(n);if(e.includes("github.com/HugoBlox/kit/modules"))return rn(e,"HugoBlox/kit");if(e.includes("github.com/HugoBlox/hugo-blox-builder"))return rn(e,"HugoBlox/hugo-blox-builder")}async function rn(n,e){let t=await ie(`${re}/repos/${e}/tags?per_page=100`);if(!t.ok)throw new Error(`GitHub API error: ${t.status}`);let r=await t.json(),o=e==="HugoBlox/kit"?"github.com/HugoBlox/kit/":K,i=n.split(o);if(i.length<2)return;let s=i[1],c=r.filter(a=>a.name.startsWith(`${s}/`)&&/v\d+\.\d+\.\d+/.test(a.name)).map(a=>a.name);if(c.length!==0)return c.sort((a,l)=>{let m=a.split("/").pop()||"0.0.0",p=l.split("/").pop()||"0.0.0";return M.rcompare(m,p)}),c[0].split("/").pop()}async function cn(n,e){let t=tt(n),r="HugoBlox/hugo-blox-builder",o="";if(t.includes("github.com/HugoBlox/kit/")){r="HugoBlox/kit";let p=t.split("github.com/HugoBlox/kit/");if(p.length<2)return;o=p[1];}else if(t.includes(K)){let p=t.split(K);if(p.length<2)return;o=p[1];}else return;let i=e==="main"||e.startsWith("v")?e:`v${e}`,s=e==="main"?"main":`${o}/${i.replace(/^v/,"v")}`,c=`${o}/hugo.yaml`,a=await ie(`${re}/repos/${r}/contents/${c}?ref=${s}`,{headers:{Accept:"application/vnd.github.v3.raw"}});if(!a.ok)return;let l=await a.text();return rt.parse(l)?.module?.hugoVersion?.min}async function ln(n){let e=E.join(n,"go.mod"),t=[E.join(n,"config","_default","module.yaml"),E.join(n,"config","_default","modules.yaml"),E.join(n,"config","_default","module.toml"),E.join(n,"config","_default","modules.toml")];try{let r=await $.readFile(e,"utf8"),o=on(r);o!==r&&await $.writeFile(e,o,"utf8");}catch{}for(let r of t)try{let o=await $.readFile(r,"utf8"),i=on(o);i!==o&&await $.writeFile(r,i,"utf8");}catch{}}function tt(n){let e=sn.find(t=>t.from===n);return e?e.to:n.startsWith(K)?n.replace(K,an):n}function on(n){let e=n;for(let t of sn)e=e.replaceAll(t.from,t.to);return e.includes(K)&&(e=e.replaceAll(K,an)),e}function Fr(n){let e=[],t=n.split(/\r?\n/),r=false;for(let o of t){let i=o.trim();if(i.startsWith("require (")){r=true;continue}if(r&&i===")"){r=false;continue}let s="";if(!r&&i.startsWith("require ")?s=i.replace("require","").trim():r&&(s=i),s){s=s.split("//")[0].trim();let c=s.split(/\s+/);c.length>=2&&e.push({path:c[0],version:c[1]});}}return e}function Be(n,e){if(!n||!e)return {updateAvailable:false,diff:""};let t=M.coerce(n),r=M.coerce(e);return !t||!r?{updateAvailable:false,diff:""}:M.lt(t,r)?{updateAvailable:true,diff:`${le(n)} -> ${le(e)}`}:{updateAvailable:false,diff:""}}function le(n){let e=/v\d+\.\d+\.\d+-(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})-([a-f0-9]{12})/,t=n.match(e);if(t){let[r,o,i,s,c,a,l,m]=t;return `commit ${m.substring(0,7)} (released ${o}-${i}-${s})`}return n}function dn(n){let e=process.env.HOME||process.env.USERPROFILE;if(!e)return n;let t=E.resolve(e),r=E.resolve(n);return r.startsWith(t)?r.replace(t,"~"):n}async function nt(n,e){try{let t=await execa(n,e,{reject:!1});return t.exitCode===0?t.stdout.trim():`Failed (${t.stderr.trim()})`}catch(t){return `Not available (${t.message})`}}function un(n,e){n.command("doctor").description("Check local environment for common issues").action(async(t,r)=>{let{logger:o,config:i}=e,c=!!r.optsWithGlobals().json,a=[];a.push({name:"Node.js",ok:true,details:process.version});let l=await nt("git",["--version"]);a.push({name:"Git",ok:!l.startsWith("Not"),details:l});let m=await nt("hugo",["version"]);a.push({name:"Hugo",ok:!m.startsWith("Not"),details:m});let p=Vr(m),w=await nt("pnpm",["--version"]);a.push({name:"pnpm",ok:!w.startsWith("Not"),details:w});let d=i.getLicense();a.push({name:"Pro license",ok:!!d,details:d?"Configured":"Missing"});let g=await D();if(g){let b=await Ct(g.root);if(b){let x=b.templateName??b.templateId??"Unknown";a.push({name:"Template",ok:true,details:`${x} (${dn(g.root)})`});let C=Wr(b.requiredHugoVersion,p);C&&a.push(C);}let P=await De(g.root);for(let x of P){let C=x.path.split("/").pop()||x.path,j=x.current;if(x.latest){let k=M.coerce(x.current),T=M.coerce(x.latest);k&&T&&M.eq(k,T)&&(j=`${j} (latest)`);}a.push({name:`Module: ${C}`,ok:true,details:j});let{updateAvailable:S}=Be(x.current,x.latest);S&&x.latest&&a.push({name:`${C} update`,ok:false,details:`Current ${x.current}, latest ${x.latest}. Run 'hbx upgrade' to update.`,level:"warn"});}}let f={status:a.some(b=>(b.level??(b.ok?"info":"error"))==="error")?"error":"success",checks:a};if(c){o.json(f);return}for(let b of f.checks){let P=b.level??(b.ok?"info":"error");P==="info"?o.success(`${b.name}: ${b.details}`):P==="warn"?o.warn(`${b.name}: ${b.details}`):o.error(`${b.name}: ${b.details}`);}});}function Vr(n){let e=n.match(/v(\d+\.\d+\.\d+)/i);return e?e[1]:n.match(/(\d+\.\d+\.\d+)/)?.[1]}function Wr(n,e){if(!n||!e)return;let t=M.coerce(n),r=M.coerce(e);if(!(!t||!r))return M.lt(r,t)?{name:"Hugo version compatibility",ok:false,details:`Template requires Hugo ${t.version}, but ${r.version} is installed`,level:"error"}:M.major(r)>M.major(t)||M.minor(r)>M.minor(t)?{name:"Hugo version compatibility",ok:true,details:`Using Hugo ${r.version}; template tested with ${t.version}`,level:"warn"}:{name:"Hugo version compatibility",ok:true,details:`Template requires Hugo ${t.version} and you're running ${r.version}`,level:"info"}}function pn(n,e){n.command("install").description("Hydrate HugoBlox Pro assets").option("--ci","Fail when prompts would appear").option("--force","Force re-download of assets").option("--path <dir>","Project directory (defaults to cwd)").action(async(t,r)=>{let{logger:o,config:i,telemetry:s}=e,a=!!r.optsWithGlobals().json,l=t.path?{root:E.resolve(t.path),manifestPath:E.join(E.resolve(t.path),"hbx.blocks.json")}:await D();if(!l)throw new u("Unable to locate a HugoBlox project - pass --path if needed");let m=i.getLicense();if(!m){if(t.ci)throw new u(`Missing license key. Set ${te} or run hbx login before using --ci.`);o.warn("No Pro license detected, proceeding with OSS assets only");}let p=Ge("Hydrating Pro assets...").start();try{let d=E.join(l.root,"config","_default","module.hbx.toml"),g=E.join(l.root,"node_modules","@hugoblox-pro","sample");await _(g),await R(E.join(g,"README.md"),`# HugoBlox Pro assets placeholder
|
|
82
|
+
`),await R(d,`# Generated by hbx install
|
|
83
83
|
[[module.imports]]
|
|
84
84
|
path = "github.com/HugoBlox/hugo-blox-builder"
|
|
85
85
|
[[module.imports]]
|
|
86
86
|
path = "node_modules/@hugoblox-pro/sample"
|
|
87
|
-
`),
|
|
87
|
+
`),p.succeed("Assets hydrated");}catch(d){throw p.fail("Failed to hydrate assets"),d}await s.track({name:"install",payload:{ci:!!t.ci,force:!!t.force,tokenPresent:!!m,customPath:!!t.path}});let w={status:"success",path:l.root,forced:!!t.force,token:!!m};a?o.json(w):(o.success("Install complete"),m||o.info("Tip: run hbx login to unlock Pro downloads"));});}function fn(n,e){n.command("login").description("Authenticate with HugoBlox Pro and register this device for template access").option("--token <value>","License key").option("--ci","Fail when license key is missing").action(async(t,r)=>{let{config:o,logger:i}=e,c=!!r.optsWithGlobals().json,a=t.token;if(!a){if(t.ci)throw new u("License key is required when using --ci");a=await B("Enter your HugoBlox Pro license key");}let l=false;try{o.setLicense(a),await o.save(),l=!0,await L(e,{force:!0});let m={status:"success",token:Qe(a)};c?i.json(m):i.success(`License key saved (${Qe(a)})`);}catch(m){throw l&&(o.clearLicense(),await o.save()),Gr(m)}});}function gn(n,e){n.command("logout").description("Remove stored HugoBlox credentials and device secrets").action(async(t,r)=>{let{config:o,logger:i}=e,s=!!r.optsWithGlobals().json;await Dt(o),o.clearLicense(),await o.save();let c={status:"success"};s?i.json(c):i.success("License key removed");});}function Gr(n){let e=n instanceof Error?n.message:"Device registration failed",t="HBX must register this machine before downloading Pro templates. Check your internet connection, ensure your license has a free device slot, or revoke an old device and rerun 'hbx login'.";return n instanceof N?new u(`${e}. ${t}`,n.details):new u(`${e}. ${t}`)}function de(n){let e=n.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!e)return {frontMatter:{},body:n};try{let t=rt.parse(e[1]);return typeof t!="object"||t===null||Array.isArray(t)?{frontMatter:{},body:n}:{frontMatter:t,body:e[2]??""}}catch{return {frontMatter:{},body:n}}}async function*ue(n){let e;try{e=await $.readdir(n,{withFileTypes:!0});}catch{return}for(let t of e){let r=E.join(n,t.name);if(t.isDirectory()){try{if((await $.lstat(r)).isSymbolicLink())continue}catch{continue}yield*ue(r);}else t.name.endsWith(".md")&&(yield r);}}function wn(n,e){n.command("v0.11.0-authors").description("Migrate author profiles from content/authors/ to data/authors/ (v0.11.0+)").option("-y, --yes","Skip confirmation prompts").option("--dry-run","Preview changes without modifying files").action(async t=>{let{logger:r}=e,o=await D();if(!o)throw new u("No Hugo project found in the current directory.");let i=Ge("Analyzing author profiles...").start();try{let s=E.join(o.root,"content","authors");if(!await v(s)){i.stop(),r.info("\u2139\uFE0F No authors directory found. Nothing to migrate.");return}let c=await bn(s);if(c.length===0){i.stop(),r.info("\u2139\uFE0F No author profiles found to migrate.");return}i.stop(),r.info(`
|
|
88
88
|
\u{1F4CB} Migration Plan (v0.11.0 Author System):
|
|
89
|
-
`),
|
|
90
|
-
Changes:`),
|
|
91
|
-
\u{1F50D} Dry run mode - no files will be modified.`);return}if(!
|
|
92
|
-
This will restructure your author data. We recommend backing up first. Continue?`,{initial:!1})){
|
|
93
|
-
\u{1F4DA} Next steps:`),
|
|
94
|
-
Original files preserved in content/authors/`);}}catch(
|
|
95
|
-
Please remove or back them up manually before running migration.`)}await
|
|
96
|
-
Please rename them to use lowercase letters, numbers, or hyphens.`);if(
|
|
97
|
-
Please manually rename one of the conflicting profiles before migration.`);for(let
|
|
98
|
-
${
|
|
89
|
+
`),r.info(` Found ${c.length} author profile(s):`);for(let l of c){let m=l.slug==="admin"?"me":l.slug;r.info(` \u2022 ${l.slug} \u2192 data/authors/${m}.yaml`),l.avatarPath&&r.info(` Avatar: ${E.basename(l.avatarPath)} \u2192 assets/media/authors/${m}${E.extname(l.avatarPath)}`);}if(r.info(`
|
|
90
|
+
Changes:`),r.info(" \u2713 Create data/authors/ directory"),r.info(" \u2713 Generate YAML files with new schema (hugoblox/author/v1)"),r.info(" \u2713 Migrate avatar images to assets/media/authors/"),r.info(" \u2713 Update author references in content files"),r.info(" \u2713 Archive original content/authors/ directory"),t.dryRun){r.info(`
|
|
91
|
+
\u{1F50D} Dry run mode - no files will be modified.`);return}if(!t.yes&&!await H(`
|
|
92
|
+
This will restructure your author data. We recommend backing up first. Continue?`,{initial:!1})){r.info("Migration cancelled.");return}let a=await mo(o.root,c,r);if(r.info(""),a.success)r.success("\u2705 Migration complete!"),r.info(` \u2022 Migrated ${a.authorsMigrated} author profile(s)`),r.info(` \u2022 Updated ${a.contentFilesMigrated} content file(s)`),r.info(`
|
|
93
|
+
\u{1F4DA} Next steps:`),r.info(" 1. Review generated files in data/authors/"),r.info(" 2. Test your site: pnpm dev"),r.info(" 3. Remove backup: rm -rf content/authors.backup");else {r.error("\u274C Migration completed with errors:");for(let l of a.errors)r.error(` \u2022 ${l}`);r.info(`
|
|
94
|
+
Original files preserved in content/authors/`);}}catch(s){throw i.stop(),s}});}async function bn(n){let e=[],t=await $.readdir(n,{withFileTypes:true});for(let o of t){if(!o.isDirectory()||o.name.startsWith("_"))continue;let i=E.join(n,o.name),s=E.join(i,"_index.md");if(!await v(s))continue;let c=ot(o.name);if(c)try{let a=await $.readFile(s,"utf8"),{frontMatter:l,body:m}=de(a),p,d=(await $.readdir(i)).find(g=>/^avatar\.(png|jpg|jpeg|webp)$/i.test(g));d&&(p=E.join(i,d)),e.push({slug:o.name,targetSlug:c,originalPath:i,frontMatter:l,content:m.trim(),avatarPath:p});}catch{}}let r=E.join(n,"_index.md");if(await v(r))try{let o=await $.readFile(r,"utf8"),{frontMatter:i,body:s}=de(o);if(Jr(i,s)){let c=y(i.slug)??"admin",a=c?ot(c):void 0;if(a&&!e.some(l=>l.targetSlug===a)){let l,p=(await $.readdir(n)).find(w=>/^avatar\.(png|jpg|jpeg|webp)$/i.test(w));p&&(l=E.join(n,p)),e.push({slug:c,targetSlug:a,originalPath:n,frontMatter:i,content:s.trim(),avatarPath:l});}}}catch{}return e}function Jr(n,e){return e.trim()?true:["title","name","first_name","last_name","bio","profiles","organizations","affiliations","interests","education","work","skills","languages","role","status","pronouns","name_pronunciation"].some(r=>n[r]!==void 0)}function ot(n){let e=z(n);if(e)return e==="admin"?"me":e}function y(n){if(typeof n!="string")return;let e=n.trim();return e===""?void 0:e}function be(n){return typeof n=="number"&&Number.isFinite(n)?n:y(n)}function Kr(n){return Array.isArray(n)?n.map(e=>y(e)).filter(e=>!!e):[]}function Yr(n){let e={},t=y(n.title??n.name);t&&(e.display=t);let r=y(n.first_name??n.given_name??n.given);r&&(e.given=r);let o=y(n.last_name??n.family_name??n.family);o&&(e.family=o);let i=y(n.middle_name??n.middle);i&&(e.middle=i);let s=y(n.nickname??n.alternate_name??n.alt_name);s&&(e.alternate=s);let c=y(n.name_pronunciation??n.pronunciation);c&&(e.pronunciation=c);let a=y(n.pronouns);return a&&(e.pronouns=a),e}function Qr(n){if(n.status&&typeof n.status=="object"&&!Array.isArray(n.status)){let t=y(n.status.icon);if(t)return {icon:t}}let e=y(n.status_icon??n.status_emoji??n.status);if(e)return {icon:e}}function Zr(n){return Array.isArray(n)?n.map(e=>{if(typeof e!="object"||e===null)return;let t=e,r=y(t.name);if(!r)return;let o=y(t.url);return o?{name:r,url:o}:{name:r}}).filter(e=>!!e):[]}function eo(n){let e={},t=["orcid","google_scholar","openalex","semantic_scholar","research_gate","scopus","arxiv"];for(let i of t){let s=y(n[i]);s&&(e[i]=s);}let r=[];Array.isArray(n.profiles)&&r.push(...n.profiles);let o=n.links;Array.isArray(o)&&r.push(...o);for(let i of r){if(typeof i!="object"||i===null)continue;let s=y(i.url);s&&to(s,e);}return Object.keys(e).length===0?void 0:e}function to(n,e){if(/^https?:\/\//i.test(n))try{let t=new URL(n),r=t.hostname.toLowerCase(),o=t.pathname.split("/").filter(Boolean);if(r.includes("scholar.google.")){let i=t.searchParams.get("user");i&&!e.google_scholar&&(e.google_scholar=i);return}if(r.includes("orcid.org")){let i=t.pathname.match(/(\d{4}-\d{4}-\d{4}-\d{3}[0-9X])/i);i&&!e.orcid&&(e.orcid=i[1]);return}if(r.includes("openalex.org")){let i=o[o.length-1];i&&!e.openalex&&(e.openalex=i);return}if(r.includes("semanticscholar.org")){let i=o[o.length-1];i&&!e.semantic_scholar&&(e.semantic_scholar=i);return}if(r.includes("researchgate.net")){let i=o[o.length-1];i&&!e.research_gate&&(e.research_gate=i);return}if(r.includes("scopus.com")){let i=t.searchParams.get("authorId")??t.searchParams.get("scopusId")??o[o.length-1];i&&!e.scopus&&(e.scopus=i);return}if(r.includes("arxiv.org")){let i=o[o.length-1];i&&!e.arxiv&&(e.arxiv=i);}}catch{}}function no(n,e,t){let r=[];if(Array.isArray(n))for(let s of n){if(typeof s!="object"||s===null)continue;let c=s,a=y(c.icon),l=y(c.url),m=y(c.label);if(a&&l){let p={icon:a,url:l};m&&(p.label=m),r.push(p);}}let o=y(t);if(o){let s=o.startsWith("mailto:")?o:`mailto:${o}`;r.some(c=>c.url===s)||r.push({icon:"at-symbol",url:s,label:"Email"});}let i=y(e);return i&&!r.some(s=>s.url===i)&&r.push({icon:"link",url:i,label:"Website"}),r}function ro(n){if(typeof n=="string"){let e=n.trim();return e||void 0}if(Array.isArray(n)){let e=n.map(t=>y(t)).filter(t=>!!t);if(e.length>0)return e}}function oo(n){return Array.isArray(n)?n.map(e=>{if(typeof e!="object"||e===null)return;let t=e,r=y(t.institution??t.organization??t.school);if(!r)return;let o={institution:r},i=y(t.degree??t.area??t.qualification);i&&(o.degree=i);let s=be(t.year);s!==void 0&&(o.year=s);let c=be(t.start??t.date_start);c!==void 0&&(o.start=c);let a=be(t.end??t.date_end);a!==void 0&&(o.end=a);let l=y(t.summary);l&&(o.summary=l);let m=vn(t.button);return m&&(o.button=m),o}).filter(e=>!!e):[]}function io(n){return Array.isArray(n)?n.map(e=>{if(typeof e!="object"||e===null)return;let t=e,r=y(t.role??t.position),o=y(t.org??t.company_name??t.company);if(!r||!o)return;let i={role:r,org:o},s=be(t.start??t.date_start);s!==void 0&&(i.start=s);let c=be(t.end??t.date_end);c!==void 0&&(i.end=c);let a=y(t.summary);a&&(i.summary=a);let l=vn(t.button);return l&&(i.button=l),i}).filter(e=>!!e):[]}function vn(n){if(typeof n!="object"||n===null)return;let e=n,t=y(e.url);if(!t)return;let r={url:t},o=y(e.text);o&&(r.text=o);let i=y(e.icon);return i&&(r.icon=i),r}function so(n){return Array.isArray(n)?n.map(e=>{if(typeof e!="object"||e===null)return;let t=e,o=(Array.isArray(t.items)?t.items:[]).map(c=>{if(typeof c!="object"||c===null)return;let a=c,l=y(a.label??a.name);if(!l)return;let m={label:l},p=xn(a.level)??it(typeof a.percent=="number"?a.percent:void 0);p!==void 0&&(m.level=p);let w=y(a.icon);return w&&(m.icon=w),m}).filter(c=>!!c);if(o.length===0)return;let i={items:o},s=y(t.name);return s&&(i.name=s),i}).filter(e=>!!e):[]}function it(n){if(typeof n!="number"||Number.isNaN(n)||n<=0)return;let e=Math.min(100,n);return Math.max(1,Math.min(5,Math.ceil(e/20)))}function xn(n){if(!(typeof n!="number"||Number.isNaN(n)))return n>=1&&n<=5?Math.round(n):it(n)}function ao(n){return Array.isArray(n)?n.map(e=>{if(typeof e=="string"){let a=y(e);return a?{name:a}:void 0}if(typeof e!="object"||e===null)return;let t=e,r=y(t.name??t.label);if(!r)return;let o=typeof t.percent=="number"?Math.max(0,Math.min(100,t.percent)):void 0,i=xn(t.level)??it(o),s={name:r};i!==void 0&&(s.level=i),o!==void 0&&(s.percent=o);let c=y(t.label)??co(o,i);return c&&(s.label=c),s}).filter(e=>!!e):[]}function co(n,e){let t=n??(typeof e=="number"?e*20:void 0);if(t!==void 0){if(t>=99)return "Native";if(t>=90)return "C2";if(t>=75)return "C1";if(t>=60)return "B2";if(t>=45)return "B1";if(t>=30)return "A2"}}function lo(n){return Array.isArray(n)?n.map(e=>{if(typeof e=="string"){let l=y(e);return l?{title:l}:void 0}if(typeof e!="object"||e===null)return;let t=e,r=y(t.title);if(!r)return;let o={title:r},i=y(t.awarder);i&&(o.awarder=i);let s=y(t.date);s&&(o.date=s);let c=y(t.summary);c&&(o.summary=c);let a=y(t.icon);return a&&(o.icon=a),o}).filter(e=>!!e):[]}function Cn(n,e){let{frontMatter:t,content:r}=n,o={schema:"hugoblox/author/v1",slug:e},i=Yr(t);Object.keys(i).length>0&&(o.name=i),t.superuser===true&&(o.is_owner=true);let s=Qr(t);s&&(o.status=s);let c=y(t.role);c&&(o.role=c);let a=y(t.bio)??r.trim();a&&(o.bio=a);let l=Zr(t.organizations??t.affiliations);l.length>0&&(o.affiliations=l);let m=eo(t);m&&(o.ids=m);let p=[];Array.isArray(t.profiles)&&p.push(...t.profiles);let w=t.links;Array.isArray(w)&&p.push(...w);let d=no(p,t.website,t.email);d.length>0&&(o.links=d);let g=Kr(t.interests);g.length>0&&(o.interests=g);let h=ro(t.postnominals??t.credentials);h&&(o.postnominals=h);let f=oo(t.education);f.length>0&&(o.education=f);let b=io(t.work??t.experience);b.length>0&&(o.experience=b);let P=so(t.skills);P.length>0&&(o.skills=P);let x=ao(t.languages);x.length>0&&(o.languages=x);let C=lo(t.awards);return C.length>0&&(o.awards=C),typeof t.weight=="number"&&Number.isFinite(t.weight)&&(o.weight=Math.trunc(t.weight)),o}async function Pn(n,e,t){let r=E.extname(n)||".png",o=E.join(e,`${t}${r}`);return await $.copyFile(n,o),o}async function mo(n,e,t){let r={success:true,authorsMigrated:0,contentFilesMigrated:0,errors:[]},o=Ge("Creating backup...").start(),i=E.join(n,"content","authors"),s=E.join(n,"content","authors.backup");try{if(await v(s)){let g=new Date().toISOString().replace(/[:.]/g,"-").split(".")[0],h=`${s}.${g}`;o.text=`Existing backup found, creating timestamped backup: ${E.basename(h)}`,await $.cp(i,h,{recursive:!0}),t.info(` Previous backup preserved as: ${E.basename(h)}`);}else await $.cp(i,s,{recursive:!0});o.text="Backup created, migrating author profiles...";let c=E.join(n,"data","authors"),a=E.join(n,"assets","media","authors");if(await v(c)){let h=(await $.readdir(c)).filter(f=>f.endsWith(".yaml")||f.endsWith(".yml"));if(h.length>0)throw o.stop(),new u(`data/authors/ already contains ${h.length} YAML file(s).
|
|
95
|
+
Please remove or back them up manually before running migration.`)}await _(c),await _(a);let l=new Map,m=new Set,p=[],w=[];for(let g of e){let h=g.targetSlug??ot(g.slug);if(!h){w.push(g.slug);continue}m.has(h)&&p.push(h),m.add(h);let f=new Set([g.slug]),b=g.slug.toLowerCase();b!==g.slug&&f.add(b);let P=z(g.slug);P&&P!==g.slug&&f.add(P);for(let x of f)l.has(x)||l.set(x,h);}if(w.length>0)throw o.stop(),new u(`Unable to normalize the following author slug(s): ${w.join(", ")}
|
|
96
|
+
Please rename them to use lowercase letters, numbers, or hyphens.`);if(p.length>0)throw o.stop(),new u(`Slug collision detected: Multiple profiles would map to: ${p.join(", ")}
|
|
97
|
+
Please manually rename one of the conflicting profiles before migration.`);for(let g=0;g<e.length;g++){let h=e[g];o.text=`Migrating profiles... (${g+1}/${e.length})`;try{let f=l.get(h.slug);if(!f)throw new u(`Unable to determine target slug for '${h.slug}'`);let b=Cn(h,f),P=E.join(c,`${f}.yaml`),x=rt.stringify(b,{defaultStringType:"QUOTE_DOUBLE",lineWidth:0});try{let C=rt.parse(x);if(!C.schema||!C.slug)throw new Error("Generated YAML missing required fields")}catch(C){throw new Error(`Invalid YAML generated: ${String(C)}`)}if(await $.writeFile(P,x,"utf8"),h.avatarPath)try{await Pn(h.avatarPath,a,f);}catch(C){r.errors.push(`\u2713 Profile '${h.slug}' migrated, but avatar copy failed: ${String(C)}`);}r.authorsMigrated++;}catch(f){r.errors.push(`Failed to migrate ${h.slug}: ${String(f)}`),r.success=!1;}}o.text="Updating content references...";let d=E.join(n,"content");if(await v(d)){let g=await Sn(d,l);r.contentFilesMigrated=g;}o.text="Finalizing migration...",await $.rm(i,{recursive:!0,force:!0}),o.succeed("Migration complete");}catch(c){o.fail("Migration failed"),r.success=false,r.errors.push(String(c));try{t.warn("\u26A0\uFE0F Attempting to rollback changes..."),!await v(i)&&await v(s)&&(await $.cp(s,i,{recursive:!0}),t.info(" \u2713 Original authors directory restored from backup"));let a=E.join(n,"data","authors");await v(a)&&(await $.readdir(a)).filter(w=>w.endsWith(".yaml")).length===r.authorsMigrated&&(await $.rm(a,{recursive:!0,force:!0}),t.info(" \u2713 Partial data/authors/ files removed"));let l=E.join(n,"assets","media","authors");await v(l)&&(await $.readdir(l)).length<=r.authorsMigrated&&(await $.rm(l,{recursive:!0,force:!0}),t.info(" \u2713 Partial avatar files removed")),t.info("\u2713 Rollback complete. Your original files are safe.");}catch(a){r.errors.push(`Rollback failed: ${String(a)}`),t.error("\u274C Rollback failed. Please manually check:"),t.error(" - content/authors.backup/ contains your original files"),t.error(" - You may need to manually restore them");}}return r}async function Sn(n,e){let t=0;for await(let r of ue(n))try{let o=await $.readFile(r,"utf8"),{frontMatter:i,body:s}=de(o),c=!1;if(Array.isArray(i.authors)){let a=i.authors.map(l=>{if(typeof l=="string"){let m=l.trim(),p=m.toLowerCase(),w=e.get(m)??e.get(l)??e.get(p);if(w)return c=!0,w}return l});i.authors=a;}if(c){let a=`---
|
|
98
|
+
${rt.stringify(i)}---
|
|
99
99
|
|
|
100
|
-
${s}`;await
|
|
101
|
-
|
|
102
|
-
`)
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
${s}`;await $.writeFile(r,a,"utf8"),t++;}}catch{}return t}function kn(n,e){n.command("v0.11.0-events").description("Migrate legacy events content to HugoBlox v0.11.0 conventions").option("-y, --yes","Skip confirmation prompts").option("--dry-run","Preview changes without modifying files").action(async t=>{let{logger:r}=e,o=await D();if(!o)throw new u("No Hugo project found in the current directory.");let i=Ge("Analyzing event content...").start();try{let s=E.join(o.root,"content","event"),c=E.join(o.root,"content","events"),a=await v(s),l=await v(c),m;if(l?m=c:a&&(m=s),!m){i.stop(),r.info("\u2139\uFE0F No legacy event content found under content/event/ or content/events/.");return}let p=await go(m),w=a&&!l;if(i.stop(),r.info(`
|
|
101
|
+
\u{1F4CB} Migration Plan (v0.11.0 Events):
|
|
102
|
+
`),w?r.info(" \u2713 Rename content/event/ \u2192 content/events/"):a&&l?r.info(" \u2713 content/events/ already exists (no rename needed)"):a?r.info(" \u2713 Legacy content/event/ directory detected (will be renamed)."):r.info(" \u2713 No legacy directory rename required"),r.info(` \u2713 Update front matter for ${p} event file(s)`),p===0&&!w){r.info(`
|
|
103
|
+
\u2139\uFE0F No event markdown files were found to migrate.`);return}if(t.dryRun){r.info(`
|
|
104
|
+
\u{1F50D} Dry run mode - no files will be modified.`);return}if(!t.yes&&!await H(`
|
|
105
|
+
This will rename event directories (if needed) and adjust front matter. Continue?`,{initial:!1})){r.info("Migration cancelled.");return}if(w){let f=Ge("Renaming content/event/ to content/events/...").start();await $.rename(s,c),f.succeed("Renamed legacy event directory.");}let d=await v(c)?c:m;if(!d)throw new u("No event directory found to migrate after analysis.");let g=Ge("Updating event front matter...").start(),h=await po(d);if(g.stop(),r.info(""),h.errors.length>0){r.error("\u274C Front matter migration completed with errors:");for(let f of h.errors)r.error(` \u2022 ${E.relative(o.root,f.file)}: ${f.message}`);throw new u("Event front matter migration encountered errors. Please resolve them and rerun the command.")}r.success("\u2705 Event migration complete!"),r.info(` \u2022 Processed ${h.processed} file(s)`),r.info(` \u2022 Updated ${h.updated} file(s)`);}catch(s){throw i.fail("Event migration failed"),s instanceof u?s:new u(`Event migration failed: ${String(s)}`)}});}async function po(n){let e={processed:0,updated:0,errors:[]};for await(let t of ue(n))try{let r=await $.readFile(t,"utf8"),{frontMatter:o,body:i}=de(r),{migrated:s,changed:c}=fo(o);if(!c){e.processed+=1;continue}let l=`---
|
|
106
|
+
${rt.stringify(s,{lineWidth:0})}---
|
|
107
|
+
|
|
108
|
+
${i}`;await $.writeFile(t,l,"utf8"),e.processed+=1,e.updated+=1;}catch(r){e.errors.push({file:t,message:String(r)}),e.processed+=1;}return e}function fo(n){let e={...n},t=false,r=(i,s)=>{e[i]===void 0&&n[s]!==void 0&&(e[i]=n[s],t=true);};r("event_start","date"),r("event_end","date_end"),r("event_all_day","all_day"),r("event_name","event"),n.publishDate!==void 0&&e.date!==n.publishDate?(e.date=n.publishDate,t=true):n.publishDate===void 0&&n.date!==void 0&&e.date!==n.date&&(e.date=n.date,t=true);let o=i=>{i in e&&(delete e[i],t=true);};return o("publishDate"),o("date_end"),o("all_day"),o("event"),{migrated:e,changed:t}}async function go(n){let e=0;for await(let t of ue(n))e+=1;return e}function En(n,e){let t=n.command("migrate").description("Migrate HugoBlox project to newer versions");wn(t,e),kn(t,e);}function Tn(n,e){let t=n.command("telemetry").description("Manage HugoBlox telemetry preferences");t.command("enable").description("Enable anonymous telemetry").action(async()=>{e.config.setTelemetryEnabled(true),await e.config.save(),e.logger.success("Telemetry enabled. Thanks for helping improve HugoBlox!");}),t.command("disable").description("Disable telemetry collection").action(async()=>{e.config.setTelemetryEnabled(false),await e.config.save(),e.logger.success("Telemetry disabled. You can re-enable it anytime.");}),t.command("status").description("Show whether telemetry is enabled").action(()=>{let r=e.config.isTelemetryEnabled();e.logger.info(`Telemetry is ${r?"enabled":"disabled"}.`);}),t.action(()=>{let r=e.config.isTelemetryEnabled();e.logger.info(`Telemetry is ${r?"enabled":"disabled"}.`),e.logger.info("Use 'hbx telemetry enable|disable' to change the setting.");});}async function _n(n,e,t){let r=M.coerce(e)?.version;if(!r)return;let o=[{path:"hugoblox.yaml",regex:/(hugo_version:\s*['"]?)([\d.]+)(['"]?)/,name:"hugoblox.yaml"},{path:"netlify.toml",regex:/(HUGO_VERSION\s*=\s*['"])([\d.]+)(['"])/,name:"netlify.toml"},{path:".github/workflows/deploy.yml",regex:/(WC_HUGO_VERSION:\s*['"]?)([\d.]+)(['"]?)/,name:"GitHub Actions"}];for(let i of o){let s=E.join(n,i.path);if(await v(s))try{let c=await $.readFile(s,"utf8"),a=c.match(i.regex);if(a){let l=a[2],m=M.coerce(l),p=M.coerce(r);if(m&&p&&M.lt(m,p)){let w=c.replace(i.regex,`$1${r}$3`);await $.writeFile(s,w,"utf8"),t.success(`Updated ${i.name} Hugo version to ${r}`);}}}catch{}}}function Hn(n,e){n.command("upgrade").alias("update").description("Upgrade HugoBlox modules to the latest version").option("-y, --yes","Skip confirmation").option("--ci","Run in non-interactive mode").option("--force","Force upgrade even if Hugo version is incompatible").option("--canary","Upgrade to the latest development commit (main branch) instead of stable release").action(async(t,r)=>{let{logger:o}=e;await kt()||(o.error("\u274C You appear to be offline. Please check your internet connection."),process.exit(1));let i=await D();if(!i)throw new u("No Hugo project found in the current directory.");await ln(i.root);let s=Ge("Checking for updates...").start(),c=await De(i.root);if(c.length===0){s.stop(),o.info("\u2139\uFE0F No official HugoBlox modules found in go.mod");return}let a=c.filter(d=>d.error);if(a.length>0){s.stop(),o.error("\u274C Failed to check for updates for some modules:");for(let d of a)o.error(` ${d.path}: ${d.error}`);process.exit(1);}let l=[];if(t.canary)s.text="Checking canary versions...",l.push(...c.map(d=>({path:d.path,version:"main"})));else {let d=c.map(g=>{let{updateAvailable:h,diff:f}=Be(g.current,g.latest);return {...g,updateAvailable:h,diff:f}}).filter(g=>g.updateAvailable&&g.latest);if(d.length===0){s.stop(),o.success("\u2705 All HugoBlox modules are up to date");return}l.push(...d.map(g=>({path:g.path,version:g.latest||""})));}s.text="Checking version requirements...";let m=await Promise.all(l.map(async d=>{try{let g=await cn(d.path,d.version);return {...d,min:g}}catch{return {...d,min:void 0}}}));if(s.stop(),!t.force){let d=await Pt();if(d){let g=m.filter(h=>{if(!h.min)return false;let f=M.coerce(h.min),b=M.coerce(d);return f&&b&&M.lt(b,f)});if(g.length>0){o.error("\u274C Hugo version incompatible with upgrade targets:");for(let h of g)o.error(` ${h.path.split("/").pop()} requires Hugo >= ${h.min} (you have ${d})`);o.info("\u{1F449} Please upgrade Hugo first: https://docs.hugoblox.com/start/cli"),o.info(" Or run with --force to ignore this check."),process.exit(1);}}else o.warn("\u26A0\uFE0F Could not detect local Hugo version. Skipping compatibility check.");}if(t.canary){o.warn("\u26A0\uFE0F Upgrading modules to latest canary (development) version.");for(let d of c)o.info(` ${d.path.split("/").pop()}: ${le(d.current)} -> @main`);}else {o.info(`\u{1F4E6} Updates available for ${l.length} module(s):`);for(let d of l){let g=c.find(h=>h.path===d.path)?.current||"?";o.info(` ${d.path.split("/").pop()}`),o.info(` Current: ${le(g)}`),o.info(` Latest: ${le(d.version)}`);}}if(!t.yes&&!t.ci&&!await H(t.canary?"Are you sure you want to upgrade to the bleeding edge?":"Do you want to upgrade now?",{initial:true})){o.info("Upgrade cancelled");return}let p=l.map(d=>`${d.path}@${d.version}`);await yo(i.root,p,o);let w=m.reduce((d,g)=>{if(!g.min)return d;let h=M.coerce(g.min),f=M.coerce(d);return h&&(!f||M.gt(h,f))?g.min:d},void 0);w&&await _n(i.root,w,o),o.info(""),o.warn("\u26A0\uFE0F Important: Please review the release notes for any breaking changes."),o.info("\u{1F449} https://github.com/HugoBlox/hugo-blox-builder/releases");});}async function yo(n,e,t){let r=Ge("Upgrading modules...").start();try{await execa("hugo",["mod","get",...e],{cwd:n}),r.text="Tidying go.mod...",await execa("hugo",["mod","tidy"],{cwd:n}),r.succeed(`\u2705 Upgraded ${e.length} module(s)`);}catch(o){r.fail("Failed to upgrade modules"),t.error(String(o)),process.exit(1);}}var Y;function Q(){if(Y)return Y;let n=process.env.HBX_CLI_VERSION??process.env.npm_package_version;if(n)return Y=n,Y;let e=bo(import.meta.url);try{let t=F.readFileSync(e,"utf8");Y=JSON.parse(t).version??"0.0.0";}catch{Y="0.0.0";}return Y}function bo(n){let e=E.dirname(fileURLToPath(n)),t=E.resolve(e,"../package.json");return F.existsSync(t)?t:E.resolve(e,"../../package.json")}function Rn(n,e){n.command("version").description("Print CLI version").action((t,r)=>{let{logger:o}=e,i=!!r.optsWithGlobals().json,s=Q(),c={status:"success",version:s};i?o.json(c):o.info(`hbx ${s}`);});}var fe=class n{#e;constructor(e){this.#e=e;}static async load(){try{let e=await $.readFile(Ee,"utf8"),t=JSON.parse(e);return new n(t)}catch(e){if(e.code==="ENOENT")return new n({});throw new xe("Failed to read configuration",{error:e})}}toJSON(){return this.#e}getLicense(){return process.env[te]??this.#e.token}setLicense(e){this.#e={...this.#e,token:e};}clearLicense(){let e={...this.#e};e.token=void 0,e.device=void 0,this.#e=e;}isTelemetryEnabled(){return process.env[ft]==="1"?false:typeof this.#e.telemetry?.enabled=="boolean"?this.#e.telemetry.enabled:true}setTelemetryEnabled(e){this.#e={...this.#e,telemetry:{...this.#e.telemetry,enabled:e,lastPrompted:Date.now()}};}getTelemetryId(){return this.#e.telemetry?.id}async ensureTelemetryId(){let e=this.getTelemetryId();if(e)return e;let t=ye.randomUUID();return this.#e={...this.#e,telemetry:{...this.#e.telemetry,id:t}},await this.save(),t}getDefaultTemplate(){return this.#e.defaults?.template}getUpdateMetadata(){return this.#e.updates}setUpdateMetadata(e){this.#e={...this.#e,updates:{...this.#e.updates,...e}};}getDeviceInfo(){return this.#e.device}setDeviceInfo(e){this.#e={...this.#e,device:e};}async save(){await $.mkdir(Ve,{recursive:true});let e=JSON.stringify(this.#e,null,2);await $.writeFile(Ee,e,{mode:384}),await $.chmod(Ee,384);}};var ge=class{#e;#t;constructor(e={}){this.#e=e.json??false,this.#t=e.debug??process.env[G]==="1";}isJsonMode(){return this.#e}setJsonMode(e){this.#e=e;}setDebug(e){this.#t=e;}info(e){this.#e||process.stdout.write(`${ve.blue("i")} ${e}
|
|
109
|
+
`);}success(e){this.#e||process.stdout.write(`${ve.green("\u2714")} ${e}
|
|
110
|
+
`);}warn(e){this.#e||process.stdout.write(`${ve.yellow("!")} ${e}
|
|
111
|
+
`);}error(e){this.#e||process.stderr.write(`${ve.red("\u2716")} ${e}
|
|
112
|
+
`);}debug(e){!this.#t||this.#e||process.stdout.write(`${ve.gray("debug")} ${e}
|
|
105
113
|
`);}json(e){let t=JSON.stringify(e,null,2);process.stdout.write(`${t}
|
|
106
|
-
`);}};var
|
|
107
|
-
Update with: ${a} (or pnpm add -g ${Ce}).`),e.setUpdateMetadata({lastNotifiedAt:o,latestVersion:i}),await e.save();}function mo(r,e,t){return !r||r.lastNotifiedAt===void 0||r.latestVersion!==t?true:e-r.lastNotifiedAt>pt}async function uo(r,e){try{let t=await fetch(`https://registry.npmjs.org/${encodeURIComponent(Ce)}/latest`,{headers:{"User-Agent":`hbx-cli/${r}`}});if(!t.ok)throw new Error(`npm registry responded with status ${t.status}`);return {latestVersion:(await t.json()).version,checkedAt:Date.now()}}catch(t){return e.debug(`update check failed: ${String(t)}`),{checkedAt:Date.now()}}}var Be=class{constructor(e){this.context=e;this.cancelled=false;}async*create(e){this.cancelled=false;try{if(yield*this.validateConfiguration(e),this.cancelled||(yield*this.fetchTemplate(e.templateId),this.cancelled)||(yield*this.scaffoldSite(e),this.cancelled)||e.options?.autoInstall!==!1&&(yield*this.installDependencies(e),this.cancelled)||e.options?.initGit!==!1&&(yield*this.initializeGit(e),this.cancelled))return;yield*this.completeCreation(e);}catch(t){yield {id:"error",type:"error",title:"Creation Failed",message:t instanceof Error?t.message:String(t),timestamp:new Date,data:{error:t,config:e}};}}async*validateConfiguration(e){yield this.createProgressStep("validate",0,"Starting validation..."),yield this.createProgressStep("validate",25,"Checking template availability...");let t=await this.validate(e);if(yield this.createProgressStep("validate",75,"Validating target path..."),!t.valid)throw new Error(`Validation failed: ${t.errors[0]?.message}`);for(let n of t.warnings)yield {id:"validate",type:"warning",title:"Configuration Warning",message:n.message,timestamp:new Date,data:{field:n.field,suggestion:n.suggestion}};yield this.createSuccessStep("validate","Configuration validated");}async*fetchTemplate(e){yield this.createProgressStep("fetch_template",0,"Fetching available templates...");let t=await V(this.context);yield this.createProgressStep("fetch_template",50,"Locating template...");let n=t.find(o=>o.id===e);if(!n)throw new Error(`Template "${e}" not found`);yield this.createProgressStep("fetch_template",75,`Found template: ${n.name}`),await this.delay(500),yield this.createSuccessStep("fetch_template",`Template "${n.name}" ready`,{template:n});}async*scaffoldSite(e){let n=(await V(this.context)).find(s=>s.id===e.templateId);if(!n)throw new Error(`Template "${e.templateId}" not found`);yield this.createProgressStep("scaffold_site",0,"Preparing target directory...");let o=Te(e.targetPath,n.slug);await we(o),yield this.createProgressStep("scaffold_site",25,"Copying template files...");let i={sampleContent:e.options?.includeSampleContent??true,includeEnv:true,packageManager:e.packageManager||"pnpm"};await ke(this.context,o,n,i),yield this.createProgressStep("scaffold_site",75,"Customizing site configuration..."),await this.customizeSiteConfig(o,e),yield this.createSuccessStep("scaffold_site","Site structure created",{targetDir:o,templateId:e.templateId});}async*installDependencies(e){let t=e.packageManager||"pnpm",n=e.targetPath;yield this.createProgressStep("install_deps",0,`Starting ${t} install...`);try{await Ee(n,t,this.context.logger)?yield this.createSuccessStep("install_deps","Dependencies installed successfully"):yield {id:"install_deps",type:"warning",title:"Dependencies installation skipped",message:"Some dependencies failed to install, but site creation can continue",timestamp:new Date};}catch(o){throw new Error(`Failed to install dependencies: ${String(o)}`)}}async*initializeGit(e){yield this.createProgressStep("init_git",0,"Initializing git repository..."),await Se(e.targetPath,this.context.logger),yield this.createProgressStep("init_git",75,"Creating initial commit..."),await this.delay(1e3),yield this.createSuccessStep("init_git","Git repository initialized");}async*completeCreation(e){yield this.createProgressStep("complete",50,"Finalizing setup..."),await this.generateSummaryReport(e),yield {id:"complete",type:"success",title:`Site "${e.siteName}" created successfully! \u{1F389}`,progress:100,timestamp:new Date,data:{siteName:e.siteName,targetPath:e.targetPath,templateId:e.templateId,packageManager:e.packageManager,nextSteps:this.generateNextSteps(e)}};}async validate(e){let t=[],n=[];(await V(this.context)).find(s=>s.id===e.templateId)||t.push({field:"templateId",message:`Template "${e.templateId}" not found`,code:"TEMPLATE_NOT_FOUND"}),(!e.siteName||e.siteName.trim().length===0)&&t.push({field:"siteName",message:"Site name is required",code:"SITE_NAME_REQUIRED"});let i=await Ae(e.targetPath);return i.valid||t.push({field:"targetPath",message:i.error||"Invalid target path",code:"INVALID_PATH"}),i.exists&&!i.isEmpty&&n.push({field:"targetPath",message:"Directory is not empty",suggestion:"Files may be overwritten during site creation"}),{valid:t.length===0,errors:t,warnings:n}}async cancel(){this.cancelled=true;}createProgressStep(e,t,n,o){return {id:e,type:"progress",title:this.getStepTitle(e),message:n,progress:t,timestamp:new Date,data:o}}createSuccessStep(e,t,n){return {id:e,type:"success",title:this.getStepTitle(e),message:t,progress:100,timestamp:new Date,data:n}}getStepTitle(e){return {validate:"Validating configuration",fetch_template:"Fetching template",scaffold_site:"Creating site structure",install_deps:"Installing dependencies",init_git:"Initializing git repository",start_server:"Starting development server",complete:"Finalizing setup"}[e]||e}async delay(e){return new Promise(t=>setTimeout(t,e))}async customizeSiteConfig(e,t){this.context.logger.debug(`Customizing site config for ${t.siteName}`);}async generateSummaryReport(e){this.context.logger.debug(`Site creation completed: ${JSON.stringify({template:e.templateId,path:e.targetPath,options:e.options})}`);}generateNextSteps(e){let t=[`cd ${e.targetPath}`];return e.options?.autoInstall===false&&t.push(`${e.packageManager||"pnpm"} install`),e.options?.autoPreview!==false&&t.push(`${e.packageManager||"pnpm"} dev`),t}};var Le=class r{constructor(e){this.context=e;}static{this.PREVIEW_DATA={"academic-cv":{thumbnailUrl:"https://hugoblox.com/previews/academic-cv-thumb.jpg",category:"academic",difficulty:"beginner",estimatedTime:3,features:["Publication lists","Research sections","Academic timeline","Contact forms"],useCases:["Professors","Researchers","PhD students","Academic professionals"]},startup:{thumbnailUrl:"https://hugoblox.com/previews/startup-thumb.jpg",category:"business",difficulty:"intermediate",estimatedTime:5,features:["Landing pages","Pricing tables","Team sections","Newsletter signup"],useCases:["SaaS companies","Startups","Product launches","Marketing sites"]},folio:{thumbnailUrl:"https://hugoblox.com/previews/folio-thumb.jpg",category:"portfolio",difficulty:"beginner",estimatedTime:2,features:["Project galleries","About sections","Contact forms","Responsive design"],useCases:["Designers","Developers","Freelancers","Creative professionals"]}};}async enrichWithPreviews(e,t){let n=e.map(o=>this.enrichTemplate(o));return t?this.applyQueryOptions(n,t):n}enrichTemplate(e){let t=r.PREVIEW_DATA[e.id];return t?{...e,preview:t,stats:this.calculateStats(e)}:{...e,preview:{thumbnailUrl:this.generateFallbackThumbnail(e),category:this.inferCategory(e),difficulty:"intermediate",estimatedTime:4,features:this.inferFeatures(e),useCases:["General purpose"]},stats:this.calculateStats(e)}}generateFallbackThumbnail(e){return `https://hugoblox.com/api/placeholder-thumb/${encodeURIComponent(e.id)}`}inferCategory(e){let t=e.name.toLowerCase(),n=(e.description||"").toLowerCase();return t.includes("academic")||t.includes("cv")||t.includes("research")?"academic":t.includes("startup")||t.includes("business")||n.includes("saas")?"business":t.includes("portfolio")||t.includes("folio")?"portfolio":t.includes("blog")||n.includes("blog")?"blog":t.includes("docs")||t.includes("documentation")?"documentation":"other"}inferFeatures(e){let t=[],n=(e.description||"").toLowerCase();return n.includes("responsive")&&t.push("Mobile responsive"),n.includes("dark")&&t.push("Dark mode support"),n.includes("seo")&&t.push("SEO optimized"),n.includes("multilingual")&&t.push("Multi-language support"),t.length>0?t:["Modern design","Responsive layout"]}calculateStats(e){let t=e.source==="pro"?80:60;return {popularity:["academic-cv","startup","folio"].includes(e.id)?t+20:t,lastUpdated:new Date().toISOString().split("T")[0]}}applyQueryOptions(e,t){let n=[...e];switch(t.category&&(n=n.filter(o=>o.preview.category===t.category)),t.difficulty&&(n=n.filter(o=>o.preview.difficulty===t.difficulty)),t.source&&(n=n.filter(o=>o.source===t.source)),t.sortBy){case "popularity":n.sort((o,i)=>(i.stats?.popularity||0)-(o.stats?.popularity||0));break;case "name":n.sort((o,i)=>o.name.localeCompare(i.name));break;case "difficulty":{let o={beginner:1,intermediate:2,advanced:3};n.sort((i,s)=>o[i.preview.difficulty]-o[s.preview.difficulty]);break}default:n.sort((o,i)=>o.source==="pro"&&i.source!=="pro"?-1:i.source==="pro"&&o.source!=="pro"?1:o.name.localeCompare(i.name));}return t.limit&&t.limit>0&&(n=n.slice(0,t.limit)),n}async getPreview(e){let t=r.PREVIEW_DATA[e];return t?{templateId:e,thumbnailUrl:t.thumbnailUrl,screenshots:await this.getScreenshots(e),demoUrl:await this.getDemoUrl(e),features:t.features,useCases:t.useCases}:null}async getScreenshots(e){let t="https://hugoblox.com/previews/";return [`${t}${e}-1.jpg`,`${t}${e}-2.jpg`,`${t}${e}-3.jpg`]}async getDemoUrl(e){return {"academic-cv":"https://hugoblox.com/templates/academic-cv/",startup:"https://hugoblox.com/templates/startup/",folio:"https://hugoblox.com/templates/portfolio/"}[e]}};var Ne=class{constructor(e){this.context=e;this.templates={fetchAll:async e=>{let t=await V(this.context);return this.previewService.enrichWithPreviews(t,e)},getById:async e=>(await this.templates.fetchAll()).find(n=>n.id===e)||null,getPreview:async e=>this.previewService.getPreview(e)};this.creation={create:e=>this.creationService.create(e),validate:async e=>this.creationService.validate(e),cancel:async()=>this.creationService.cancel()};this.system={detectPackageManager:async e=>Nt(e||process.cwd()),validatePath:async e=>Ae(e),getDefaultConfig:()=>({templateId:"startup",siteName:"my-hugoblox-site",targetPath:"./my-hugoblox-site",packageManager:"pnpm",options:{includeSampleContent:true,initGit:true,autoInstall:true,autoPreview:true},showAdvanced:false,rememberedChoices:{}})};this.previewService=new Le(e),this.creationService=new Be(e);}};async function po(r={}){let e=await fo(r);return new Ne(e)}async function fo(r){let e=Y(),t=await me.load(),n=new ue({debug:r.debug??process.env[G]==="1",json:true});await t.ensureTelemetryId();let o=r.telemetryEnabled!==false?new Q(t,n,e):new nt(t,n,e);return r.progressCallback&&(o.progressCallback=r.progressCallback),{config:t,logger:n,telemetry:o}}var nt=class extends Q{async track(){}setCommand(){}};async function ho(r=process.argv){let e=Y(),t=await me.load(),n=new ue({debug:process.env[G]==="1"});await t.ensureTelemetryId();let o=new Q(t,n,e),i={config:t,logger:n,telemetry:o};await yr(e,t,n),await vo(i);let s=new Command;s.name("hbx").description("HugoBlox Experience CLI").version(e,"-v, --version","Show CLI version").option("--json","Output machine-readable JSON").option("--debug","Enable verbose logging"),s.hook("preAction",(c,a)=>{let l=a?.optsWithGlobals?.()??c.optsWithGlobals();n.setJsonMode(!!l.json),n.setDebug(!!l.debug||process.env[G]==="1"),o.setCommand(bo(a));}),Wt(s,i),Ct(s,i),Zt(s,i),Gt(s,i),Qt(s,i),er(s,i),tr(s,i),nr(s,i),dr(s,i),ar(s,i),fr(s,i);try{await s.parseAsync(r);}catch(c){yo(c,n);}}function yo(r,e){if(ot(r)){let t={status:"error",code:r.code,message:r.message,details:r.details};e.isJsonMode()?e.json(t):e.error(`${r.code}: ${r.message}`);}else r instanceof O?e.error(`${r.code}: ${r.message}`):r instanceof Error?e.error(r.message):e.error("Unknown error");process.exit(1);}(process.argv[1]===fileURLToPath(import.meta.url)||process.argv[1].endsWith("/bin/hbx")||process.argv[1].endsWith("/bin/hugoblox"))&&ho();function bo(r){if(!r)return ve;let e=[],t=r;for(;t?.parent;){let n=t.name?.();n&&e.unshift(n),t=t.parent;}return e.length?`${ve} ${e.join(" ")}`.trim():ve}async function vo(r){if(process.env[ee]&&r.config.getLicense()&&!r.config.getDeviceInfo())try{await L(r);}catch(e){r.logger.debug(`Skipping device registration warm-up: ${String(e)}`);}}
|
|
114
|
+
`);}};var Co=new Set(["command","project","duration","status","errorCode","errorMessage","metadata"]),Po=50,So=6144,Dn=25e3,Z=class{#e;#t;#r;#o=[];#n;#i=false;#s;#a;#c;constructor(e,t,r){this.#e=e,this.#t=t,this.#r=r,this.#a=process.env.HBX_RELEASE_CHANNEL??process.env.RELEASE_CHANNEL??"stable",this.#c=randomUUID(),this.#l();}isEnabled(){return this.#e.isTelemetryEnabled()}setCommand(e){this.#s=e;}async track(e){this.isEnabled()&&(this.#o.push({...e,timestamp:new Date().toISOString(),payload:e.payload??{}}),await this.flush());}async flush(){if(!this.#o.length)return;if(this.#n){await this.#n;return}let e=this.#o.splice(0);this.#n=this.#m(e).finally(()=>{this.#n=void 0;}),await this.#n;}#l(){if(this.#i)return;let e=()=>{this.flush();};process.once("beforeExit",e),process.once("exit",e),process.once("SIGINT",e),process.once("SIGTERM",e),this.#i=true;}async#m(e){if(!e.length)return;let t=this.#e.getTelemetryId(),o=[...e.map(i=>To(i))];for(;o.length;){let i=[],s;for(;o.length&&i.length<Po;){let c=o[0];if(!c)break;let a=[...i,c],l=this.#d(a,t),m=JSON.stringify(l);if(Buffer$1.byteLength(m,"utf8")>Dn){if(!i.length){o.shift(),this.#t.warn("Dropped telemetry event because payload exceeded max size");continue}break}let p=o.shift();if(!p)break;i.push(p),s=m;}!i.length||!s||await this.#u(s,t);}}#d(e,t){return {clientId:t&&t.length>=8?t:"anonymous",os:Ne.platform(),osVersion:Eo(),arch:process.arch,nodeVersion:process.version,ci:ko(),command:this.#s,releaseChannel:this.#a,sessionId:this.#c,cliVersion:this.#r,version:this.#r,hasLicense:!!this.#e.getLicense(),events:e}}async#u(e,t){let r=Buffer$1.byteLength(e,"utf8");if(r>Dn){this.#t.warn("Telemetry payload skipped because it exceeded the maximum request size");return}try{let o=new AbortController,i=setTimeout(()=>o.abort(),5e3),s=await fetch(bt,{method:"POST",headers:{"Content-Type":"application/json","Content-Length":String(r),"User-Agent":`hbx-cli/${this.#r}`,...t?{"x-telemetry-id":t}:void 0},body:e,signal:o.signal});if(clearTimeout(i),s.status===413){this.#t.warn("Telemetry payload rejected (too large)");return}if(!s.ok)throw new Error(`telemetry responded with status ${s.status}`)}catch(o){this.#t.debug(`telemetry send failed: ${String(o)}`);}}};function ko(){return process.env.CI==="1"||process.env.CONTINUOUS_INTEGRATION==="1"||!!process.env.BUILD_NUMBER||!!process.env.RUN_ID}function Eo(){let n=Ne.version;if(typeof n=="function")try{return n()}catch{return Ne.release()}return Ne.release()}function To(n){let e=Ao(n.payload);if(!e){let{payload:t,...r}=n;return r}try{let t=JSON.stringify(e);return Buffer$1.byteLength(t,"utf8")>So?{...n,payload:{truncated:!0}}:{...n,payload:e}}catch{return {...n,payload:{truncated:true}}}}function Ao(n){if(!n||typeof n!="object")return;let e={};for(let t of Co)if(Object.hasOwn(n,t)){let r=n[t];if(t==="metadata"&&(r==null||typeof r!="object"))continue;e[t]=r;}return Object.keys(e).length?e:void 0}async function Ln(n,e,t){if(process.env[gt]==="1")return;let r=e.getUpdateMetadata()??{},o=Date.now(),i=r.latestVersion,s=r.lastChecked??0;if(!i||o-s>vt){let l=await $o(n,t);l.latestVersion&&(i=l.latestVersion),l.checkedAt>0&&(s=l.checkedAt,e.setUpdateMetadata({lastChecked:s,latestVersion:i}),await e.save());}if(!i||!M.valid(i)||!M.gt(i,n)||!_o(r,o,i))return;let a=`npm install -g ${Te}`;t.warn(`A new version of hbx is available: ${i} (current ${n}).
|
|
115
|
+
Update with: ${a} (or pnpm add -g ${Te}).`),e.setUpdateMetadata({lastNotifiedAt:o,latestVersion:i}),await e.save();}function _o(n,e,t){return !n||n.lastNotifiedAt===void 0||n.latestVersion!==t?true:e-n.lastNotifiedAt>xt}async function $o(n,e){try{let t=await fetch(`https://registry.npmjs.org/${encodeURIComponent(Te)}/latest`,{headers:{"User-Agent":`hbx-cli/${n}`}});if(!t.ok)throw new Error(`npm registry responded with status ${t.status}`);return {latestVersion:(await t.json()).version,checkedAt:Date.now()}}catch(t){return e.debug(`update check failed: ${String(t)}`),{checkedAt:Date.now()}}}var Oe=class{constructor(e){this.context=e;this.cancelled=false;}async*create(e){this.cancelled=false;try{if(yield*this.validateConfiguration(e),this.cancelled||(yield*this.fetchTemplate(e.templateId),this.cancelled)||(yield*this.scaffoldSite(e),this.cancelled)||e.options?.autoInstall!==!1&&(yield*this.installDependencies(e),this.cancelled)||e.options?.initGit!==!1&&(yield*this.initializeGit(e),this.cancelled))return;yield*this.completeCreation(e);}catch(t){yield {id:"error",type:"error",title:"Creation Failed",message:t instanceof Error?t.message:String(t),timestamp:new Date,data:{error:t,config:e}};}}async*validateConfiguration(e){yield this.createProgressStep("validate",0,"Starting validation..."),yield this.createProgressStep("validate",25,"Checking template availability...");let t=await this.validate(e);if(yield this.createProgressStep("validate",75,"Validating target path..."),!t.valid)throw new Error(`Validation failed: ${t.errors[0]?.message}`);for(let r of t.warnings)yield {id:"validate",type:"warning",title:"Configuration Warning",message:r.message,timestamp:new Date,data:{field:r.field,suggestion:r.suggestion}};yield this.createSuccessStep("validate","Configuration validated");}async*fetchTemplate(e){yield this.createProgressStep("fetch_template",0,"Fetching available templates...");let t=await V(this.context);yield this.createProgressStep("fetch_template",50,"Locating template...");let r=t.find(o=>o.id===e);if(!r)throw new Error(`Template "${e}" not found`);yield this.createProgressStep("fetch_template",75,`Found template: ${r.name}`),await this.delay(500),yield this.createSuccessStep("fetch_template",`Template "${r.name}" ready`,{template:r});}async*scaffoldSite(e){let r=(await V(this.context)).find(s=>s.id===e.templateId);if(!r)throw new Error(`Template "${e.templateId}" not found`);yield this.createProgressStep("scaffold_site",0,"Preparing target directory...");let o=He(e.targetPath,r.slug);await Pe(o),yield this.createProgressStep("scaffold_site",25,"Copying template files...");let i={sampleContent:e.options?.includeSampleContent??true,includeEnv:true,packageManager:e.packageManager||"pnpm"};await $e(this.context,o,r,i),yield this.createProgressStep("scaffold_site",75,"Customizing site configuration..."),await this.customizeSiteConfig(o,e),yield this.createSuccessStep("scaffold_site","Site structure created",{targetDir:o,templateId:e.templateId});}async*installDependencies(e){let t=e.packageManager||"pnpm",r=e.targetPath;yield this.createProgressStep("install_deps",0,`Starting ${t} install...`);try{await Ie(r,t,this.context.logger)?yield this.createSuccessStep("install_deps","Dependencies installed successfully"):yield {id:"install_deps",type:"warning",title:"Dependencies installation skipped",message:"Some dependencies failed to install, but site creation can continue",timestamp:new Date};}catch(o){throw new Error(`Failed to install dependencies: ${String(o)}`)}}async*initializeGit(e){yield this.createProgressStep("init_git",0,"Initializing git repository..."),await _e(e.targetPath,this.context.logger),yield this.createProgressStep("init_git",75,"Creating initial commit..."),await this.delay(1e3),yield this.createSuccessStep("init_git","Git repository initialized");}async*completeCreation(e){yield this.createProgressStep("complete",50,"Finalizing setup..."),await this.generateSummaryReport(e),yield {id:"complete",type:"success",title:`Site "${e.siteName}" created successfully! \u{1F389}`,progress:100,timestamp:new Date,data:{siteName:e.siteName,targetPath:e.targetPath,templateId:e.templateId,packageManager:e.packageManager,nextSteps:this.generateNextSteps(e)}};}async validate(e){let t=[],r=[];(await V(this.context)).find(s=>s.id===e.templateId)||t.push({field:"templateId",message:`Template "${e.templateId}" not found`,code:"TEMPLATE_NOT_FOUND"}),(!e.siteName||e.siteName.trim().length===0)&&t.push({field:"siteName",message:"Site name is required",code:"SITE_NAME_REQUIRED"});let i=await je(e.targetPath);return i.valid||t.push({field:"targetPath",message:i.error||"Invalid target path",code:"INVALID_PATH"}),i.exists&&!i.isEmpty&&r.push({field:"targetPath",message:"Directory is not empty",suggestion:"Files may be overwritten during site creation"}),{valid:t.length===0,errors:t,warnings:r}}async cancel(){this.cancelled=true;}createProgressStep(e,t,r,o){return {id:e,type:"progress",title:this.getStepTitle(e),message:r,progress:t,timestamp:new Date,data:o}}createSuccessStep(e,t,r){return {id:e,type:"success",title:this.getStepTitle(e),message:t,progress:100,timestamp:new Date,data:r}}getStepTitle(e){return {validate:"Validating configuration",fetch_template:"Fetching template",scaffold_site:"Creating site structure",install_deps:"Installing dependencies",init_git:"Initializing git repository",start_server:"Starting development server",complete:"Finalizing setup"}[e]||e}async delay(e){return new Promise(t=>setTimeout(t,e))}async customizeSiteConfig(e,t){this.context.logger.debug(`Customizing site config for ${t.siteName}`);}async generateSummaryReport(e){this.context.logger.debug(`Site creation completed: ${JSON.stringify({template:e.templateId,path:e.targetPath,options:e.options})}`);}generateNextSteps(e){let t=[`cd ${e.targetPath}`];return e.options?.autoInstall===false&&t.push(`${e.packageManager||"pnpm"} install`),e.options?.autoPreview!==false&&t.push(`${e.packageManager||"pnpm"} dev`),t}};var Fe=class n{constructor(e){this.context=e;}static{this.PREVIEW_DATA={"academic-cv":{thumbnailUrl:"https://hugoblox.com/previews/academic-cv-thumb.jpg",category:"academic",difficulty:"beginner",estimatedTime:3,features:["Publication lists","Research sections","Academic timeline","Contact forms"],useCases:["Professors","Researchers","PhD students","Academic professionals"]},startup:{thumbnailUrl:"https://hugoblox.com/previews/startup-thumb.jpg",category:"business",difficulty:"intermediate",estimatedTime:5,features:["Landing pages","Pricing tables","Team sections","Newsletter signup"],useCases:["SaaS companies","Startups","Product launches","Marketing sites"]},folio:{thumbnailUrl:"https://hugoblox.com/previews/folio-thumb.jpg",category:"portfolio",difficulty:"beginner",estimatedTime:2,features:["Project galleries","About sections","Contact forms","Responsive design"],useCases:["Designers","Developers","Freelancers","Creative professionals"]}};}async enrichWithPreviews(e,t){let r=e.map(o=>this.enrichTemplate(o));return t?this.applyQueryOptions(r,t):r}enrichTemplate(e){let t=n.PREVIEW_DATA[e.id];return t?{...e,preview:t,stats:this.calculateStats(e)}:{...e,preview:{thumbnailUrl:this.generateFallbackThumbnail(e),category:this.inferCategory(e),difficulty:"intermediate",estimatedTime:4,features:this.inferFeatures(e),useCases:["General purpose"]},stats:this.calculateStats(e)}}generateFallbackThumbnail(e){return `https://hugoblox.com/api/placeholder-thumb/${encodeURIComponent(e.id)}`}inferCategory(e){let t=e.name.toLowerCase(),r=(e.description||"").toLowerCase();return t.includes("academic")||t.includes("cv")||t.includes("research")?"academic":t.includes("startup")||t.includes("business")||r.includes("saas")?"business":t.includes("portfolio")||t.includes("folio")?"portfolio":t.includes("blog")||r.includes("blog")?"blog":t.includes("docs")||t.includes("documentation")?"documentation":"other"}inferFeatures(e){let t=[],r=(e.description||"").toLowerCase();return r.includes("responsive")&&t.push("Mobile responsive"),r.includes("dark")&&t.push("Dark mode support"),r.includes("seo")&&t.push("SEO optimized"),r.includes("multilingual")&&t.push("Multi-language support"),t.length>0?t:["Modern design","Responsive layout"]}calculateStats(e){let t=e.source==="pro"?80:60;return {popularity:["academic-cv","startup","folio"].includes(e.id)?t+20:t,lastUpdated:new Date().toISOString().split("T")[0]}}applyQueryOptions(e,t){let r=[...e];switch(t.category&&(r=r.filter(o=>o.preview.category===t.category)),t.difficulty&&(r=r.filter(o=>o.preview.difficulty===t.difficulty)),t.source&&(r=r.filter(o=>o.source===t.source)),t.sortBy){case "popularity":r.sort((o,i)=>(i.stats?.popularity||0)-(o.stats?.popularity||0));break;case "name":r.sort((o,i)=>o.name.localeCompare(i.name));break;case "difficulty":{let o={beginner:1,intermediate:2,advanced:3};r.sort((i,s)=>o[i.preview.difficulty]-o[s.preview.difficulty]);break}default:r.sort((o,i)=>o.source==="pro"&&i.source!=="pro"?-1:i.source==="pro"&&o.source!=="pro"?1:o.name.localeCompare(i.name));}return t.limit&&t.limit>0&&(r=r.slice(0,t.limit)),r}async getPreview(e){let t=n.PREVIEW_DATA[e];return t?{templateId:e,thumbnailUrl:t.thumbnailUrl,screenshots:await this.getScreenshots(e),demoUrl:await this.getDemoUrl(e),features:t.features,useCases:t.useCases}:null}async getScreenshots(e){let t="https://hugoblox.com/previews/";return [`${t}${e}-1.jpg`,`${t}${e}-2.jpg`,`${t}${e}-3.jpg`]}async getDemoUrl(e){return {"academic-cv":"https://hugoblox.com/templates/academic-cv/",startup:"https://hugoblox.com/templates/startup/",folio:"https://hugoblox.com/templates/portfolio/"}[e]}};var Ue=class{constructor(e){this.context=e;this.templates={fetchAll:async e=>{let t=await V(this.context);return this.previewService.enrichWithPreviews(t,e)},getById:async e=>(await this.templates.fetchAll()).find(r=>r.id===e)||null,getPreview:async e=>this.previewService.getPreview(e)};this.creation={create:e=>this.creationService.create(e),validate:async e=>this.creationService.validate(e),cancel:async()=>this.creationService.cancel()};this.system={detectPackageManager:async e=>Gt(e||process.cwd()),validatePath:async e=>je(e),getDefaultConfig:()=>({templateId:"startup",siteName:"my-hugoblox-site",targetPath:"./my-hugoblox-site",packageManager:"pnpm",options:{includeSampleContent:true,initGit:true,autoInstall:true,autoPreview:true},showAdvanced:false,rememberedChoices:{}})};this.previewService=new Fe(e),this.creationService=new Oe(e);}};async function Io(n={}){let e=await Ho(n);return new Ue(e)}async function Ho(n){let e=Q(),t=await fe.load(),r=new ge({debug:n.debug??process.env[G]==="1",json:true});await t.ensureTelemetryId();let o=n.telemetryEnabled!==false?new Z(t,r,e):new dt(t,r,e);return n.progressCallback&&(o.progressCallback=n.progressCallback),{config:t,logger:r,telemetry:o}}var dt=class extends Z{async track(){}setCommand(){}};async function Ro(n=process.argv){let e=Q(),t=await fe.load(),r=new ge({debug:process.env[G]==="1"});await t.ensureTelemetryId();let o=new Z(t,r,e),i={config:t,logger:r,telemetry:o};await Ln(e,t,r),await Mo(i);let s=new Command;s.name("hbx").description("HugoBlox Experience CLI").version(e,"-v, --version","Show CLI version").option("--json","Output machine-readable JSON").option("--debug","Enable verbose logging"),s.hook("preAction",(c,a)=>{let l=a?.optsWithGlobals?.()??c.optsWithGlobals();r.setJsonMode(!!l.json),r.setDebug(!!l.debug||process.env[G]==="1"),o.setCommand(Lo(a));}),Qt(s,i),$t(s,i),pn(s,i),en(s,i),un(s,i),fn(s,i),gn(s,i),En(s,i),Hn(s,i),Tn(s,i),Rn(s,i);try{await s.parseAsync(n);}catch(c){Do(c,r);}}function Do(n,e){if(ut(n)){let t={status:"error",code:n.code,message:n.message,details:n.details};e.isJsonMode()?e.json(t):e.error(`${n.code}: ${n.message}`);}else n instanceof N?e.error(`${n.code}: ${n.message}`):n instanceof Error?e.error(n.message):e.error("Unknown error");process.exit(1);}(process.argv[1]===fileURLToPath(import.meta.url)||process.argv[1].endsWith("/bin/hbx")||process.argv[1].endsWith("/bin/hugoblox"))&&Ro();function Lo(n){if(!n)return ke;let e=[],t=n;for(;t?.parent;){let r=t.name?.();r&&e.unshift(r),t=t.parent;}return e.length?`${ke} ${e.join(" ")}`.trim():ke}async function Mo(n){if(process.env[te]&&n.config.getLicense()&&!n.config.getDeviceInfo())try{await L(n);}catch(e){n.logger.debug(`Skipping device registration warm-up: ${String(e)}`);}}
|
|
108
116
|
|
|
109
|
-
export {
|
|
117
|
+
export { Ro as bootstrap, Io as createWelcomeScreenAPI, Q as getCliVersion };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hugoblox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "The official CLI for creating and managing HugoBlox sites.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"vitest": "1.4.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
|
-
"build": "tsup",
|
|
59
|
-
"build:
|
|
58
|
+
"build": "cross-env HBX_PUBLISH_BUILD=1 tsup",
|
|
59
|
+
"build:dev": "tsup",
|
|
60
60
|
"dev": "tsx watch src/index.ts",
|
|
61
61
|
"lint": "biome check .",
|
|
62
62
|
"lint:fix": "biome check --apply .",
|