hugoblox 0.8.0 → 0.8.1
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 +42 -42
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
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 Xe from 'ora';
|
|
6
|
+
import it from 'yaml';
|
|
7
7
|
import { execa } from 'execa';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
8
|
+
import Oe from 'node:os';
|
|
9
|
+
import Et from 'node:dns/promises';
|
|
10
|
+
import Ge from 'prompts';
|
|
11
11
|
import ye, { randomUUID } from 'node:crypto';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
13
|
import { promisify } from 'node:util';
|
|
@@ -17,12 +17,12 @@ import M from 'semver';
|
|
|
17
17
|
import ve from 'chalk';
|
|
18
18
|
import { Buffer as Buffer$1 } from 'node:buffer';
|
|
19
19
|
|
|
20
|
-
var N=class extends Error{constructor(e,t="HBX_ERROR",r){super(e),this.name="HbxError",this.code=t,this.details=r;}},
|
|
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;}},m=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 ft(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 j(n,e){await $(E.dirname(n)),await _.writeFile(n,e);}var ke="hbx",X="HBX_DEBUG",te="HBX_LICENSE_TOKEN",ht="HBX_TELEMETRY_DISABLED",ze=E.join(Oe.homedir(),".hbx"),Ee=E.join(ze,"config.json"),Un=E.join(Oe.homedir(),".cache","hbx"),ne=E.join(Un,"templates"),yt="HBX_UPDATE_CHECK_DISABLED",re="https://api.github.com",wt=`${re}/repos/HugoBlox/hugo-blox-builder/contents/templates`,bt="https://github.com/HugoBlox/hugo-blox-builder.git",vt="HBX_TEMPLATES_DIR",q="https://cli-api.hugoblox.com",xt=`${q}/api/usage-insights`,Te="hugoblox",Ct=1e3*60*60*24,Pt=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 St(n){let e=E.join(n,"hugoblox.yaml");if(await v(e))try{let t=await _.readFile(e,"utf8"),r=it.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 m("Failed to parse hugoblox.yaml",{error:t})}}async function kt(){try{let{stdout:n}=await execa("hugo",["version"]);return Gn(n)}catch{return}}function Gn(n){let e=n.match(/v(\d+\.\d+\.\d+)/i);return e?e[1]:n.match(/(\d+\.\d+\.\d+)/)?.[1]}var J=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 a=new AbortController,c=setTimeout(()=>a.abort(),t);try{let l=await fetch(n,{...i,signal:a.signal});if(clearTimeout(c),l.status===429||l.status>=500&&l.status<600)throw new J(`Server error: ${l.status}`);return l}catch(l){clearTimeout(c),s++;let d=l.name==="AbortError";if(s>r)throw d?new J(`Request timed out after ${t}ms`,l):l instanceof J?l:new J("Network request failed",l);let w=o*2**(s-1);await new Promise(u=>setTimeout(u,w));}}throw new J("Unreachable")}async function Tt(){try{return await Et.lookup("google.com"),!0}catch{try{return await Et.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 m(`Option required in CI mode: ${n}`)}return (await Ge({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 m(`Option required in CI mode: ${n}`)}return (await Ge({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 m(`Confirmation required in CI mode: ${n}`)}return (await Ge({type:"confirm",name:"value",message:n,initial:e.initial??true},{onCancel:()=>{throw new ee}})).value}function _t(n){let e=n.match(/github\.com[/:]([\w-]+)\/([\w-]+?)(?:\.git)?$/i);return e?{owner:e[1],repo:e[2]}:null}function Xn(n){return _t(n)!==null}async function qn(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 m(`Repository does not contain a 'hugoblox/themes' directory. Please check the repository structure at https://github.com/${n}/${e}`):new m(`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 m(`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 m?r:new m(`Failed to access GitHub repository: ${r instanceof Error?r.message:String(r)}`)}}async function Jn(n,e){let t=await ie(n,{headers:{"User-Agent":"hbx-cli"}});if(!t.ok)throw new m(`Failed to download theme file (status ${t.status})`);let r=await t.text();await j(e,r);}async function Kn(n,e){let t=E.join(n,"config","_default","params.yaml");if(!await v(t))throw new m(`params.yaml not found at ${t}. Please ensure you're in a HugoBlox site.`);let r=await _.readFile(t,"utf8"),o=it.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 a=it.stringify(i);await _.writeFile(t,a,"utf8");}function U(n){return n.toLowerCase().replace(/\.yaml$/i,"")}function It(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 a=await D();if(!a)throw new m("Not in a HugoBlox site. Please run this command from within a HugoBlox site directory (must contain hugoblox.yaml)");let c=a.root,l=t.repo;if(!l){if(t.ci)throw new m("--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(),!Xn(l))throw new m("Invalid GitHub repository URL. Please provide a valid GitHub URL (e.g., https://github.com/owner/repo)");let d=_t(l);if(!d)throw new m("Failed to parse GitHub URL");let{owner:p,repo:w}=d,u=p,g=Xe("Fetching available themes...").start(),h;try{h=await qn(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 m(`Theme '${b}' not found. Available themes: ${h.map(T=>T.name).join(", ")}`);f=[k];}let P=E.join(c,"data","themes",u);await $(P);let x=Xe(`Downloading ${f.length} theme(s)...`).start();try{for(let S of f){let k=E.join(P,S.name);await Jn(S.downloadUrl,k);}x.succeed(`\u2705 Downloaded ${f.length} theme(s) to data/themes/${u}/`);}catch(S){throw x.fail("Failed to download themes"),S}let C=!1,R=null;if((t.setActive||t.setActive!==!1&&!t.noSetActive)&&(t.ci?f.length===1&&(C=!0,R=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?R=U(f[0].name):R=await he("Which theme do you want to activate?",f.map(k=>({title:U(k.name),value:U(k.name)})))))),C&&R){let S=`${u}/${R}`,k=Xe("Updating params.yaml...").start();try{await Kn(c,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:u,themesCount:f.length,activated:C,ci:!!t.ci}}),s){o.json({status:"success",vendor:u,themes:f.map(S=>S.name),activated:R?`${u}/${R}`:null});return}o.success(`
|
|
21
|
+
\u{1F3A8} Themes installed successfully!`),(!C||!R)&&(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: "${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:
|
|
23
|
+
hugoblox:`),o.info(" theme:"),o.info(` pack: "${u}/${U(f[0].name)}"`));}catch(a){if(s){o.json({status:"error",message:a instanceof Error?a.message:String(a)});return}throw a}});}function Ht(n,e){let t=n.command("add").description("Add resources (themes)");It(t,e);}function Rt(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,a="Block creation is coming soon. Follow Discord for updates or to preview it early.";if(s){i.json({status:"pending",message:a});return}i.info(a);});}var Je="com.hugoblox.cli",Zn=1,er=createRequire(import.meta.url),tr=promisify(ye.scrypt),O=null;try{O=er("keytar");}catch{O=null;}async function jt(n,e,t,r,o){let i=`device:${t}`,s,a;if(O)await O.setPassword(Je,i,r);else {let c=await or(r,e);s=c.payload,a=c.salt;}n.setDeviceInfo({id:t,label:o,secretAlias:O?i:void 0,secretFallback:s,secretFallbackSalt:a,secretFallbackVersion:s?Zn:void 0}),await n.save();}async function Dt(n,e){let t=n.getDeviceInfo();if(!t?.id)return;let r;if(t.secretAlias&&O&&(r=await O.getPassword(Je,t.secretAlias)),!r&&t.secretFallback&&t.secretFallbackSalt)try{let{key:o}=await Bt(e,t.secretFallbackSalt);r=rr(t.secretFallback,o);}catch{r=void 0;}if(r)return {id:t.id,secret:r,label:t.label}}async function Ke(n){let e=n.getDeviceInfo();e?.secretAlias&&O&&await O.deletePassword(Je,e.secretAlias),n.setDeviceInfo(void 0),await n.save();}function nr(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 rr(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 Bt(n,e){let t=Buffer.from(e,"base64");return {key:await tr(n,t,32,{N:32768,r:8,p:1,maxmem:64*1024*1024}),salt:e}}async function or(n,e){let t=ye.randomBytes(16).toString("base64"),{key:r}=await Bt(e,t);return {payload:nr(n,r),salt:t}}async function L(n,e={}){let t=n.config.getLicense();if(!t)throw new m("Set HBX_LICENSE_TOKEN or run 'hbx login' to access Pro content.");let r=await n.config.ensureTelemetryId();if(e.force)await Ke(n.config);else {let s=await Dt(n.config,r);if(s)return {id:s.id,secret:s.secret}}let o=e.label??Oe.hostname(),i=await sr(n.config,t,r,o);return await jt(n.config,r,i.deviceId,i.deviceSecret,o),n.logger.debug(`Registered device ${i.deviceId}`),{id:i.deviceId,secret:i.deviceSecret}}async function Lt(n){await Ke(n);}async function sr(n,e,t,r){let o=await fetch(`${q}/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 ar(o);if(!o.ok)throw i?.code==="license_device_limit"?new m("This license has reached the maximum number of devices. Revoke an existing device and try again."):o.status===401||o.status===403?new m(i?.error??"Unable to register device"):new m(i?.error??`Device registration failed (status ${o.status})`);if(!i?.deviceId||!i?.deviceSecret)throw new m("Device registration response was missing credentials");return i}async function ar(n){try{return await n.json()}catch{return}}function cr(n){return n.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}async function V(n){let{logger:e}=n,t=await lr(e),r=await dr(n);return t.length||r.length?[...r,...t]:We}async function lr(n){try{let e=await fetch(wt,{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:cr(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 dr(n){let{logger:e,config:t}=n,r=new Headers({"User-Agent":"hbx-cli"});try{let a=await t.ensureTelemetryId();r.set("x-telemetry-id",a);}catch{}let o,i=t.getLicense();if(i)try{let a=await L(n);o=new Headers(r),o.set("Authorization",`Bearer ${i}`),o.set("X-HBX-Device-Id",a.id),o.set("X-HBX-Device-Secret",a.secret);}catch(a){e?.debug?.(`Skipping device-auth headers for Pro templates: ${String(a)}`);}let s=[];o&&s.push({label:"with auth",headers:o}),s.push({label:o?"without auth":"anonymous",headers:r});for(let a of s)try{let c=await fetch(`${q}/api/pro-templates`,{headers:a.headers});if(!c.ok)throw new Error(`catalog responded with status ${c.status}`);return (await c.json()).templates.map(d=>({id:d.id,name:`${d.name} (Pro)`,description:d.description??void 0,repoPath:void 0,slug:d.slug??d.id,source:"pro",version:d.version,sizeBytes:d.sizeBytes,updatedAt:d.updatedAt,commitHash:d.commitHash,downloadEndpoint:d.downloadUrl}))}catch(c){e.debug(`Unable to fetch Pro template catalog (${a.label}): ${String(c)}`);}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 Qe(n,e,t={},r=0){let o=n.config.getLicense();if(!o)throw new m("A HugoBlox Pro license key is required before accessing Pro templates.");let i=await n.config.ensureTelemetryId(),s=await L(n,{force:r>0}),a=new Headers(t.headers??{});a.set("Authorization",`Bearer ${o}`),a.set("X-HBX-Device-Id",s.id),a.set("X-HBX-Device-Secret",s.secret),a.set("X-Telemetry-Id",i);let c=await fetch(`${q}${e}`,{...t,headers:a});if((c.status===401||c.status===403)&&r===0)return await L(n,{force:true}),Qe(n,e,t,r+1);if(!c.ok){let l=await mr(c);throw l?.code==="license_device_limit"?new m("This license has reached the maximum number of devices. Revoke an existing device and try again."):c.status===401||c.status===403?new m(l?.error??"Device authentication failed."):new m(l?.error??`Request failed (${c.status})`)}return c}async function mr(n){try{return await n.json()}catch{return}}var pr=3;async function Ot(n,e,t,r){if(e.source==="pro"){await yr(n,e,t,r);return}let o=process.env[vt];if(o){await fr(e,o,t),r.debug(`Hydrated template ${e.id} from local override`);return}let i=await hr(e,r),s=i!==void 0?E.join(ne,e.id,i):void 0;if(s&&await v(s)){await K(s,t),r.debug(`Hydrated template ${e.id} from cache (${i})`);return}let a=await _.mkdtemp(E.join(Oe.tmpdir(),"hbx-template-")),c=E.join(a,"repo");try{await execa("git",["clone","--depth","1",bt,c],{stdio:"ignore"});let l=await gr(c,e);s?(await $(E.dirname(s)),await _.rm(s,{recursive:!0,force:!0}),await _.cp(l,s,{recursive:!0}),await Ft(E.join(ne,e.id)),await K(s,t),r.debug(`Hydrated template ${e.id} from fresh cache (${i})`)):(await K(l,t),r.debug(`Hydrated template ${e.id} from repository`));}catch(l){throw new m("Failed to clone HugoBlox templates. Ensure git is installed and accessible.",{error:l})}finally{await _.rm(a,{recursive:true,force:true});}}async function fr(n,e,t){let r=E.join(e,n.id);try{await _.access(r);}catch(o){throw new m(`Local template not found at ${r}`,{error:o})}await K(r,t);}async function gr(n,e){let t=e.repoPath??"",r=E.join(n,t);return await _.access(r),r}async function K(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 Ft(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(pr))await _.rm(r.path,{recursive:true,force:true});}async function hr(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 yr(n,e,t,r){let o=e.version?E.join(ne,e.id,e.version):void 0;if(o&&await v(o)){await K(o,t),r.debug(`Hydrated Pro template ${e.id} from cache (${e.version})`);return}let i=await _.mkdtemp(E.join(Oe.tmpdir(),"hbx-pro-template-")),s=E.join(i,"template.tgz"),a=E.join(i,"extract");await $(a);try{let c=await wr(n,e,s);await execa("tar",["-xzf",s,"-C",a]);let l=await br(a,e.slug),d=e.version??c.version??void 0,p=d!==void 0?E.join(ne,e.id,d):void 0;p?(await $(E.dirname(p)),await _.rm(p,{recursive:!0,force:!0}),await _.cp(l,p,{recursive:!0}),await Ft(E.join(ne,e.id)),await K(p,t),r.debug(`Hydrated Pro template ${e.id} from fresh cache (${d})`)):(await K(l,t),r.debug(`Hydrated Pro template ${e.id} from archive`));}catch(c){throw new m(`Failed to download Pro template ${e.name}. Ensure your license is valid and try again.`,{error:c})}finally{await _.rm(i,{recursive:true,force:true});}}async function wr(n,e,t){let r=e.downloadEndpoint??`/api/pro-templates/${encodeURIComponent(e.id)}/download`,o=await Qe(n,r),i=await vr(o);if(!i?.url)throw new m("Pro template download URL was missing");let s=await fetch(i.url);if(!s.ok)throw new m(`Pro template archive download failed (${s.status})`);let a=Buffer.from(await s.arrayBuffer());return await _.writeFile(t,a),{version:i.version}}async function br(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 vr(n){try{return await n.json()}catch{return}}var Ut="https://hugoblox.com/discord",Vt="https://docs.hugoblox.com",zt="https://hugoblox.com/pro";function W(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 Ot(n,t,e,o),await Cr(e,t,r),r.sampleContent||await Sr(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 xr(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 xr(n){let e=E.join(n,"pnpm-workspace.yaml");if(await v(e))return;await j(e,`packages:
|
|
24
24
|
- './*'
|
|
25
|
-
`);}async function
|
|
25
|
+
`);}async function Xt(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 Cr(n,e,t){let r=W(E.basename(n))||e.slug;await Pr(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,7 +33,7 @@ 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
|
|
36
|
+
`);for(let[i,s]of Object.entries(o)){let a=E.join(n,i);await v(a)||await j(a,s);}}async function Pr(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 j(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 j(t,JSON.stringify(s,null,2));}catch{await j(t,JSON.stringify(r,null,2));}}async function Sr(n,e){let t=E.join(n,"content");await _.rm(t,{recursive:true,force:true}),await $(E.dirname(E.join(t,"_index.md"))),await j(E.join(t,"_index.md"),kr(e));}function kr(n){return `---
|
|
37
37
|
title: "${n.name}"
|
|
38
38
|
type: landing
|
|
39
39
|
design:
|
|
@@ -47,14 +47,14 @@ sections:
|
|
|
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: "${Ut}"
|
|
51
51
|
icon: "chat-bubble-left-right"
|
|
52
52
|
secondary_action:
|
|
53
53
|
text: "Upgrade to Pro"
|
|
54
|
-
url: "${
|
|
54
|
+
url: "${zt}"
|
|
55
55
|
tertiary_action:
|
|
56
56
|
text: "View Docs"
|
|
57
|
-
url: "${
|
|
57
|
+
url: "${Vt}"
|
|
58
58
|
design:
|
|
59
59
|
css_class: "bg-gradient-to-r from-blue-600 to-indigo-600 text-white"
|
|
60
60
|
spacing:
|
|
@@ -63,55 +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](${Ut}) for support and inspiration.
|
|
67
|
+
2. Explore the [documentation](${Vt}) to learn how to add blocks, deploy, and automate.
|
|
68
|
+
3. [Upgrade to Pro](${zt}) 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
|
|
71
|
-
`),i=[],s=false,
|
|
72
|
-
`)}function
|
|
70
|
+
`}function Ze(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 qt(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 Re(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 Er(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 Yt(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:a}=e,l=!!o.optsWithGlobals().json,d=Xe({text:"Fetching templates...",spinner:"dots"}).start(),p=await V(e).finally(()=>{d.succeed("\u2728 Templates ready");}),u=Er(p,r.template);if(!u){if(r.ci)throw new m("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})));u=p.find(T=>T.id===k);}if(!u)throw new m("Unable to determine template");let g=u.source==="pro",h=await Ar(r,t,u),f=He(h,u.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 m(`"${u.name}" is a HugoBlox Pro template. Set HBX_LICENSE_TOKEN with your license key before running in CI.`);if(i.info(`"${u.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 m("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 Kt(s.getLicense());s.setLicense(T),await s.save();}if(!g&&P&&!s.getLicense()){if(r.ci)throw new m("Set HBX_LICENSE_TOKEN before running --ci when enabling Pro features.");let k=await Kt(s.getLicense());s.setLicense(k),await s.save();}P&&await L(e);let x=Xe(`Creating site in ${E.relative(process.cwd(),f)||"."}...`).start();try{await _e(e,f,u,{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 R={status:"success",template:u.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 Tr(r,l)),await a.track({name:"new-site",payload:{template:u.id,sample:b,pro:P,ci:!!r.ci,packageManager:r.packageManager??"pnpm",install:r.install!==false,dependenciesReady:C,preview:S}}),S){await Xt(f,r.packageManager??"pnpm",i);return}if(l){i.json(R);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 Tr(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 Ar(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?$r(o)?o:W(o)||t.slug:t.slug}function $r(n){return /[\\/]/.test(n)||n.includes(":")}async function Kt(n){let t=(await B("Enter your HugoBlox Pro license key (from your purchase confirmation email)",{initial:n??""})).trim();if(!t)throw new m("A HugoBlox Pro license key is required to continue. Check your purchase email or visit https://hugoblox.com/pro.");return t}var Rr=fileURLToPath(import.meta.url),tt=E.dirname(Rr);function jr(){return tt.endsWith("dist")?E.join(tt,"lib","templates","minimal-theme.yaml"):E.resolve(tt,"..","lib","templates","minimal-theme.yaml")}var Qt=jr();function Dr(n){return /^[a-zA-Z0-9_-]+$/.test(n)}async function Br(){try{return await _.readFile(Qt,"utf8")}catch(n){throw new m(`Failed to load theme template: ${Qt}`,{error:n})}}function Lr(n,e,t,r){let o=n.split(`
|
|
71
|
+
`),i=[],s=false,a=0;for(let c of o){if(c.trim()==="meta:"){s=true,a=c.indexOf("meta:"),i.push(c),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){c.trim()&&!c.startsWith(" ".repeat(a+2))&&c.indexOf(":")>0&&(s=false,i.push(c));continue}i.push(c);}return i.join(`
|
|
72
|
+
`)}function Zt(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,a=!!o.optsWithGlobals().json;try{let c=r.vendor;if(!c){if(r.ci)throw new m("--vendor is required when running with --ci");c=await B("What is your GitHub username? (This will be your vendor namespace)");}if(c=c.trim(),!c)throw new m("Vendor namespace is required");if(!Dr(c))throw new m("Vendor namespace must contain only alphanumeric characters, hyphens, and underscores");let l=t;if(!l){if(r.ci)throw new m("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 m("Theme slug is required");let d=W(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",c),u=E.join(w,`${d}.yaml`);if(await v(u)){if(r.ci)throw new m(`Theme file already exists: ${u}`);if(!await H(`Theme file ${d}.yaml already exists. Overwrite?`,{initial:!1})){i.info("Theme creation cancelled");return}}let g=Xe("Creating theme...").start();try{await $(w);let f=await Br(),b=Lr(f,c,p,d);await j(u,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:c,themeFilename:d,ci:!!r.ci}});let h=E.relative(process.cwd(),u);if(a){i.json({status:"success",path:u,vendor:c,themeFilename:d,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: "${
|
|
75
|
+
hugoblox:`),i.info(" theme:"),i.info(` pack: "${c}/${d}"`),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
|
-
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/${
|
|
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/${d}.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
|
-
hbx add theme --repo https://github.com/${
|
|
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
|
|
80
|
+
hbx add theme --repo https://github.com/${c}/your-repo-name
|
|
81
|
+
`),i.info("\u{1F4A1} Tip: You can add multiple themes to the same repository!"));}catch(c){if(a){i.json({status:"error",message:c instanceof Error?c.message:String(c)});return}throw c}});}function en(n,e){let t=n.command("create").description("Create resources (site, theme, block)");Yt(t,e),Zt(t,e),Rt(t,e);}function nn(n,e){Nr(n,e),Or(n,e);}function Nr(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,c=!!o.optsWithGlobals().json,l=await rn(r.path),d=["server"];r.defaultFlags!==false&&d.push("--disableFastRender"),d.push(...t),await on(d,l,i,{allowSignalExit:true,label:"dev server"}),await s.track({name:"dev",payload:{customPath:!!r.path,defaultFlags:r.defaultFlags!==false,args:t}}),c&&i.json({status:"success"});});}function Or(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,c=!!o.optsWithGlobals().json,l=await rn(r.path),d=[];r.defaultFlags!==false&&d.push("--gc","--minify"),d.push(...t),await on(d,l,i,{allowSignalExit:false,label:"build"}),await s.track({name:"build",payload:{customPath:!!r.path,defaultFlags:r.defaultFlags!==false,args:t}}),c&&i.json({status:"success"});});}async function rn(n){let e=n?E.resolve(n):E.resolve(process.cwd()),t=await D(e);if(!t)throw new m("Unable to locate a HugoBlox project. Run this inside a project or pass --path.");return t.root}async function on(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 m(`Hugo ${r.label} failed: ${i.shortMessage??i.message}`,{error:i})}}var Ur=["github.com/HugoBlox/kit/modules","github.com/HugoBlox/hugo-blox-builder","github.com/wowchemy/wowchemy-hugo-themes"],nt=[{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"}],G="github.com/HugoBlox/hugo-blox-builder/",rt="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=mn(t).map(s=>({...s,path:Be(s.path)})).filter(s=>Ur.some(a=>s.path.startsWith(a)));return await Promise.all(o.map(async s=>{try{let a=await cn(s.path);return {path:s.path,current:s.version,latest:a}}catch(a){return {path:s.path,current:s.version,latest:void 0,error:a.message}}}))}async function cn(n){let e=Be(n);if(e.includes("github.com/HugoBlox/kit/modules"))return sn(e,"HugoBlox/kit");if(e.includes("github.com/HugoBlox/hugo-blox-builder"))return sn(e,"HugoBlox/hugo-blox-builder")}async function sn(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/":G,i=n.split(o);if(i.length<2)return;let s=i[1],a=r.filter(c=>c.name.startsWith(`${s}/`)&&/v\d+\.\d+\.\d+/.test(c.name)).map(c=>c.name);if(a.length!==0)return a.sort((c,l)=>{let d=c.split("/").pop()||"0.0.0",p=l.split("/").pop()||"0.0.0";return M.rcompare(d,p)}),a[0].split("/").pop()}async function ln(n,e){let t=Be(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(G)){let p=t.split(G);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")}`,a=`${o}/hugo.yaml`,c=await ie(`${re}/repos/${r}/contents/${a}?ref=${s}`,{headers:{Accept:"application/vnd.github.v3.raw"}});if(!c.ok)return;let l=await c.text();return it.parse(l)?.module?.hugoVersion?.min}async function dn(n,e={}){let t=E.join(n,"go.mod"),r=[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 o=await _.readFile(t,"utf8"),i=e.fetchLatest===!0?await Vr(o,e.fetchLatestFn??cn):void 0,s=zr(o,i);s!==o&&await _.writeFile(t,s,"utf8");}catch{}for(let o of r)try{let i=await _.readFile(o,"utf8"),s=Wr(i);s!==i&&await _.writeFile(o,s,"utf8");}catch{}}function Be(n){let e=nt.find(t=>t.from===n);return e?e.to:n.startsWith(G)?n.replace(G,rt):n}function un(n){let e=n;for(let t of nt)e=e.replaceAll(t.from,t.to);return e.includes(G)&&(e=e.replaceAll(G,rt)),e}async function Vr(n,e){let r=mn(n).map(s=>{let a=Be(s.path);if(a!==s.path)return a}).filter(s=>!!s),o=Array.from(new Set(r)),i=await Promise.all(o.map(async s=>{try{let a=await e(s);return a?[s,a]:void 0}catch{return}}));return new Map(i.filter(s=>!!s))}function zr(n,e){let t=n,r=i=>i.replace(/^v/,"");for(let i of nt){let s=new RegExp(`(^[\\t ]*)${an(i.from)}\\s+v(\\d+\\.\\d+\\.\\d+)(-0\\.[0-9]{14}-[a-f0-9]{12})?(\\s+//.*)?`,"gm");t=t.replace(s,(a,c,l,d,p)=>{let w=p??"",u=r(e?.get(i.to)??l);return `${c}${i.to} v${u}${w}`});}let o=new RegExp(`(^[\\t ]*)${an(G)}([^\\s]+)\\s+v(\\d+\\.\\d+\\.\\d+)(-0\\.[0-9]{14}-[a-f0-9]{12})?(\\s+//.*)?`,"gm");return t=t.replace(o,(i,s,a,c,l,d)=>{let p=d??"",w=`${rt}${a}`,u=r(e?.get(w)??c);return `${s}${w} v${u}${p}`}),t=un(t),t}function Wr(n){return un(n)}function an(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function mn(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 a=s.split(/\s+/);a.length>=2&&e.push({path:a[0],version:a[1]});}}return e}function Le(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,a,c,l,d]=t;return `commit ${d.substring(0,7)} (released ${o}-${i}-${s})`}return n}function fn(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 ot(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 gn(n,e){n.command("doctor").description("Check local environment for common issues").action(async(t,r)=>{let{logger:o,config:i}=e,a=!!r.optsWithGlobals().json,c=[];c.push({name:"Node.js",ok:true,details:process.version});let l=await ot("git",["--version"]);c.push({name:"Git",ok:!l.startsWith("Not"),details:l});let d=await ot("hugo",["version"]);c.push({name:"Hugo",ok:!d.startsWith("Not"),details:d});let p=Xr(d),w=await ot("pnpm",["--version"]);c.push({name:"pnpm",ok:!w.startsWith("Not"),details:w});let u=i.getLicense();c.push({name:"Pro license",ok:!!u,details:u?"Configured":"Missing"});let g=await D();if(g){let b=await St(g.root);if(b){let x=b.templateName??b.templateId??"Unknown";c.push({name:"Template",ok:true,details:`${x} (${fn(g.root)})`});let C=qr(b.requiredHugoVersion,p);C&&c.push(C);}let P=await De(g.root);for(let x of P){let C=x.path.split("/").pop()||x.path,R=x.current;if(x.latest){let k=M.coerce(x.current),T=M.coerce(x.latest);k&&T&&M.eq(k,T)&&(R=`${R} (latest)`);}c.push({name:`Module: ${C}`,ok:true,details:R});let{updateAvailable:S}=Le(x.current,x.latest);S&&x.latest&&c.push({name:`${C} update`,ok:false,details:`Current ${x.current}, latest ${x.latest}. Run 'hbx upgrade' to update.`,level:"warn"});}}let f={status:c.some(b=>(b.level??(b.ok?"info":"error"))==="error")?"error":"success",checks:c};if(a){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 Xr(n){let e=n.match(/v(\d+\.\d+\.\d+)/i);return e?e[1]:n.match(/(\d+\.\d+\.\d+)/)?.[1]}function qr(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 hn(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,c=!!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 m("Unable to locate a HugoBlox project - pass --path if needed");let d=i.getLicense();if(!d){if(t.ci)throw new m(`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=Xe("Hydrating Pro assets...").start();try{let u=E.join(l.root,"config","_default","module.hbx.toml"),g=E.join(l.root,"node_modules","@hugoblox-pro","sample");await $(g),await j(E.join(g,"README.md"),`# HugoBlox Pro assets placeholder
|
|
82
|
+
`),await j(u,`# 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
|
-
`),p.succeed("Assets hydrated");}catch(
|
|
87
|
+
`),p.succeed("Assets hydrated");}catch(u){throw p.fail("Failed to hydrate assets"),u}await s.track({name:"install",payload:{ci:!!t.ci,force:!!t.force,tokenPresent:!!d,customPath:!!t.path}});let w={status:"success",path:l.root,forced:!!t.force,token:!!d};c?o.json(w):(o.success("Install complete"),d||o.info("Tip: run hbx login to unlock Pro downloads"));});}function yn(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,a=!!r.optsWithGlobals().json,c=t.token;if(!c){if(t.ci)throw new m("License key is required when using --ci");c=await B("Enter your HugoBlox Pro license key");}let l=false;try{o.setLicense(c),await o.save(),l=!0,await L(e,{force:!0});let d={status:"success",token:Ze(c)};a?i.json(d):i.success(`License key saved (${Ze(c)})`);}catch(d){throw l&&(o.clearLicense(),await o.save()),Kr(d)}});}function wn(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 Lt(o),o.clearLicense(),await o.save();let a={status:"success"};s?i.json(a):i.success("License key removed");});}function Kr(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 m(`${e}. ${t}`,n.details):new m(`${e}. ${t}`)}function ue(n){let e=n.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!e)return {frontMatter:{},body:n};try{let t=it.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*me(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*me(r);}else t.name.endsWith(".md")&&(yield r);}}function xn(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 m("No Hugo project found in the current directory.");let i=Xe("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 a=await Cn(s);if(a.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
|
-
`),r.info(` Found ${
|
|
89
|
+
`),r.info(` Found ${a.length} author profile(s):`);for(let l of a){let d=l.slug==="admin"?"me":l.slug;r.info(` \u2022 ${l.slug} \u2192 data/authors/${d}.yaml`),l.avatarPath&&r.info(` Avatar: ${E.basename(l.avatarPath)} \u2192 assets/media/authors/${d}${E.extname(l.avatarPath)}`);}if(r.info(`
|
|
90
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
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
|
|
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
|
|
94
|
-
Original files preserved in content/authors/`);}}catch(s){throw i.stop(),s}});}async function
|
|
95
|
-
Please remove or back them up manually before running migration.`)}await
|
|
96
|
-
Please rename them to use lowercase letters, numbers, or hyphens.`);if(p.length>0)throw o.stop(),new
|
|
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
|
|
98
|
-
${
|
|
92
|
+
This will restructure your author data. We recommend backing up first. Continue?`,{initial:!1})){r.info("Migration cancelled.");return}let c=await go(o.root,a,r);if(r.info(""),c.success)r.success("\u2705 Migration complete!"),r.info(` \u2022 Migrated ${c.authorsMigrated} author profile(s)`),r.info(` \u2022 Updated ${c.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 c.errors)r.error(` \u2022 ${l}`);r.info(`
|
|
94
|
+
Original files preserved in content/authors/`);}}catch(s){throw i.stop(),s}});}async function Cn(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 a=st(o.name);if(a)try{let c=await _.readFile(s,"utf8"),{frontMatter:l,body:d}=ue(c),p,u=(await _.readdir(i)).find(g=>/^avatar\.(png|jpg|jpeg|webp)$/i.test(g));u&&(p=E.join(i,u)),e.push({slug:o.name,targetSlug:a,originalPath:i,frontMatter:l,content:d.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}=ue(o);if(Zr(i,s)){let a=y(i.slug)??"admin",c=a?st(a):void 0;if(c&&!e.some(l=>l.targetSlug===c)){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:a,targetSlug:c,originalPath:n,frontMatter:i,content:s.trim(),avatarPath:l});}}}catch{}return e}function Zr(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 st(n){let e=W(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 eo(n){return Array.isArray(n)?n.map(e=>y(e)).filter(e=>!!e):[]}function to(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 a=y(n.name_pronunciation??n.pronunciation);a&&(e.pronunciation=a);let c=y(n.pronouns);return c&&(e.pronouns=c),e}function no(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 ro(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 oo(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&&io(s,e);}return Object.keys(e).length===0?void 0:e}function io(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 so(n,e,t){let r=[];if(Array.isArray(n))for(let s of n){if(typeof s!="object"||s===null)continue;let a=s,c=y(a.icon),l=y(a.url),d=y(a.label);if(c&&l){let p={icon:c,url:l};d&&(p.label=d),r.push(p);}}let o=y(t);if(o){let s=o.startsWith("mailto:")?o:`mailto:${o}`;r.some(a=>a.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 ao(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 co(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 a=be(t.start??t.date_start);a!==void 0&&(o.start=a);let c=be(t.end??t.date_end);c!==void 0&&(o.end=c);let l=y(t.summary);l&&(o.summary=l);let d=Pn(t.button);return d&&(o.button=d),o}).filter(e=>!!e):[]}function lo(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 a=be(t.end??t.date_end);a!==void 0&&(i.end=a);let c=y(t.summary);c&&(i.summary=c);let l=Pn(t.button);return l&&(i.button=l),i}).filter(e=>!!e):[]}function Pn(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 uo(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(a=>{if(typeof a!="object"||a===null)return;let c=a,l=y(c.label??c.name);if(!l)return;let d={label:l},p=Sn(c.level)??at(typeof c.percent=="number"?c.percent:void 0);p!==void 0&&(d.level=p);let w=y(c.icon);return w&&(d.icon=w),d}).filter(a=>!!a);if(o.length===0)return;let i={items:o},s=y(t.name);return s&&(i.name=s),i}).filter(e=>!!e):[]}function at(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 Sn(n){if(!(typeof n!="number"||Number.isNaN(n)))return n>=1&&n<=5?Math.round(n):at(n)}function mo(n){return Array.isArray(n)?n.map(e=>{if(typeof e=="string"){let c=y(e);return c?{name:c}: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=Sn(t.level)??at(o),s={name:r};i!==void 0&&(s.level=i),o!==void 0&&(s.percent=o);let a=y(t.label)??po(o,i);return a&&(s.label=a),s}).filter(e=>!!e):[]}function po(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 fo(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 a=y(t.summary);a&&(o.summary=a);let c=y(t.icon);return c&&(o.icon=c),o}).filter(e=>!!e):[]}function kn(n,e){let{frontMatter:t,content:r}=n,o={schema:"hugoblox/author/v1",slug:e},i=to(t);Object.keys(i).length>0&&(o.name=i),t.superuser===true&&(o.is_owner=true);let s=no(t);s&&(o.status=s);let a=y(t.role);a&&(o.role=a);let c=y(t.bio)??r.trim();c&&(o.bio=c);let l=ro(t.organizations??t.affiliations);l.length>0&&(o.affiliations=l);let d=oo(t);d&&(o.ids=d);let p=[];Array.isArray(t.profiles)&&p.push(...t.profiles);let w=t.links;Array.isArray(w)&&p.push(...w);let u=so(p,t.website,t.email);u.length>0&&(o.links=u);let g=eo(t.interests);g.length>0&&(o.interests=g);let h=ao(t.postnominals??t.credentials);h&&(o.postnominals=h);let f=co(t.education);f.length>0&&(o.education=f);let b=lo(t.work??t.experience);b.length>0&&(o.experience=b);let P=uo(t.skills);P.length>0&&(o.skills=P);let x=mo(t.languages);x.length>0&&(o.languages=x);let C=fo(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 En(n,e,t){let r=E.extname(n)||".png",o=E.join(e,`${t}${r}`);return await _.copyFile(n,o),o}async function go(n,e,t){let r={success:true,authorsMigrated:0,contentFilesMigrated:0,errors:[]},o=Xe("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 a=E.join(n,"data","authors"),c=E.join(n,"assets","media","authors");if(await v(a)){let h=(await _.readdir(a)).filter(f=>f.endsWith(".yaml")||f.endsWith(".yml"));if(h.length>0)throw o.stop(),new m(`data/authors/ already contains ${h.length} YAML file(s).
|
|
95
|
+
Please remove or back them up manually before running migration.`)}await $(a),await $(c);let l=new Map,d=new Set,p=[],w=[];for(let g of e){let h=g.targetSlug??st(g.slug);if(!h){w.push(g.slug);continue}d.has(h)&&p.push(h),d.add(h);let f=new Set([g.slug]),b=g.slug.toLowerCase();b!==g.slug&&f.add(b);let P=W(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 m(`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 m(`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 m(`Unable to determine target slug for '${h.slug}'`);let b=kn(h,f),P=E.join(a,`${f}.yaml`),x=it.stringify(b,{defaultStringType:"QUOTE_DOUBLE",lineWidth:0});try{let C=it.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 En(h.avatarPath,c,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 u=E.join(n,"content");if(await v(u)){let g=await Tn(u,l);r.contentFilesMigrated=g;}o.text="Finalizing migration...",await _.rm(i,{recursive:!0,force:!0}),o.succeed("Migration complete");}catch(a){o.fail("Migration failed"),r.success=false,r.errors.push(String(a));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 c=E.join(n,"data","authors");await v(c)&&(await _.readdir(c)).filter(w=>w.endsWith(".yaml")).length===r.authorsMigrated&&(await _.rm(c,{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(c){r.errors.push(`Rollback failed: ${String(c)}`),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 Tn(n,e){let t=0;for await(let r of me(n))try{let o=await _.readFile(r,"utf8"),{frontMatter:i,body:s}=ue(o),a=!1;if(Array.isArray(i.authors)){let c=i.authors.map(l=>{if(typeof l=="string"){let d=l.trim(),p=d.toLowerCase(),w=e.get(d)??e.get(l)??e.get(p);if(w)return a=!0,w}return l});i.authors=c;}if(a){let c=`---
|
|
98
|
+
${it.stringify(i)}---
|
|
99
99
|
|
|
100
|
-
${s}`;await
|
|
100
|
+
${s}`;await _.writeFile(r,c,"utf8"),t++;}}catch{}return t}function An(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 m("No Hugo project found in the current directory.");let i=Xe("Analyzing event content...").start();try{let s=E.join(o.root,"content","event"),a=E.join(o.root,"content","events"),c=await v(s),l=await v(a),d;if(l?d=a:c&&(d=s),!d){i.stop(),r.info("\u2139\uFE0F No legacy event content found under content/event/ or content/events/.");return}let p=await bo(d),w=c&&!l;if(i.stop(),r.info(`
|
|
101
101
|
\u{1F4CB} Migration Plan (v0.11.0 Events):
|
|
102
|
-
`),w?r.info(" \u2713 Rename content/event/ \u2192 content/events/"):
|
|
102
|
+
`),w?r.info(" \u2713 Rename content/event/ \u2192 content/events/"):c&&l?r.info(" \u2713 content/events/ already exists (no rename needed)"):c?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
103
|
\u2139\uFE0F No event markdown files were found to migrate.`);return}if(t.dryRun){r.info(`
|
|
104
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=
|
|
106
|
-
${
|
|
105
|
+
This will rename event directories (if needed) and adjust front matter. Continue?`,{initial:!1})){r.info("Migration cancelled.");return}if(w){let f=Xe("Renaming content/event/ to content/events/...").start();await _.rename(s,a),f.succeed("Renamed legacy event directory.");}let u=await v(a)?a:d;if(!u)throw new m("No event directory found to migrate after analysis.");let g=Xe("Updating event front matter...").start(),h=await yo(u);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 m("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 m?s:new m(`Event migration failed: ${String(s)}`)}});}async function yo(n){let e={processed:0,updated:0,errors:[]};for await(let t of me(n))try{let r=await _.readFile(t,"utf8"),{frontMatter:o,body:i}=ue(r),{migrated:s,changed:a}=wo(o);if(!a){e.processed+=1;continue}let l=`---
|
|
106
|
+
${it.stringify(s,{lineWidth:0})}---
|
|
107
107
|
|
|
108
|
-
${i}`;await
|
|
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 wo(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 bo(n){let e=0;for await(let t of me(n))e+=1;return e}function $n(n,e){let t=n.command("migrate").description("Migrate HugoBlox project to newer versions");xn(t,e),An(t,e);}function _n(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 Hn(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 a=await _.readFile(s,"utf8"),c=a.match(i.regex);if(c){let l=c[2],d=M.coerce(l),p=M.coerce(r);if(d&&p&&M.lt(d,p)){let w=a.replace(i.regex,`$1${r}$3`);await _.writeFile(s,w,"utf8"),t.success(`Updated ${i.name} Hugo version to ${r}`);}}}catch{}}}function Dn(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 Tt()||(o.error("\u274C You appear to be offline. Please check your internet connection."),process.exit(1));let i=await D();if(!i)throw new m("No Hugo project found in the current directory.");await dn(i.root,{fetchLatest:true});let s=Xe("Checking for updates...").start(),a=await De(i.root);if(a.length===0){s.stop(),o.info("\u2139\uFE0F No official HugoBlox modules found in go.mod");return}let c=a.filter(u=>u.error);if(c.length>0){s.stop(),o.error("\u274C Failed to check for updates for some modules:");for(let u of c)o.error(` ${u.path}: ${u.error}`);process.exit(1);}let l=[];if(t.canary)s.text="Checking canary versions...",l.push(...a.map(u=>({path:u.path,version:"main"})));else {let u=a.map(g=>{let{updateAvailable:h,diff:f}=Le(g.current,g.latest);return {...g,updateAvailable:h,diff:f}}).filter(g=>g.updateAvailable&&g.latest);if(u.length===0){s.stop(),o.success("\u2705 All HugoBlox modules are up to date");return}l.push(...u.map(g=>({path:g.path,version:g.latest||""})));}s.text="Checking version requirements...";let d=await Promise.all(l.map(async u=>{try{let g=await ln(u.path,u.version);return {...u,min:g}}catch{return {...u,min:void 0}}}));if(s.stop(),!t.force){let u=await kt();if(u){let g=d.filter(h=>{if(!h.min)return false;let f=M.coerce(h.min),b=M.coerce(u);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 ${u})`);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 u of a)o.info(` ${u.path.split("/").pop()}: ${le(u.current)} -> @main`);}else {o.info(`\u{1F4E6} Updates available for ${l.length} module(s):`);for(let u of l){let g=a.find(h=>h.path===u.path)?.current||"?";o.info(` ${u.path.split("/").pop()}`),o.info(` Current: ${le(g)}`),o.info(` Latest: ${le(u.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(u=>`${u.path}@${u.version}`);await xo(i.root,p,o);let w=d.reduce((u,g)=>{if(!g.min)return u;let h=M.coerce(g.min),f=M.coerce(u);return h&&(!f||M.gt(h,f))?g.min:u},void 0);w&&await Hn(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 xo(n,e,t){let r=Xe("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=Po(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 Po(n){let e=E.dirname(fileURLToPath(n)),t=E.resolve(e,"../package.json");return F.existsSync(t)?t:E.resolve(e,"../../package.json")}function Ln(n,e){n.command("version").description("Print CLI version").action((t,r)=>{let{logger:o}=e,i=!!r.optsWithGlobals().json,s=Q(),a={status:"success",version:s};i?o.json(a):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[ht]==="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(ze,{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[X]==="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
109
|
`);}success(e){this.#e||process.stdout.write(`${ve.green("\u2714")} ${e}
|
|
110
110
|
`);}warn(e){this.#e||process.stdout.write(`${ve.yellow("!")} ${e}
|
|
111
111
|
`);}error(e){this.#e||process.stderr.write(`${ve.red("\u2716")} ${e}
|
|
112
112
|
`);}debug(e){!this.#t||this.#e||process.stdout.write(`${ve.gray("debug")} ${e}
|
|
113
113
|
`);}json(e){let t=JSON.stringify(e,null,2);process.stdout.write(`${t}
|
|
114
|
-
`);}};var
|
|
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)}`);}}
|
|
114
|
+
`);}};var Eo=new Set(["command","project","duration","status","errorCode","errorMessage","metadata"]),To=50,Ao=6144,Mn=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.#d(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#d(e){if(!e.length)return;let t=this.#e.getTelemetryId(),o=[...e.map(i=>Io(i))];for(;o.length;){let i=[],s;for(;o.length&&i.length<To;){let a=o[0];if(!a)break;let c=[...i,a],l=this.#u(c,t),d=JSON.stringify(l);if(Buffer$1.byteLength(d,"utf8")>Mn){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=d;}!i.length||!s||await this.#m(s,t);}}#u(e,t){return {clientId:t&&t.length>=8?t:"anonymous",os:Oe.platform(),osVersion:_o(),arch:process.arch,nodeVersion:process.version,ci:$o(),command:this.#s,releaseChannel:this.#a,sessionId:this.#c,cliVersion:this.#r,version:this.#r,hasLicense:!!this.#e.getLicense(),events:e}}async#m(e,t){let r=Buffer$1.byteLength(e,"utf8");if(r>Mn){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(xt,{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 $o(){return process.env.CI==="1"||process.env.CONTINUOUS_INTEGRATION==="1"||!!process.env.BUILD_NUMBER||!!process.env.RUN_ID}function _o(){let n=Oe.version;if(typeof n=="function")try{return n()}catch{return Oe.release()}return Oe.release()}function Io(n){let e=Ho(n.payload);if(!e){let{payload:t,...r}=n;return r}try{let t=JSON.stringify(e);return Buffer$1.byteLength(t,"utf8")>Ao?{...n,payload:{truncated:!0}}:{...n,payload:e}}catch{return {...n,payload:{truncated:true}}}}function Ho(n){if(!n||typeof n!="object")return;let e={};for(let t of Eo)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 On(n,e,t){if(process.env[yt]==="1")return;let r=e.getUpdateMetadata()??{},o=Date.now(),i=r.latestVersion,s=r.lastChecked??0;if(!i||o-s>Ct){let l=await jo(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)||!Ro(r,o,i))return;let c=`npm install -g ${Te}`;t.warn(`A new version of hbx is available: ${i} (current ${n}).
|
|
115
|
+
Update with: ${c} (or pnpm add -g ${Te}).`),e.setUpdateMetadata({lastNotifiedAt:o,latestVersion:i}),await e.save();}function Ro(n,e,t){return !n||n.lastNotifiedAt===void 0||n.latestVersion!==t?true:e-n.lastNotifiedAt>Pt}async function jo(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 Fe=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 Re(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 Ue=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 Ve=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=>qt(e||process.cwd()),validatePath:async e=>Re(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 Ue(e),this.creationService=new Fe(e);}};async function Do(n={}){let e=await Bo(n);return new Ve(e)}async function Bo(n){let e=Q(),t=await fe.load(),r=new ge({debug:n.debug??process.env[X]==="1",json:true});await t.ensureTelemetryId();let o=n.telemetryEnabled!==false?new Z(t,r,e):new pt(t,r,e);return n.progressCallback&&(o.progressCallback=n.progressCallback),{config:t,logger:r,telemetry:o}}var pt=class extends Z{async track(){}setCommand(){}};async function Mo(n=process.argv){let e=Q(),t=await fe.load(),r=new ge({debug:process.env[X]==="1"});await t.ensureTelemetryId();let o=new Z(t,r,e),i={config:t,logger:r,telemetry:o};await On(e,t,r),await Uo(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",(a,c)=>{let l=c?.optsWithGlobals?.()??a.optsWithGlobals();r.setJsonMode(!!l.json),r.setDebug(!!l.debug||process.env[X]==="1"),o.setCommand(Fo(c));}),en(s,i),Ht(s,i),hn(s,i),nn(s,i),gn(s,i),yn(s,i),wn(s,i),$n(s,i),Dn(s,i),_n(s,i),Ln(s,i);try{await s.parseAsync(n);}catch(a){No(a,r);}}function No(n,e){if(ft(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"))&&Mo();function Fo(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 Uo(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)}`);}}
|
|
116
116
|
|
|
117
|
-
export {
|
|
117
|
+
export { Mo as bootstrap, Do as createWelcomeScreenAPI, Q as getCliVersion };
|