vibespot 0.9.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,46 +1,46 @@
1
- var yr=Object.defineProperty;var Ze=(e,t)=>()=>(e&&(t=e(e=0)),t);var So=(e,t)=>{for(var o in t)yr(e,o,{get:t[o],enumerable:!0})};import Bl from"path";import{fileURLToPath as Vl}from"url";var h=Ze(()=>{"use strict"});import{readFileSync as wo,writeFileSync as br,mkdirSync as xo,existsSync as Rn}from"fs";import{dirname as Sr,join as nt}from"path";function v(e){return wo(e,"utf-8")}function M(e,t){xo(Sr(e),{recursive:!0}),br(e,t,"utf-8")}function b(e){return Rn(e)}function ge(e){xo(e,{recursive:!0})}function Ft(e){let t=[nt(import.meta.dirname,"../../assets",e),nt(import.meta.dirname,"../assets",e),nt(process.cwd(),"assets",e)];for(let o of t)if(Rn(o))return o;throw new Error(`Asset not found: ${e}`)}function ot(){if(tt)return tt;let e=[nt(import.meta.dirname,"../../package.json"),nt(import.meta.dirname,"../package.json"),nt(process.cwd(),"package.json")];for(let t of e)if(Rn(t))try{let o=JSON.parse(wo(t,"utf-8"));if(o.name==="vibespot"&&o.version)return tt=o.version,tt}catch{}return tt="dev",tt}var tt,Q=Ze(()=>{"use strict";h();tt=""});import{join as Io}from"path";import{homedir as vr}from"os";function N(){if(!b(Pn))return{};try{let e=JSON.parse(v(Pn));return e.aiEngine==="api"&&(e.aiEngine="anthropic-api"),e}catch{return{}}}function he(e,t){let o=t||N();switch(e){case"anthropic-api":case"api":return o.anthropicApiKey||process.env.ANTHROPIC_API_KEY;case"openai-api":return o.openaiApiKey||process.env.OPENAI_API_KEY;case"gemini-api":return o.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY;default:return}}function On(e){return e.length<=12?"***":e.slice(0,7)+"..."+e.slice(-4)}function z(e){let o={...N(),...e};M(Pn,JSON.stringify(o,null,2))}function Ke(){let e=N();if(!e.hubspotAccounts?.length)return null;let t=e.activeHubSpotAccount;if(t){let o=e.hubspotAccounts.find(n=>n.portalId===t);if(o)return o}return e.hubspotAccounts[0]||null}function Ht(e,t,o,n){let i=N().hubspotAccounts||[],a=i.findIndex(l=>l.portalId===t),r={portalId:t,portalName:o,personalAccessKey:e,dataCenter:n,addedAt:new Date().toISOString()};a>=0?i[a]=r:i.push(r),z({hubspotAccounts:i,activeHubSpotAccount:t})}function To(e){let t=N(),o=(t.hubspotAccounts||[]).filter(s=>s.portalId!==e),n={hubspotAccounts:o};t.activeHubSpotAccount===e&&(n.activeHubSpotAccount=o[0]?.portalId||void 0),z(n)}function $o(e){z({activeHubSpotAccount:e})}function ue(){return Ke()?.personalAccessKey||null}function Lt(e){return N().enabledCLITools?.includes(e)??!1}function ko(e,t){let o=N(),n=new Set(o.enabledCLITools||[]);t?n.add(e):n.delete(e),z({enabledCLITools:[...n]})}var wr,Pn,Z=Ze(()=>{"use strict";h();Q();wr=Io(vr(),".vibespot"),Pn=Io(wr,"config.json")});import{readFileSync as Ar}from"fs";import{basename as Ir}from"path";async function Po(e){let t=Ro.get(e);if(t&&t.expiresAt-Date.now()>kr)return t;let o=await fetch(`${Me}/localdevauth/v1/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({encodedOAuthRefreshToken:e})});if(!o.ok){let i=await o.text().catch(()=>"");throw new Error(o.status===401||o.status===403?"Invalid or expired Personal Access Key":`Token exchange failed (${o.status}): ${i.slice(0,200)}`)}let n=await o.json(),s={accessToken:n.oauthAccessToken,expiresAt:n.expiresAtMillis,hubId:n.hubId,hubName:n.hubName||""};return Ro.set(e,s),s}async function st(e){let{accessToken:t}=await Po(e);return{Authorization:`Bearer ${t}`}}function Yt(e){return e.replace(/^\/+/,"").split("/").filter(Boolean).map(encodeURIComponent).join("/")}function Er(e){return e.startsWith("pat-eu1-")?"eu1":e.startsWith("pat-na1-")?"na1":e.startsWith("CiRldTE")?"eu1":"na1"}function Nr(e){return new Promise(t=>setTimeout(t,e))}async function At(e,t){let o=`HTTP ${e.status}`,n,s;try{let i=await e.json();if(i.message&&typeof i.message=="string"&&(o=i.message),i.category&&typeof i.category=="string"&&(n=i.category),i.errors&&Array.isArray(i.errors)&&i.errors.length>0){let a=i.errors[0];s=a.message||JSON.stringify(a)}}catch{try{let i=await e.text();i&&(o=i.slice(0,500))}catch{}}return{status:e.status,message:t?`${o} (${t})`:o,category:n,detail:s}}async function It(e,t,o=Tr){for(let n=0;n<=o;n++){let s=await fetch(e,t);if(s.status===429||s.status>=500&&n<o){let i=$r*Math.pow(2,n);await Nr(i);continue}return s}return fetch(e,t)}async function Vt(e){let t=await Po(e),o=`${Me}/account-info/v3/details`,n=await It(o,{headers:await st(e)});if(!n.ok){let r=await At(n);throw new Error(`Failed to get account info: ${r.message}`)}let s=await n.json(),i=String(s.portalId||t.hubId||""),a=t.hubName||s.uiDomain||i;return{portalId:i,portalName:a,dataCenter:Er(e)}}async function Oo(e,t,o){let n=Ar(o),s=Ir(o),i=new FormData,a=new Blob([n]);i.append("file",a,s);let r=`${Me}/cms/v3/source-code/published/content/${Yt(t)}`,l=await It(r,{method:"PUT",headers:await st(e),body:i});if(!l.ok){let c=await At(l,t);return{success:!1,path:t,error:c}}return{success:!0,path:t}}async function Jn(e,t){let o=`${Me}/cms/v3/source-code/published/content/${Yt(t)}`,n=await It(o,{method:"DELETE",headers:await st(e)});if(!n.ok&&n.status!==404){let s=await At(n,t);throw new Error(`Failed to delete ${t}: ${s.message}`)}}async function Mo(e,t){let o=`${Me}/cms/v3/source-code/published/content/${Yt(t)}`,n=await It(o,{method:"GET",headers:await st(e)});if(!n.ok){let i=await At(n,t);throw new Error(`Failed to download ${t}: ${i.message}`)}let s=await n.arrayBuffer();return Buffer.from(s)}async function zt(e,t){let o=`${Me}/cms/v3/source-code/published/metadata/${Yt(t)}`,n=await It(o,{method:"GET",headers:await st(e)});if(n.status===404)return null;if(!n.ok){let s=await At(n,t);throw new Error(`Failed to get metadata for ${t}: ${s.message}`)}return await n.json()}async function jo(e){let t=await st(e),o=[`${Me}/cms/v3/source-code/published/metadata`,`${Me}/cms/v3/source-code/published/metadata/`,`${Me}/designmanager/v1/portals/content/listing`];for(let n of o)try{let s=await fetch(n,{method:"GET",headers:t});if(s.ok){let i=await s.json(),a=i.children||i.objects||(Array.isArray(i)?i:null);if(a&&a.length>0)return a.filter(r=>r.folder)}}catch{}return[]}var Me,Tr,$r,kr,Ro,Ye=Ze(()=>{"use strict";h();Me="https://api.hubapi.com",Tr=3,$r=1e3,kr=300*1e3,Ro=new Map});var Go={};So(Go,{fetchTheme:()=>Tt});import{mkdirSync as Lo,writeFileSync as Or}from"fs";import{join as Mr,dirname as jr}from"path";async function Gn(e,t){let o=await zt(e,t);if(!o)return[];if(!o.folder)return[o.path||t];let n=[],s=o.children||[];for(let i of s){let a=typeof i=="string"?i:i.name;if(!a)continue;let r=`${t}/${a}`;if(typeof i=="string")n.push(...await Gn(e,r));else{let l=i;l.folder?n.push(...await Gn(e,l.path||r)):n.push(l.path||r)}}return n}async function Dr(e,t,o){let n=0;async function s(){for(;n<e.length;){let a=n++;await o(e[a])}}let i=Array.from({length:Math.min(t,e.length)},()=>s());await Promise.all(i)}async function Tt(e,t,o,n={}){let s=n.concurrency??5,i=await Gn(e,t);if(i.length===0)throw new Error(`Theme "${t}" not found on HubSpot or is empty`);Lo(o,{recursive:!0}),await Dr(i,s,async a=>{let r=a.startsWith(t+"/")?a.slice(t.length+1):a,l=Mr(o,r);Lo(jr(l),{recursive:!0});let c=await Mo(e,a);Or(l,c),n.onFile?.(r)})}var en=Ze(()=>{"use strict";h();Ye()});var po={};So(po,{collectThemeFiles:()=>Wi,extractDesignContext:()=>Il});import{existsSync as An,readdirSync as In,readFileSync as vl}from"fs";import{join as Re}from"path";import{spawn as wl}from"child_process";async function xl(){return uo||(uo=(await import("@anthropic-ai/sdk")).default),uo}function Dt(e){try{return vl(e,"utf-8")}catch{return""}}function Wi(e){let t=[],o=0;function n(r,l){if(!l.trim())return!0;let c=`
1
+ var ya=Object.defineProperty;var lt=(t,e)=>()=>(t&&(e=t(t=0)),e);var Vs=(t,e)=>{for(var n in e)ya(t,n,{get:e[n],enumerable:!0})};import _d from"path";import{fileURLToPath as Rd}from"url";var f=lt(()=>{"use strict"});import{readFileSync as zn,writeFileSync as ba,mkdirSync as zs,existsSync as zt}from"fs";import{dirname as Sa,join as He}from"path";function x(t){return zn(t,"utf-8")}function F(t,e){zs(Sa(t),{recursive:!0}),ba(t,e,"utf-8")}function S(t){return zt(t)}function we(t){zs(t,{recursive:!0})}function qt(t){let e=[He(import.meta.dirname,"../../assets",t),He(import.meta.dirname,"../assets",t),He(process.cwd(),"assets",t)];for(let n of e)if(zt(n))return n;throw new Error(`Asset not found: ${t}`)}function ut(){if(dt)return dt;let t=[He(import.meta.dirname,"../../package.json"),He(import.meta.dirname,"../package.json"),He(process.cwd(),"package.json")];for(let e of t)if(zt(e))try{let n=JSON.parse(zn(e,"utf-8"));if(n.name==="vibespot"&&n.version)return dt=n.version,dt}catch{}return dt="dev",dt}function qs(){if(Yt)return Yt;let t=[He(import.meta.dirname,"../../CHANGELOG.md"),He(import.meta.dirname,"../CHANGELOG.md"),He(process.cwd(),"CHANGELOG.md")];for(let e of t)if(zt(e))try{return Yt=zn(e,"utf-8"),Yt}catch{}return""}var dt,Yt,X=lt(()=>{"use strict";f();dt="";Yt=""});import{join as Zs}from"path";import{homedir as va}from"os";import{chmodSync as wa}from"fs";function E(){if(!S(Xt))return{};try{let t=JSON.parse(x(Xt));return t.aiEngine==="api"&&(t.aiEngine="anthropic-api"),t}catch{return{}}}function ge(t,e){let n=e||E();switch(t){case"anthropic-api":case"api":return n.anthropicApiKey||process.env.ANTHROPIC_API_KEY;case"openai-api":return n.openaiApiKey||process.env.OPENAI_API_KEY;case"gemini-api":return n.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY;default:return}}function qn(t){return t.length<=12?"***":t.slice(0,7)+"..."+t.slice(-4)}function Y(t){let n={...E(),...t};if(F(Xt,JSON.stringify(n,null,2)),process.platform!=="win32")try{wa(Xt,384)}catch{}}function Ze(){let t=E();if(!t.hubspotAccounts?.length)return null;let e=t.activeHubSpotAccount;if(e){let n=t.hubspotAccounts.find(s=>s.portalId===e);if(n)return n}return t.hubspotAccounts[0]||null}function Qt(t,e,n,s){let i=E().hubspotAccounts||[],a=i.findIndex(l=>l.portalId===e),r={portalId:e,portalName:n,personalAccessKey:t,dataCenter:s,addedAt:new Date().toISOString()};a>=0?i[a]=r:i.push(r),Y({hubspotAccounts:i,activeHubSpotAccount:e})}function eo(t){let e=E(),n=(e.hubspotAccounts||[]).filter(o=>o.portalId!==t),s={hubspotAccounts:n};e.activeHubSpotAccount===t&&(s.activeHubSpotAccount=n[0]?.portalId||void 0),Y(s)}function to(t){Y({activeHubSpotAccount:t})}function he(){return Ze()?.personalAccessKey||null}function Zt(t){return E().enabledCLITools?.includes(t)??!1}function no(t,e){let n=E(),s=new Set(n.enabledCLITools||[]);e?s.add(t):s.delete(t),Y({enabledCLITools:[...s]})}var xa,Xt,ee=lt(()=>{"use strict";f();X();xa=Zs(va(),".vibespot"),Xt=Zs(xa,"config.json")});import{readFileSync as Ia}from"fs";import{basename as ka}from"path";async function ao(t){let e=ro.get(t);if(e&&e.expiresAt-Date.now()>Ea)return e;let n=await fetch(`${Le}/localdevauth/v1/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({encodedOAuthRefreshToken:t})});if(!n.ok){let i=await n.text().catch(()=>"");throw new Error(n.status===401||n.status===403?"Invalid or expired Personal Access Key":`Token exchange failed (${n.status}): ${i.slice(0,200)}`)}let s=await n.json(),o={accessToken:s.oauthAccessToken,expiresAt:s.expiresAtMillis,hubId:s.hubId,hubName:s.hubName||""};return ro.set(t,o),o}async function mt(t){let{accessToken:e}=await ao(t);return{Authorization:`Bearer ${e}`}}function rn(t){return t.replace(/^\/+/,"").split("/").filter(Boolean).map(encodeURIComponent).join("/")}function Ma(t){return t.startsWith("pat-eu1-")?"eu1":t.startsWith("pat-na1-")?"na1":t.startsWith("CiRldTE")?"eu1":"na1"}function Na(t){return new Promise(e=>setTimeout(e,t))}async function _t(t,e){let n=`HTTP ${t.status}`,s,o;try{let i=await t.json();if(i.message&&typeof i.message=="string"&&(n=i.message),i.category&&typeof i.category=="string"&&(s=i.category),i.errors&&Array.isArray(i.errors)&&i.errors.length>0){let a=i.errors[0];o=a.message||JSON.stringify(a)}}catch{try{let i=await t.text();i&&(n=i.slice(0,500))}catch{}}return{status:t.status,message:e?`${n} (${e})`:n,category:s,detail:o}}async function Pt(t,e,n=$a){for(let s=0;s<=n;s++){let o=await fetch(t,e);if(o.status===429||o.status>=500&&s<n){let i=Ta*Math.pow(2,s);await Na(i);continue}return o}return fetch(t,e)}async function an(t){let e=await ao(t),n=`${Le}/account-info/v3/details`,s=await Pt(n,{headers:await mt(t)});if(!s.ok){let r=await _t(s);throw new Error(`Failed to get account info: ${r.message}`)}let o=await s.json(),i=String(o.portalId||e.hubId||""),a=e.hubName||o.uiDomain||i;return{portalId:i,portalName:a,dataCenter:Ma(t)}}async function lo(t,e,n){let s=Ia(n),o=ka(n),i=new FormData,a=new Blob([s]);i.append("file",a,o);let r=`${Le}/cms/v3/source-code/published/content/${rn(e)}`,l=await Pt(r,{method:"PUT",headers:await mt(t),body:i});if(!l.ok){let c=await _t(l,e);return{success:!1,path:e,error:c}}return{success:!0,path:e}}async function es(t,e){let n=`${Le}/cms/v3/source-code/published/content/${rn(e)}`,s=await Pt(n,{method:"DELETE",headers:await mt(t)});if(!s.ok&&s.status!==404){let o=await _t(s,e);throw new Error(`Failed to delete ${e}: ${o.message}`)}}async function co(t,e){let n=`${Le}/cms/v3/source-code/published/content/${rn(e)}`,s=await Pt(n,{method:"GET",headers:await mt(t)});if(!s.ok){let i=await _t(s,e);throw new Error(`Failed to download ${e}: ${i.message}`)}let o=await s.arrayBuffer();return Buffer.from(o)}async function ln(t,e){let n=`${Le}/cms/v3/source-code/published/metadata/${rn(e)}`,s=await Pt(n,{method:"GET",headers:await mt(t)});if(s.status===404)return null;if(!s.ok){let o=await _t(s,e);throw new Error(`Failed to get metadata for ${e}: ${o.message}`)}return await s.json()}async function uo(t){let e=await mt(t),n=[`${Le}/cms/v3/source-code/published/metadata`,`${Le}/cms/v3/source-code/published/metadata/`,`${Le}/designmanager/v1/portals/content/listing`];for(let s of n)try{let o=await fetch(s,{method:"GET",headers:e});if(o.ok){let i=await o.json(),a=i.children||i.objects||(Array.isArray(i)?i:null);if(a&&a.length>0)return a.filter(r=>r.folder)}}catch{}return[]}var Le,$a,Ta,Ea,ro,tt=lt(()=>{"use strict";f();Le="https://api.hubapi.com",$a=3,Ta=1e3,Ea=300*1e3,ro=new Map});var yo={};Vs(yo,{fetchTheme:()=>Rt});import{mkdirSync as ho,writeFileSync as Oa}from"fs";import{join as ja,dirname as Fa}from"path";async function os(t,e){let n=await ln(t,e);if(!n)return[];if(!n.folder)return[n.path||e];let s=[],o=n.children||[];for(let i of o){let a=typeof i=="string"?i:i.name;if(!a)continue;let r=`${e}/${a}`;if(typeof i=="string")s.push(...await os(t,r));else{let l=i;l.folder?s.push(...await os(t,l.path||r)):s.push(l.path||r)}}return s}async function Ja(t,e,n){let s=0;async function o(){for(;s<t.length;){let a=s++;await n(t[a])}}let i=Array.from({length:Math.min(e,t.length)},()=>o());await Promise.all(i)}async function Rt(t,e,n,s={}){let o=s.concurrency??5,i=await os(t,e);if(i.length===0)throw new Error(`Theme "${e}" not found on HubSpot or is empty`);ho(n,{recursive:!0}),await Ja(i,o,async a=>{let r=a.startsWith(e+"/")?a.slice(e.length+1):a,l=ja(n,r);ho(Fa(l),{recursive:!0});let c=await co(t,a);Oa(l,c),s.onFile?.(r)})}var pn=lt(()=>{"use strict";f();tt()});var Hs={};Vs(Hs,{collectThemeFiles:()=>Wr,extractDesignContext:()=>ud});import{existsSync as Gn,readdirSync as Un,readFileSync as rd}from"fs";import{join as Fe}from"path";import{spawn as ad}from"child_process";async function ld(){return Js||(Js=(await import("@anthropic-ai/sdk")).default),Js}function Vt(t){try{return rd(t,"utf-8")}catch{return""}}function Wr(t){let e=[],n=0;function s(r,l){if(!l.trim())return!0;let c=`
2
2
  ### ${r}
3
3
  \`\`\`
4
4
  ${l}
5
5
  \`\`\`
6
- `;return o+c.length>Cl?!1:(t.push(c),o+=c.length,!0)}let s=Dt(Re(e,"theme.json"));s&&n("theme.json",s);let i=Re(e,"css");if(An(i)){for(let r of In(i).filter(l=>l.endsWith(".css")))if(!n(`css/${r}`,Dt(Re(i,r))))break}let a=Re(e,"modules");if(An(a))for(let r of In(a).filter(l=>l.endsWith(".module"))){let l=Re(a,r),c=Dt(Re(l,"module.css"));if(c&&!n(`modules/${r}/module.css`,c))break}if(An(a))for(let r of In(a).filter(l=>l.endsWith(".module"))){let l=Re(a,r),c=Dt(Re(l,"module.html"));if(c&&!n(`modules/${r}/module.html`,c))break}if(An(a))for(let r of In(a).filter(l=>l.endsWith(".module"))){let l=Re(a,r),c=Dt(Re(l,"fields.json"));if(c&&!n(`modules/${r}/fields.json`,c))break}return t.join("")}function Al(){if(!Tn)try{Tn=v(Ft("extraction-prompt.md"))}catch{Tn=""}return Tn}function mo(e,t,o){return new Promise((n,s)=>{let i={...process.env};delete i.CLAUDECODE;let a=wl(e,t,{stdio:["pipe","pipe","pipe"],env:i,shell:!0}),r="",l="";a.stdout.on("data",c=>{r+=c.toString()}),a.stderr.on("data",c=>{l+=c.toString()}),a.on("error",c=>s(new Error(`${e} failed to start: ${c.message}`))),a.on("close",c=>{c===0||r.trim()?n(r.trim()):s(new Error(`${e} exited with code ${c}: ${l.trim()}`))}),a.stdin.write(o),a.stdin.end()})}async function Il(e,t){t?.({status:"Collecting theme files..."});let o=Wi(e);if(!o.trim())throw new Error("No CSS, HTML, or fields.json files found in theme.");let n=Al();if(!n)throw new Error("Extraction prompt not found (assets/extraction-prompt.md).");let s=`Analyze this HubSpot CMS theme and extract the design system:
7
- ${o}`;t?.({status:"Analyzing design patterns..."});let i=N(),a=i.aiEngine||"anthropic-api",r="";switch(a){case"anthropic-api":case"api":{let l=he("anthropic-api");if(!l)throw new Error("Anthropic API key not configured. Open Settings to add one.");let c=await xl();r=(await new c({apiKey:l}).messages.create({model:i.anthropicApiModel||"claude-sonnet-4-6",max_tokens:8e3,system:n,messages:[{role:"user",content:s}]})).content.filter(f=>f.type==="text").map(f=>f.text).join("");break}case"openai-api":{let l=he("openai-api");if(!l)throw new Error("OpenAI API key not configured. Open Settings to add one.");let c=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`},body:JSON.stringify({model:i.openaiApiModel||"gpt-4o",max_tokens:8e3,messages:[{role:"system",content:n},{role:"user",content:s}]})});if(!c.ok)throw new Error(`OpenAI API error: ${c.status} ${await c.text()}`);r=(await c.json()).choices?.[0]?.message?.content||"";break}case"gemini-api":{let l=he("gemini-api");if(!l)throw new Error("Gemini API key not configured. Open Settings to add one.");let c=i.geminiApiModel||"gemini-2.5-flash",u=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${c}:generateContent?key=${l}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({system_instruction:{parts:[{text:n}]},contents:[{role:"user",parts:[{text:s}]}],generationConfig:{maxOutputTokens:8e3}})});if(!u.ok)throw new Error(`Gemini API error: ${u.status} ${await u.text()}`);r=(await u.json()).candidates?.[0]?.content?.parts?.map(f=>f.text).join("")||"";break}case"claude-code":{let l=`${n}
6
+ `;return n+c.length>cd?!1:(e.push(c),n+=c.length,!0)}let o=Vt(Fe(t,"theme.json"));o&&s("theme.json",o);let i=Fe(t,"css");if(Gn(i)){for(let r of Un(i).filter(l=>l.endsWith(".css")))if(!s(`css/${r}`,Vt(Fe(i,r))))break}let a=Fe(t,"modules");if(Gn(a))for(let r of Un(a).filter(l=>l.endsWith(".module"))){let l=Fe(a,r),c=Vt(Fe(l,"module.css"));if(c&&!s(`modules/${r}/module.css`,c))break}if(Gn(a))for(let r of Un(a).filter(l=>l.endsWith(".module"))){let l=Fe(a,r),c=Vt(Fe(l,"module.html"));if(c&&!s(`modules/${r}/module.html`,c))break}if(Gn(a))for(let r of Un(a).filter(l=>l.endsWith(".module"))){let l=Fe(a,r),c=Vt(Fe(l,"fields.json"));if(c&&!s(`modules/${r}/fields.json`,c))break}return e.join("")}function dd(){if(!Wn)try{Wn=x(qt("extraction-prompt.md"))}catch{Wn=""}return Wn}function Ds(t,e,n){return new Promise((s,o)=>{let i={...process.env};delete i.CLAUDECODE;let a=ad(t,e,{stdio:["pipe","pipe","pipe"],env:i,shell:!0}),r="",l="";a.stdout.on("data",c=>{r+=c.toString()}),a.stderr.on("data",c=>{l+=c.toString()}),a.on("error",c=>o(new Error(`${t} failed to start: ${c.message}`))),a.on("close",c=>{c===0||r.trim()?s(r.trim()):o(new Error(`${t} exited with code ${c}: ${l.trim()}`))}),a.stdin.write(n),a.stdin.end()})}async function ud(t,e){e?.({status:"Collecting theme files..."});let n=Wr(t);if(!n.trim())throw new Error("No CSS, HTML, or fields.json files found in theme.");let s=dd();if(!s)throw new Error("Extraction prompt not found (assets/extraction-prompt.md).");let o=`Analyze this HubSpot CMS theme and extract the design system:
7
+ ${n}`;e?.({status:"Analyzing design patterns..."});let i=E(),a=i.aiEngine||"anthropic-api",r="";switch(a){case"anthropic-api":case"api":{let l=ge("anthropic-api");if(!l)throw new Error("Anthropic API key not configured. Open Settings to add one.");let c=await ld();r=(await new c({apiKey:l}).messages.create({model:i.anthropicApiModel||"claude-sonnet-4-6",max_tokens:8e3,system:s,messages:[{role:"user",content:o}]})).content.filter(p=>p.type==="text").map(p=>p.text).join("");break}case"openai-api":{let l=ge("openai-api");if(!l)throw new Error("OpenAI API key not configured. Open Settings to add one.");let c=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`},body:JSON.stringify({model:i.openaiApiModel||"gpt-4o",max_tokens:8e3,messages:[{role:"system",content:s},{role:"user",content:o}]})});if(!c.ok)throw new Error(`OpenAI API error: ${c.status} ${await c.text()}`);r=(await c.json()).choices?.[0]?.message?.content||"";break}case"gemini-api":{let l=ge("gemini-api");if(!l)throw new Error("Gemini API key not configured. Open Settings to add one.");let c=i.geminiApiModel||"gemini-2.5-flash",d=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${c}:generateContent?key=${l}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({system_instruction:{parts:[{text:s}]},contents:[{role:"user",parts:[{text:o}]}],generationConfig:{maxOutputTokens:8e3}})});if(!d.ok)throw new Error(`Gemini API error: ${d.status} ${await d.text()}`);r=(await d.json()).candidates?.[0]?.content?.parts?.map(p=>p.text).join("")||"";break}case"claude-code":{let l=`${s}
8
8
 
9
9
  ## User Request
10
- ${s}`,c=["--print"];i.claudeCodeModel&&c.push("--model",i.claudeCodeModel),r=await mo("claude",c,l);break}case"gemini-cli":{let l=`${n}
10
+ ${o}`,c=["--print"];i.claudeCodeModel&&c.push("--model",i.claudeCodeModel),r=await Ds("claude",c,l);break}case"gemini-cli":{let l=`${s}
11
11
 
12
12
  ## User Request
13
- ${s}`;r=await mo("gemini",[],l);break}case"codex-cli":{let l=`${n}
13
+ ${o}`;r=await Ds("gemini",[],l);break}case"codex-cli":{let l=`${s}
14
14
 
15
15
  ## User Request
16
- ${s}`;r=await mo("codex",[],l);break}default:throw new Error(`Unknown AI engine: ${a}. Open Settings to configure one.`)}if(!r.trim())throw new Error("AI returned empty response.");return t?.({status:"Design extraction complete."}),r}var uo,Cl,Tn,fo=Ze(()=>{"use strict";h();Q();Z();uo=null;Cl=8e4;Tn=""});h();h();import{Command as Ll}from"commander";h();h();h();import et from"chalk";var Ie={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},vo=!!process.env.NO_COLOR;function Oe(e){return vo?et:et.hex(e)}var C={accent:Oe(Ie.accent),accentBright:Oe(Ie.accentBright),success:Oe(Ie.success),info:Oe(Ie.info),warn:Oe(Ie.warn),error:Oe(Ie.error),muted:Oe(Ie.muted),vibes:Oe(Ie.vibes),heading:vo?et.bold:et.bold.hex(Ie.accent),command:Oe(Ie.accentBright),dim:et.dim,bold:et.bold};Q();function Te(){let e=C.vibes,t=C.accent,o=C.muted,n=[`${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584\u2584")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${t("\u2584\u2584\u2584\u2584\u2584 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584 \u2580\u2580\u2588\u2588\u2580\u2580")}`,`${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 ")}${e(" \u224B\u224B\u224B\u224B ")}${t("\u2580\u2580\u2580\u2584 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${e(" \u2588\u2584\u2584\u2588\u2580 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${t(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${e(" \u2580\u2580\u2580 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2580\u2580\u2580\u2580\u2580")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${t("\u2580\u2580\u2580\u2580 \u2588\u2588 \u2580\u2580\u2580\u2580 \u2588\u2588 ")}`];console.log();for(let s of n)console.log(` ${s}`);console.log(),console.log(` ${o("AI-powered HubSpot Landing Pages")} ${C.dim(`v${ot()}`)}`),console.log()}h();h();import{join as Gt}from"path";import{homedir as Ut}from"os";import{readFileSync as Eo,existsSync as Wt,readdirSync as xr}from"fs";h();import{execSync as Co}from"child_process";function A(e,t={}){try{return{stdout:Co(e,{encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:12e4,...t}).trim(),stderr:"",success:!0}}catch(o){let n=o,s=(n.stdout??"").toString().trim(),i=(n.stderr??"").toString().trim();return{stdout:s,stderr:i,success:!1}}}function Ao(e,t={}){try{return Co(e,{stdio:"inherit",timeout:3e5,...t}),!0}catch{return!1}}Z();var Be=process.platform==="win32"?"where":"which";function bt(){let e=A("node --version");return{name:"Node.js",found:e.success,version:e.stdout.replace(/^v/,""),path:A(`${Be} node`).stdout}}function St(){let e=A("git --version");return{name:"Git",found:e.success,version:e.stdout.replace("git version ",""),path:A(`${Be} git`).stdout}}function $e(){let e=A("hs --version");return{name:"HubSpot CLI",found:e.success,version:e.stdout,path:A(`${Be} hs`).stdout}}function vt(){let e=A("claude --version");if(!e.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=Gt(Ut(),".claude"),o=!1,n="Not signed in \u2014 run `claude` to authenticate";try{if(Wt(t)){let s=xr(t);(s.some(a=>a.includes("credentials")||a.includes("auth")||a.includes("token")||a===".credentials.json")||s.length>2)&&(o=!0,n="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:e.stdout,path:A(`${Be} claude`).stdout,authenticated:o,authDetail:n}}function wt(e){try{let t=Gt(Ut(),".hscli","config.yml");if(!Wt(t))return"na1";let o=Eo(t,"utf-8"),n=o.indexOf(`accountId: ${e}`);if(n===-1)return"na1";let s=o.indexOf("personalAccessKey:",n);if(s===-1)return"na1";let a=o.slice(s,s+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!a)return"na1";if(a[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function ke(){let e=A("hs accounts list");if(!e.success||!e.stdout)return{authenticated:!1,portalName:"",portalId:"",accounts:[]};let t=[],o="",n="",s=e.stdout.match(/Account:\s*(.+?)\s*\((\d+)\)/);s&&(o=s[1].trim(),n=s[2].trim());let i=e.stdout.split(`
17
- `);for(let a of i){let r=a.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(r&&!/Account ID/i.test(a)&&!/^-+$/.test(a.trim())&&!/^Name\s/i.test(a.trim())){let l=r[1].trim(),c=r[2].trim(),u=r[3]?.trim()||"unknown";t.push({name:l,portalId:c,authType:u,isDefault:c===n})}}return s?{authenticated:!0,portalName:o,portalId:n,accounts:t}:t.length>0?{authenticated:!0,portalName:t[0].name,portalId:t[0].portalId,accounts:t}:{authenticated:e.stdout.length>0,portalName:"",portalId:"",accounts:[]}}function xt(){let e=A("gemini --version");if(!e.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=Gt(Ut(),".config","gcloud","application_default_credentials.json"),o=Wt(t),n=!!(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||process.env.GOOGLE_AI_API_KEY),s=o||n;return{name:"Gemini CLI",found:!0,version:e.stdout,path:A(`${Be} gemini`).stdout,authenticated:s,authDetail:s?"Authenticated":"Run `gemini` to sign in with Google"}}function Ct(){let e=A("codex --version");if(!e.success)return{name:"OpenAI Codex CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=!!process.env.OPENAI_API_KEY,o=!1;try{let i=Gt(Ut(),".codex","auth.json");Wt(i)&&(o=Eo(i,"utf-8").length>10)}catch{}let n=t||o,s=o?"Authenticated (OAuth)":t?"Authenticated (API key)":"Not authenticated";return{name:"OpenAI Codex CLI",found:!0,version:e.stdout,path:A(`${Be} codex`).stdout,authenticated:n,authDetail:s}}function jn(){let e=A("gh --version");return{name:"GitHub CLI",found:e.success,version:e.stdout.split(`
18
- `)[0]?.replace("gh version ","").split(" ")[0]||"",path:A(`${Be} gh`).stdout}}function Dn(){let e=A("gh auth status 2>&1");if(!e.success&&!e.stdout)return{authenticated:!1,username:""};let t=e.stdout||e.stderr||"",o=t.match(/Logged in to github\.com.*account\s+(\S+)/);if(o)return{authenticated:!0,username:o[1]};let n=t.match(/account\s+(\S+)/);return n&&t.includes("Logged in")?{authenticated:!0,username:n[1]}:{authenticated:t.includes("Logged in"),username:""}}function No(){return!!process.env.ANTHROPIC_API_KEY}function Kt(e){return parseInt(e.split(".")[0],10)>=18}function _o(e){let t=parseInt(e.split(".")[0],10);return!isNaN(t)&&t>=8}function Cr(){let e=N(),t=e.hubspotUploadMode||"api",o=e.hubspotAccounts||[],n=o.map(i=>({name:i.portalName,portalId:i.portalId,authType:"personalaccesskey",isDefault:i.portalId===(e.activeHubSpotAccount||o[0]?.portalId)})),s=Ke();return{authenticated:!!s,portalName:s?.portalName||"",portalId:s?.portalId||"",dataCenter:s?s.dataCenter:"na1",accounts:n,uploadMode:t}}var Mn={name:"",found:!1,version:"",path:"",authenticated:!1,authDetail:"Disabled"};function Bt(){let e=N(),t=bt(),o=St(),n=e.hubspotUploadMode||"api",s;if(n==="cli"){let w=$e(),k=w.found?ke():{authenticated:!1,portalName:"",portalId:"",accounts:[]},E=k.portalId?wt(k.portalId):"na1";s={...w,...k,dataCenter:E,uploadMode:"cli"}}else s={name:"HubSpot API",found:!0,version:"v3",path:"",...Cr()};let i=jn(),a=i.found?Dn():{authenticated:!1,username:""},r=e.enabledCLITools||[],l=Lt("claude-code")?vt():{...Mn,name:"Claude Code"},c=Lt("gemini-cli")?xt():{...Mn,name:"Gemini CLI"},u=Lt("codex-cli")?Ct():{...Mn,name:"OpenAI Codex CLI"};function p(w,...k){if(w)return{configured:!0,masked:On(w),source:"config"};for(let E of k)if(process.env[E])return{configured:!0,masked:On(process.env[E]),source:"env"};return{configured:!1,masked:"",source:null}}let f=p(e.anthropicApiKey,"ANTHROPIC_API_KEY"),g=p(e.openaiApiKey,"OPENAI_API_KEY"),y=p(e.geminiApiKey,"GEMINI_API_KEY","GOOGLE_AI_API_KEY"),S=[];return l.found&&l.authenticated&&S.push("claude-code"),f.configured&&S.push("anthropic-api"),g.configured&&S.push("openai-api"),c.found&&c.authenticated&&S.push("gemini-cli"),y.configured&&S.push("gemini-api"),u.found&&u.authenticated&&S.push("codex-cli"),{tools:{node:t,git:o,hubspot:s,github:{...i,...a},claudeCode:l,geminiCli:c,codexCli:u},apiKeys:{anthropic:f,openai:g,gemini:y},activeEngine:e.aiEngine||null,availableEngines:S,enabledCLITools:r}}Z();Ye();h();import*as U from"@clack/prompts";function Fn(e){U.isCancel(e)&&(U.cancel(C.muted("Operation cancelled.")),process.exit(0))}async function re(e){U.intro(C.heading(e))}async function ae(e){U.outro(C.success(e))}async function Ee(e,t){U.note(e,t?C.heading(t):void 0)}async function ve(e){let t=await U.text({message:C.accent(e.message),placeholder:e.placeholder,defaultValue:e.defaultValue,validate:e.validate});return Fn(t),t}async function ee(e){let t=await U.confirm({message:C.accent(e.message),initialValue:e.initialValue??!0});return Fn(t),t}async function it(e){let t=await U.select({message:C.accent(e.message),options:e.options});return Fn(t),t}async function le(){let e=U.spinner();return{start:t=>e.start(C.muted(t)),stop:t=>e.stop(C.success(t)),message:t=>e.message(C.muted(t))}}function B(e){U.log.info(e)}function P(e){U.log.success(C.success(e))}function W(e){U.log.warn(C.warn(e))}function D(e){U.log.error(C.error(e))}async function qt(){await re("Checking your environment");let e=bt();e.found||(D("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),Kt(e.version)||(D(`Node.js ${e.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),P(`Node.js v${e.version}`);let t=St();t.found||(D("Git not found. Install it from https://git-scm.com"),process.exit(1)),P(`Git ${t.version}`);let o=N(),n=o.hubspotUploadMode!=="cli",s="",i="";if(n){let S=ue(),w=Ke();if(S)s=w?.portalId||"",i=w?.portalName||"",P(`HubSpot${i?`: ${i}`:""}${s?` (${s})`:""} \u2014 API mode`);else{W("No HubSpot account connected"),await Ee(`You need a Personal Access Key to deploy themes.
16
+ ${o}`;r=await Ds("codex",[],l);break}default:throw new Error(`Unknown AI engine: ${a}. Open Settings to configure one.`)}if(!r.trim())throw new Error("AI returned empty response.");return e?.({status:"Design extraction complete."}),r}var Js,cd,Wn,Ls=lt(()=>{"use strict";f();X();ee();Js=null;cd=8e4;Wn=""});f();f();import{Command as Td}from"commander";f();f();f();import ct from"chalk";var Te={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},Ys=!!process.env.NO_COLOR;function De(t){return Ys?ct:ct.hex(t)}var k={accent:De(Te.accent),accentBright:De(Te.accentBright),success:De(Te.success),info:De(Te.info),warn:De(Te.warn),error:De(Te.error),muted:De(Te.muted),vibes:De(Te.vibes),heading:Ys?ct.bold:ct.bold.hex(Te.accent),command:De(Te.accentBright),dim:ct.dim,bold:ct.bold};X();function Ee(){let t=k.vibes,e=k.accent,n=k.muted,s=[`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584\u2584")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2584\u2584\u2584\u2584\u2584 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584 \u2580\u2580\u2588\u2588\u2580\u2580")}`,`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B ")}${e("\u2580\u2580\u2580\u2584 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t(" \u2588\u2584\u2584\u2588\u2580 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${e(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t(" \u2580\u2580\u2580 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2580\u2580\u2580\u2580\u2580")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2580\u2580\u2580\u2580 \u2588\u2588 \u2580\u2580\u2580\u2580 \u2588\u2588 ")}`];console.log();for(let o of s)console.log(` ${o}`);console.log(),console.log(` ${n("AI-powered HubSpot Landing Pages")} ${k.dim(`v${ut()}`)}`),console.log()}f();f();import{join as en}from"path";import{homedir as tn}from"os";import{readFileSync as so,existsSync as nn,readdirSync as Ca}from"fs";f();import{execSync as Xs}from"child_process";function $(t,e={}){try{return{stdout:Xs(t,{encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:12e4,...e}).trim(),stderr:"",success:!0}}catch(n){let s=n,o=(s.stdout??"").toString().trim(),i=(s.stderr??"").toString().trim();return{stdout:o,stderr:i,success:!1}}}function Qs(t,e={}){try{return Xs(t,{stdio:"inherit",timeout:3e5,...e}),!0}catch{return!1}}ee();var et=process.platform==="win32"?"where":"which";function kt(){let t=$("node --version");return{name:"Node.js",found:t.success,version:t.stdout.replace(/^v/,""),path:$(`${et} node`).stdout}}function $t(){let t=$("git --version");return{name:"Git",found:t.success,version:t.stdout.replace("git version ",""),path:$(`${et} git`).stdout}}function Me(){let t=$("hs --version");return{name:"HubSpot CLI",found:t.success,version:t.stdout,path:$(`${et} hs`).stdout}}function Tt(){let t=$("claude --version");if(!t.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=en(tn(),".claude"),n=!1,s="Not signed in \u2014 run `claude` to authenticate";try{if(nn(e)){let o=Ca(e);(o.some(a=>a.includes("credentials")||a.includes("auth")||a.includes("token")||a===".credentials.json")||o.length>2)&&(n=!0,s="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:t.stdout,path:$(`${et} claude`).stdout,authenticated:n,authDetail:s}}function Et(t){try{let e=en(tn(),".hscli","config.yml");if(!nn(e))return"na1";let n=so(e,"utf-8"),s=n.indexOf(`accountId: ${t}`);if(s===-1)return"na1";let o=n.indexOf("personalAccessKey:",s);if(o===-1)return"na1";let a=n.slice(o,o+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!a)return"na1";if(a[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function Ne(){let t=$("hs accounts list");if(!t.success||!t.stdout)return{authenticated:!1,portalName:"",portalId:"",accounts:[]};let e=[],n="",s="",o=t.stdout.match(/Account:\s*(.+?)\s*\((\d+)\)/);o&&(n=o[1].trim(),s=o[2].trim());let i=t.stdout.split(`
17
+ `);for(let a of i){let r=a.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(r&&!/Account ID/i.test(a)&&!/^-+$/.test(a.trim())&&!/^Name\s/i.test(a.trim())){let l=r[1].trim(),c=r[2].trim(),d=r[3]?.trim()||"unknown";e.push({name:l,portalId:c,authType:d,isDefault:c===s})}}return o?{authenticated:!0,portalName:n,portalId:s,accounts:e}:e.length>0?{authenticated:!0,portalName:e[0].name,portalId:e[0].portalId,accounts:e}:{authenticated:t.stdout.length>0,portalName:"",portalId:"",accounts:[]}}function Mt(){let t=$("gemini --version");if(!t.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=en(tn(),".config","gcloud","application_default_credentials.json"),n=nn(e),s=!!(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||process.env.GOOGLE_AI_API_KEY),o=n||s;return{name:"Gemini CLI",found:!0,version:t.stdout,path:$(`${et} gemini`).stdout,authenticated:o,authDetail:o?"Authenticated":"Run `gemini` to sign in with Google"}}function Nt(){let t=$("codex --version");if(!t.success)return{name:"OpenAI Codex CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=!!process.env.OPENAI_API_KEY,n=!1;try{let i=en(tn(),".codex","auth.json");nn(i)&&(n=so(i,"utf-8").length>10)}catch{}let s=e||n,o=n?"Authenticated (OAuth)":e?"Authenticated (API key)":"Not authenticated";return{name:"OpenAI Codex CLI",found:!0,version:t.stdout,path:$(`${et} codex`).stdout,authenticated:s,authDetail:o}}function Qn(){let t=$("gh --version");return{name:"GitHub CLI",found:t.success,version:t.stdout.split(`
18
+ `)[0]?.replace("gh version ","").split(" ")[0]||"",path:$(`${et} gh`).stdout}}function Zn(){let t=$("gh auth status 2>&1");if(!t.success&&!t.stdout)return{authenticated:!1,username:""};let e=t.stdout||t.stderr||"",n=e.match(/Logged in to github\.com.*account\s+(\S+)/);if(n)return{authenticated:!0,username:n[1]};let s=e.match(/account\s+(\S+)/);return s&&e.includes("Logged in")?{authenticated:!0,username:s[1]}:{authenticated:e.includes("Logged in"),username:""}}function oo(){return!!process.env.ANTHROPIC_API_KEY}function sn(t){return parseInt(t.split(".")[0],10)>=18}function io(t){let e=parseInt(t.split(".")[0],10);return!isNaN(e)&&e>=8}function Aa(){let t=E(),e=t.hubspotUploadMode||"api",n=t.hubspotAccounts||[],s=n.map(i=>({name:i.portalName,portalId:i.portalId,authType:"personalaccesskey",isDefault:i.portalId===(t.activeHubSpotAccount||n[0]?.portalId)})),o=Ze();return{authenticated:!!o,portalName:o?.portalName||"",portalId:o?.portalId||"",dataCenter:o?o.dataCenter:"na1",accounts:s,uploadMode:e}}var Xn={name:"",found:!1,version:"",path:"",authenticated:!1,authDetail:"Disabled"};function on(){let t=E(),e=kt(),n=$t(),s=t.hubspotUploadMode||"api",o;if(s==="cli"){let y=Me(),w=y.found?Ne():{authenticated:!1,portalName:"",portalId:"",accounts:[]},I=w.portalId?Et(w.portalId):"na1";o={...y,...w,dataCenter:I,uploadMode:"cli"}}else o={name:"HubSpot API",found:!0,version:"v3",path:"",...Aa()};let i=Qn(),a=i.found?Zn():{authenticated:!1,username:""},r=t.enabledCLITools||[],l=Zt("claude-code")?Tt():{...Xn,name:"Claude Code"},c=Zt("gemini-cli")?Mt():{...Xn,name:"Gemini CLI"},d=Zt("codex-cli")?Nt():{...Xn,name:"OpenAI Codex CLI"};function u(y,...w){if(y)return{configured:!0,masked:qn(y),source:"config"};for(let I of w)if(process.env[I])return{configured:!0,masked:qn(process.env[I]),source:"env"};return{configured:!1,masked:"",source:null}}let p=u(t.anthropicApiKey,"ANTHROPIC_API_KEY"),g=u(t.openaiApiKey,"OPENAI_API_KEY"),h=u(t.geminiApiKey,"GEMINI_API_KEY","GOOGLE_AI_API_KEY"),b=[];return l.found&&l.authenticated&&b.push("claude-code"),p.configured&&b.push("anthropic-api"),g.configured&&b.push("openai-api"),c.found&&c.authenticated&&b.push("gemini-cli"),h.configured&&b.push("gemini-api"),d.found&&d.authenticated&&b.push("codex-cli"),{tools:{node:e,git:n,hubspot:o,github:{...i,...a},claudeCode:l,geminiCli:c,codexCli:d},apiKeys:{anthropic:p,openai:g,gemini:h},activeEngine:t.aiEngine||null,availableEngines:b,enabledCLITools:r}}ee();tt();f();import*as B from"@clack/prompts";function ts(t){B.isCancel(t)&&(B.cancel(k.muted("Operation cancelled.")),process.exit(0))}async function le(t){B.intro(k.heading(t))}async function ce(t){B.outro(k.success(t))}async function _e(t,e){B.note(t,e?k.heading(e):void 0)}async function Ae(t){let e=await B.text({message:k.accent(t.message),placeholder:t.placeholder,defaultValue:t.defaultValue,validate:t.validate});return ts(e),e}async function ne(t){let e=await B.confirm({message:k.accent(t.message),initialValue:t.initialValue??!0});return ts(e),e}async function pt(t){let e=await B.select({message:k.accent(t.message),options:t.options});return ts(e),e}async function de(){let t=B.spinner();return{start:e=>t.start(k.muted(e)),stop:e=>t.stop(k.success(e)),message:e=>t.message(k.muted(e))}}function z(t){B.log.info(t)}function P(t){B.log.success(k.success(t))}function K(t){B.log.warn(k.warn(t))}function U(t){B.log.error(k.error(t))}async function cn(){await le("Checking your environment");let t=kt();t.found||(U("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),sn(t.version)||(U(`Node.js ${t.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),P(`Node.js v${t.version}`);let e=$t();e.found||(U("Git not found. Install it from https://git-scm.com"),process.exit(1)),P(`Git ${e.version}`);let n=E(),s=n.hubspotUploadMode!=="cli",o="",i="";if(s){let b=he(),y=Ze();if(b)o=y?.portalId||"",i=y?.portalName||"",P(`HubSpot${i?`: ${i}`:""}${o?` (${o})`:""} \u2014 API mode`);else{K("No HubSpot account connected"),await _e(`You need a Personal Access Key to deploy themes.
19
19
  Create one at: https://app.hubspot.com/l/personal-access-key
20
- Make sure the Content scope is enabled.`,"HubSpot connection required");let k=await ve({message:"Paste your Personal Access Key:",placeholder:"pat-na1-...",validate:R=>R.trim()?void 0:"Key is required"}),E=await le();E.start("Validating key...");try{let R=await Vt(k);Ht(k,R.portalId,R.portalName,R.dataCenter),S=k,s=R.portalId,i=R.portalName,E.stop(`Connected to ${R.portalName} (${R.portalId})`)}catch(R){E.stop("Validation failed"),D(`Invalid key: ${R instanceof Error?R.message:String(R)}`),process.exit(1)}}}else{let S=$e();if(S.found)P(`HubSpot CLI v${S.version}`);else{W("HubSpot CLI not found"),await ee({message:"Install HubSpot CLI globally?"})||(D("HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli"),process.exit(1));let E=await le();E.start("Installing HubSpot CLI..."),A("npm install -g @hubspot/cli").success||(E.stop("Failed"),D("Try: npm install -g @hubspot/cli"),process.exit(1)),S=$e(),E.stop(`HubSpot CLI v${S.version} installed`)}let w=ke();if(w.authenticated)P(`HubSpot portal${w.portalName?`: ${w.portalName}`:""} (ID: ${w.portalId})`);else{W("HubSpot not authenticated"),await ee({message:"Run `hs init` now?"})||(D("Run `hs init` manually."),process.exit(1));let E=await le();E.start("Waiting for HubSpot authentication..."),Ao("hs init")||(E.stop("Authentication failed"),process.exit(1)),w=ke(),E.stop(`Connected to portal${w.portalName?`: ${w.portalName}`:""} (ID: ${w.portalId})`)}s=w.portalId,i=w.portalName}let a=vt(),r=xt(),l=Ct(),c=No(),u={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"},p,f=o.aiEngine,g=[];if(a.found&&g.push({value:"claude-code",label:"Claude Code",hint:f==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),r.found&&g.push({value:"gemini-cli",label:"Gemini CLI",hint:f==="gemini-cli"?"last used":"uses your existing Gemini setup"}),l.found&&g.push({value:"codex-cli",label:"OpenAI Codex",hint:f==="codex-cli"?"last used":"uses your existing OpenAI setup"}),c&&g.push({value:"api",label:"Anthropic API",hint:f==="api"?"last used":"uses your API key"}),f&&g.sort((S,w)=>S.value===f?-1:w.value===f?1:0),g.length===1)p=g[0].value,P(`AI engine: ${u[p]} (auto-detected)`);else if(g.length>1)p=await it({message:"Choose your AI engine:",options:g});else if(await Ee(`You need an AI coding assistant to power the conversion.
20
+ Make sure the Content scope is enabled.`,"HubSpot connection required");let w=await Ae({message:"Paste your Personal Access Key:",placeholder:"pat-na1-...",validate:T=>T.trim()?void 0:"Key is required"}),I=await de();I.start("Validating key...");try{let T=await an(w);Qt(w,T.portalId,T.portalName,T.dataCenter),b=w,o=T.portalId,i=T.portalName,I.stop(`Connected to ${T.portalName} (${T.portalId})`)}catch(T){I.stop("Validation failed"),U(`Invalid key: ${T instanceof Error?T.message:String(T)}`),process.exit(1)}}}else{let b=Me();if(b.found)P(`HubSpot CLI v${b.version}`);else{K("HubSpot CLI not found"),await ne({message:"Install HubSpot CLI globally?"})||(U("HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli"),process.exit(1));let I=await de();I.start("Installing HubSpot CLI..."),$("npm install -g @hubspot/cli").success||(I.stop("Failed"),U("Try: npm install -g @hubspot/cli"),process.exit(1)),b=Me(),I.stop(`HubSpot CLI v${b.version} installed`)}let y=Ne();if(y.authenticated)P(`HubSpot portal${y.portalName?`: ${y.portalName}`:""} (ID: ${y.portalId})`);else{K("HubSpot not authenticated"),await ne({message:"Run `hs init` now?"})||(U("Run `hs init` manually."),process.exit(1));let I=await de();I.start("Waiting for HubSpot authentication..."),Qs("hs init")||(I.stop("Authentication failed"),process.exit(1)),y=Ne(),I.stop(`Connected to portal${y.portalName?`: ${y.portalName}`:""} (ID: ${y.portalId})`)}o=y.portalId,i=y.portalName}let a=Tt(),r=Mt(),l=Nt(),c=oo(),d={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"},u,p=n.aiEngine,g=[];if(a.found&&g.push({value:"claude-code",label:"Claude Code",hint:p==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),r.found&&g.push({value:"gemini-cli",label:"Gemini CLI",hint:p==="gemini-cli"?"last used":"uses your existing Gemini setup"}),l.found&&g.push({value:"codex-cli",label:"OpenAI Codex",hint:p==="codex-cli"?"last used":"uses your existing OpenAI setup"}),c&&g.push({value:"api",label:"Anthropic API",hint:p==="api"?"last used":"uses your API key"}),p&&g.sort((b,y)=>b.value===p?-1:y.value===p?1:0),g.length===1)u=g[0].value,P(`AI engine: ${d[u]} (auto-detected)`);else if(g.length>1)u=await pt({message:"Choose your AI engine:",options:g});else if(await _e(`You need an AI coding assistant to power the conversion.
21
21
 
22
- ${C.bold("Option 1:")} Install Claude Code ${C.muted("(recommended)")}
22
+ ${k.bold("Option 1:")} Install Claude Code ${k.muted("(recommended)")}
23
23
  https://claude.ai/code
24
24
 
25
- ${C.bold("Option 2:")} Install Gemini CLI
25
+ ${k.bold("Option 2:")} Install Gemini CLI
26
26
  https://github.com/google-gemini/gemini-cli
27
27
 
28
- ${C.bold("Option 3:")} Install OpenAI Codex
28
+ ${k.bold("Option 3:")} Install OpenAI Codex
29
29
  https://github.com/openai/codex
30
30
 
31
- ${C.bold("Option 4:")} Set an Anthropic API key
31
+ ${k.bold("Option 4:")} Set an Anthropic API key
32
32
  export ANTHROPIC_API_KEY=sk-ant-...
33
- (get one at https://console.anthropic.com)`,"AI engine required"),p=await it({message:"Which will you set up?",options:[{value:"claude-code",label:"Claude Code",hint:"I'll install it now"},{value:"gemini-cli",label:"Gemini CLI",hint:"I'll install it now"},{value:"codex-cli",label:"OpenAI Codex",hint:"I'll install it now"},{value:"api",label:"Anthropic API",hint:"I'll enter my key"}]}),p==="api"){let S=await ve({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:w=>w.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=S,z({anthropicApiKey:S})}let y;return p==="claude-code"&&(y=await it({message:"Which model?",options:[{value:"sonnet",label:"Sonnet",hint:"fast, recommended"},{value:"opus",label:"Opus",hint:"most capable"},{value:"haiku",label:"Haiku",hint:"fastest, cheapest"}]})),z({aiEngine:p}),await ae("Environment ready!"),{aiEngine:p,model:y,portalId:s,portalName:i}}h();import{readdirSync as Hn,statSync as _r}from"fs";import{join as Y,basename as Ln,extname as Rr}from"path";Q();function Do(e){let t=[],o=[Y(e,"src/components/landing"),Y(e,"src/components/sections"),Y(e,"src/components"),Y(e,"src/pages"),Y(e,"app/components"),Y(e,"components")];for(let n of o)if(b(n))try{let s=Hn(n);for(let i of s){let a=Y(n,i);if(!_r(a).isFile())continue;let l=Rr(i);if(![".tsx",".jsx"].includes(l))continue;let c=Ln(i,l);if(c.startsWith("ui")||c==="index")continue;let u=v(a),p=Pr(c,u);t.push({name:c,path:a,description:p})}}catch{}return t}function Pr(e,t){let o=[];return/carousel|slider|swiper|embla/i.test(t)&&o.push("carousel"),/accordion|collapsible|expand/i.test(t)&&o.push("accordion"),/form|submit|input.*email/i.test(t)&&o.push("form"),/nav|navigation|menu/i.test(t)&&o.push("navigation"),/hero|headline|tagline/i.test(t)&&o.push("hero"),/footer|copyright/i.test(t)&&o.push("footer"),/testimonial|quote|review/i.test(t)&&o.push("testimonials"),/pricing|plan|tier/i.test(t)&&o.push("pricing"),/faq|question.*answer/i.test(t)&&o.push("FAQ"),/feature|benefit|advantage/i.test(t)&&o.push("features"),/contact|get.in.touch/i.test(t)&&o.push("contact"),/cta|call.to.action/i.test(t)&&o.push("CTA"),/team|member|bio/i.test(t)&&o.push("team"),o.length===0?e.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim():o.join(", ")}function Jo(e){let t=[Y(e,"src/index.css"),Y(e,"src/globals.css"),Y(e,"src/app/globals.css"),Y(e,"app/globals.css")],o=0,n=[];for(let s of t){if(!b(s))continue;let i=v(s),a=i.match(/--[\w-]+:/g);a&&(o+=a.length);let r=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(r)for(let c of r){let u=c.match(/['"]([^'"]+)['"]/)?.[1];u&&!n.includes(u)&&n.push(u)}let l=i.match(/@import\s+url\([^)]*fonts\.googleapis\.com[^)]*family=([^&)]+)/g);if(l)for(let c of l){let u=c.match(/family=([^&)]+)/)?.[1]?.replace(/\+/g," ");u&&!n.includes(u)&&n.push(u)}}return{varCount:o,fonts:n}}function Fo(e){let t=[],o=Y(e,"src/hooks");if(b(o))try{let s=Hn(o);for(let i of s)/scroll/i.test(i)&&t.push("Scroll animations"),/intersection/i.test(i)&&t.push("Scroll animations")}catch{}let n=Y(e,"src/components/landing");if(b(n))try{let s=Hn(n);for(let i of s){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let a=v(Y(n,i));/carousel|embla|swiper/i.test(a)&&!t.includes("Carousel")&&t.push("Carousel"),/accordion|collapsible/i.test(a)&&!t.includes("Accordion")&&t.push("Accordion"),/typing|typewriter/i.test(a)&&!t.includes("Typing animation")&&t.push("Typing animation"),/parallax|requestAnimationFrame/i.test(a)&&!t.includes("Parallax")&&t.push("Parallax")}}catch{}return t.length===0&&t.push("Scroll animations"),t}function Ho(e){let t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let l=Ln(e.replace(/\.git$/,""))||"react-source";if(t=Y(process.cwd(),"workspace",l),!b(t)){let c=A(`git clone --depth 1 "${e}" "${t}"`);if(!c.success)throw new Error(`Failed to clone ${e}: ${c.stderr}`)}}else if(t=e,!b(t))throw new Error(`Directory not found: ${t}`);let n=Do(t),s=b(Y(t,"tailwind.config.ts"))||b(Y(t,"tailwind.config.js")),{varCount:i,fonts:a}=Jo(t),r=Fo(t);return{sourceDir:t,wasCloned:o,components:n,hasTailwind:s,cssVarCount:i,fonts:a,interactions:r}}async function Xt(){await re("Source Project");let e=await ve({message:"GitHub URL or local path to your React project:",placeholder:"https://github.com/user/my-lovable-page",validate:y=>{if(!y.trim())return"Please enter a URL or path"}}),t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let y=Ln(e.replace(/\.git$/,""))||"react-source";if(t=Y(process.cwd(),"workspace",y),b(t))P(`Using existing clone: ${C.dim(t)}`);else{let S=await le();S.start("Cloning repository..."),A(`git clone --depth 1 "${e}" "${t}"`).success||(S.stop("Clone failed"),D(`Failed to clone ${e}. Check the URL and your access permissions.`),process.exit(1)),S.stop(`Cloned to ${C.dim(t)}`)}}else t=e,b(t)||(D(`Directory not found: ${t}`),process.exit(1)),P(`Using local source: ${C.dim(t)}`);let n=await le();n.start("Analyzing project structure...");let s=Do(t),i=b(Y(t,"tailwind.config.ts"))||b(Y(t,"tailwind.config.js")),{varCount:a,fonts:r}=Jo(t),l=Fo(t);n.stop(`Found ${s.length} landing page components`),s.length===0&&(W("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=s.map((y,S)=>` ${C.dim(`${S+1}.`)} ${C.bold(y.name)} ${C.muted(`\u2014 ${y.description}`)}`).join(`
34
- `),u=i?`Tailwind + custom CSS (${a} variables)`:`Custom CSS (${a} variables)`,p=r.length>0?r.join(", "):"System fonts",f=l.join(", ");return await Ee(`${c}
35
-
36
- CSS: ${u}
37
- JS: ${f}
38
- Font: ${p}`,`${s.length} components detected`),await ee({message:"Does this look right?"})||(D("Please adjust your source directory and try again."),process.exit(0)),await ae("Source analyzed!"),{sourceDir:t,wasCloned:o,components:s,hasTailwind:i,cssVarCount:a,fonts:r,interactions:l}}h();import{join as $t}from"path";Q();Z();h();import{mkdirSync as Le,writeFileSync as Qt}from"fs";import{join as we}from"path";function Zt(e,t){Le(e,{recursive:!0}),Le(we(e,"templates"),{recursive:!0}),Le(we(e,"modules"),{recursive:!0}),Le(we(e,"css"),{recursive:!0}),Le(we(e,"js"),{recursive:!0}),Le(we(e,"images"),{recursive:!0}),Le(we(e,"assets"),{recursive:!0});let o={label:t,preview_path:"./templates/home.html",screenshot_path:"./images/template-previews/home.png",enable_domain_stylesheets:!1,version:"1.0.0",author:{name:"vibeSpot",url:"https://github.com/borismichel/vibespot"}};Qt(we(e,"theme.json"),JSON.stringify(o,null,2)+`
39
- `),Qt(we(e,"fields.json"),`[]
40
- `);let n=`<!--
33
+ (get one at https://console.anthropic.com)`,"AI engine required"),u=await pt({message:"Which will you set up?",options:[{value:"claude-code",label:"Claude Code",hint:"I'll install it now"},{value:"gemini-cli",label:"Gemini CLI",hint:"I'll install it now"},{value:"codex-cli",label:"OpenAI Codex",hint:"I'll install it now"},{value:"api",label:"Anthropic API",hint:"I'll enter my key"}]}),u==="api"){let b=await Ae({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:y=>y.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=b,Y({anthropicApiKey:b})}let h;return u==="claude-code"&&(h=await pt({message:"Which model?",options:[{value:"sonnet",label:"Sonnet",hint:"fast, recommended"},{value:"opus",label:"Opus",hint:"most capable"},{value:"haiku",label:"Haiku",hint:"fastest, cheapest"}]})),Y({aiEngine:u}),await ce("Environment ready!"),{aiEngine:u,model:h,portalId:o,portalName:i}}f();import{readdirSync as ns,statSync as _a}from"fs";import{join as q,basename as ss,extname as Pa}from"path";X();function mo(t){let e=[],n=[q(t,"src/components/landing"),q(t,"src/components/sections"),q(t,"src/components"),q(t,"src/pages"),q(t,"app/components"),q(t,"components")];for(let s of n)if(S(s))try{let o=ns(s);for(let i of o){let a=q(s,i);if(!_a(a).isFile())continue;let l=Pa(i);if(![".tsx",".jsx"].includes(l))continue;let c=ss(i,l);if(c.startsWith("ui")||c==="index")continue;let d=x(a),u=Ra(c,d);e.push({name:c,path:a,description:u})}}catch{}return e}function Ra(t,e){let n=[];return/carousel|slider|swiper|embla/i.test(e)&&n.push("carousel"),/accordion|collapsible|expand/i.test(e)&&n.push("accordion"),/form|submit|input.*email/i.test(e)&&n.push("form"),/nav|navigation|menu/i.test(e)&&n.push("navigation"),/hero|headline|tagline/i.test(e)&&n.push("hero"),/footer|copyright/i.test(e)&&n.push("footer"),/testimonial|quote|review/i.test(e)&&n.push("testimonials"),/pricing|plan|tier/i.test(e)&&n.push("pricing"),/faq|question.*answer/i.test(e)&&n.push("FAQ"),/feature|benefit|advantage/i.test(e)&&n.push("features"),/contact|get.in.touch/i.test(e)&&n.push("contact"),/cta|call.to.action/i.test(e)&&n.push("CTA"),/team|member|bio/i.test(e)&&n.push("team"),n.length===0?t.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim():n.join(", ")}function po(t){let e=[q(t,"src/index.css"),q(t,"src/globals.css"),q(t,"src/app/globals.css"),q(t,"app/globals.css")],n=0,s=[];for(let o of e){if(!S(o))continue;let i=x(o),a=i.match(/--[\w-]+:/g);a&&(n+=a.length);let r=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(r)for(let c of r){let d=c.match(/['"]([^'"]+)['"]/)?.[1];d&&!s.includes(d)&&s.push(d)}let l=i.match(/@import\s+url\([^)]*fonts\.googleapis\.com[^)]*family=([^&)]+)/g);if(l)for(let c of l){let d=c.match(/family=([^&)]+)/)?.[1]?.replace(/\+/g," ");d&&!s.includes(d)&&s.push(d)}}return{varCount:n,fonts:s}}function fo(t){let e=[],n=q(t,"src/hooks");if(S(n))try{let o=ns(n);for(let i of o)/scroll/i.test(i)&&e.push("Scroll animations"),/intersection/i.test(i)&&e.push("Scroll animations")}catch{}let s=q(t,"src/components/landing");if(S(s))try{let o=ns(s);for(let i of o){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let a=x(q(s,i));/carousel|embla|swiper/i.test(a)&&!e.includes("Carousel")&&e.push("Carousel"),/accordion|collapsible/i.test(a)&&!e.includes("Accordion")&&e.push("Accordion"),/typing|typewriter/i.test(a)&&!e.includes("Typing animation")&&e.push("Typing animation"),/parallax|requestAnimationFrame/i.test(a)&&!e.includes("Parallax")&&e.push("Parallax")}}catch{}return e.length===0&&e.push("Scroll animations"),e}function go(t){let e,n=!1;if(t.startsWith("http")||t.startsWith("git@")){n=!0;let l=ss(t.replace(/\.git$/,""))||"react-source";if(e=q(process.cwd(),"workspace",l),!S(e)){let c=$(`git clone --depth 1 "${t}" "${e}"`);if(!c.success)throw new Error(`Failed to clone ${t}: ${c.stderr}`)}}else if(e=t,!S(e))throw new Error(`Directory not found: ${e}`);let s=mo(e),o=S(q(e,"tailwind.config.ts"))||S(q(e,"tailwind.config.js")),{varCount:i,fonts:a}=po(e),r=fo(e);return{sourceDir:e,wasCloned:n,components:s,hasTailwind:o,cssVarCount:i,fonts:a,interactions:r}}async function dn(){await le("Source Project");let t=await Ae({message:"GitHub URL or local path to your React project:",placeholder:"https://github.com/user/my-lovable-page",validate:h=>{if(!h.trim())return"Please enter a URL or path"}}),e,n=!1;if(t.startsWith("http")||t.startsWith("git@")){n=!0;let h=ss(t.replace(/\.git$/,""))||"react-source";if(e=q(process.cwd(),"workspace",h),S(e))P(`Using existing clone: ${k.dim(e)}`);else{let b=await de();b.start("Cloning repository..."),$(`git clone --depth 1 "${t}" "${e}"`).success||(b.stop("Clone failed"),U(`Failed to clone ${t}. Check the URL and your access permissions.`),process.exit(1)),b.stop(`Cloned to ${k.dim(e)}`)}}else e=t,S(e)||(U(`Directory not found: ${e}`),process.exit(1)),P(`Using local source: ${k.dim(e)}`);let s=await de();s.start("Analyzing project structure...");let o=mo(e),i=S(q(e,"tailwind.config.ts"))||S(q(e,"tailwind.config.js")),{varCount:a,fonts:r}=po(e),l=fo(e);s.stop(`Found ${o.length} landing page components`),o.length===0&&(K("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=o.map((h,b)=>` ${k.dim(`${b+1}.`)} ${k.bold(h.name)} ${k.muted(`\u2014 ${h.description}`)}`).join(`
34
+ `),d=i?`Tailwind + custom CSS (${a} variables)`:`Custom CSS (${a} variables)`,u=r.length>0?r.join(", "):"System fonts",p=l.join(", ");return await _e(`${c}
35
+
36
+ CSS: ${d}
37
+ JS: ${p}
38
+ Font: ${u}`,`${o.length} components detected`),await ne({message:"Does this look right?"})||(U("Please adjust your source directory and try again."),process.exit(0)),await ce("Source analyzed!"),{sourceDir:e,wasCloned:n,components:o,hasTailwind:i,cssVarCount:a,fonts:r,interactions:l}}f();import{join as Ot}from"path";X();ee();f();import{mkdirSync as Ke,writeFileSync as un}from"fs";import{join as Ie}from"path";function mn(t,e){Ke(t,{recursive:!0}),Ke(Ie(t,"templates"),{recursive:!0}),Ke(Ie(t,"modules"),{recursive:!0}),Ke(Ie(t,"css"),{recursive:!0}),Ke(Ie(t,"js"),{recursive:!0}),Ke(Ie(t,"images"),{recursive:!0}),Ke(Ie(t,"assets"),{recursive:!0});let n={label:e,preview_path:"./templates/home.html",screenshot_path:"./images/template-previews/home.png",enable_domain_stylesheets:!1,version:"1.0.0",author:{name:"vibeSpot",url:"https://github.com/borismichel/vibespot"}};un(Ie(t,"theme.json"),JSON.stringify(n,null,2)+`
39
+ `),un(Ie(t,"fields.json"),`[]
40
+ `);let s=`<!--
41
41
  templateType: page
42
42
  isAvailableForNewContent: false
43
- label: ${t} (placeholder)
43
+ label: ${e} (placeholder)
44
44
  screenshotPath: ../images/template-previews/home.png
45
45
  -->
46
46
  {% extends "./layouts/base.html" %}
@@ -48,11 +48,11 @@ ${C.bold("Option 4:")} Set an Anthropic API key
48
48
  {% block body %}
49
49
  {% dnd_area "main_content"
50
50
  label="Main Content",
51
- class="body-container body-container--${t}"
51
+ class="body-container body-container--${e}"
52
52
  %}
53
53
  {% end_dnd_area %}
54
54
  {% endblock body %}
55
- `;Qt(we(e,"templates","home.html"),n);let s=`<!--
55
+ `;un(Ie(t,"templates","home.html"),s);let o=`<!--
56
56
  templateType: none
57
57
  isAvailableForNewContent: false
58
58
  label: Base Layout
@@ -75,27 +75,27 @@ ${C.bold("Option 4:")} Set an Anthropic API key
75
75
  {{ standard_footer_includes }}
76
76
  </body>
77
77
  </html>
78
- `;Le(we(e,"templates","layouts"),{recursive:!0}),Qt(we(e,"templates","layouts","base.html"),s)}en();async function tn(){await re("HubSpot Theme Setup");let e=await it({message:"Do you have an existing HubSpot theme?",options:[{value:"fetch",label:"Fetch my existing theme from HubSpot",hint:"downloads your current theme"},{value:"create",label:"Start fresh (HubSpot Boilerplate)",hint:"creates a new starter theme"}]}),t,o,n=$t(process.cwd(),"workspace");if(ge(n),e==="fetch"){t=await ve({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:p=>p.trim()?void 0:"Theme name is required"}),o=$t(n,t);let l=await le();l.start("Fetching theme from HubSpot...");let c=N(),u=ue();if(c.hubspotUploadMode==="cli"||!u)A(`hs cms fetch "${t}" "${o}"`).success||(l.stop("Fetch failed"),D(`Could not fetch theme "${t}". Check the name in HubSpot Design Manager.`),process.exit(1));else try{await Tt(u,t,o)}catch(p){l.stop("Fetch failed"),D(`Could not fetch theme "${t}": ${p instanceof Error?p.message:String(p)}`),process.exit(1)}l.stop(`Theme fetched: ${C.dim(o)}`)}else{t=await ve({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),o=$t(n,t);let l=await le();l.start("Creating theme...");try{Zt(o,t)}catch(c){l.stop("Creation failed"),D(`Could not create theme "${t}": ${c instanceof Error?c.message:String(c)}`),process.exit(1)}l.stop(`Theme created: ${C.dim(o)}`)}await re("Checking theme compatibility");let s=$t(o,"templates/layouts/base.html");b(s)||(D(`base.html not found at ${s}. Your theme may have a different structure.`),process.exit(1)),P("base.html found");let i=v(s),a=!1;if(i.includes("template_css"))P("template_css support");else{W("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
78
+ `;Ke(Ie(t,"templates","layouts"),{recursive:!0}),un(Ie(t,"templates","layouts","base.html"),o)}pn();async function fn(){await le("HubSpot Theme Setup");let t=await pt({message:"Do you have an existing HubSpot theme?",options:[{value:"fetch",label:"Fetch my existing theme from HubSpot",hint:"downloads your current theme"},{value:"create",label:"Start fresh (HubSpot Boilerplate)",hint:"creates a new starter theme"}]}),e,n,s=Ot(process.cwd(),"workspace");if(we(s),t==="fetch"){e=await Ae({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:u=>u.trim()?void 0:"Theme name is required"}),n=Ot(s,e);let l=await de();l.start("Fetching theme from HubSpot...");let c=E(),d=he();if(c.hubspotUploadMode==="cli"||!d)$(`hs cms fetch "${e}" "${n}"`).success||(l.stop("Fetch failed"),U(`Could not fetch theme "${e}". Check the name in HubSpot Design Manager.`),process.exit(1));else try{await Rt(d,e,n)}catch(u){l.stop("Fetch failed"),U(`Could not fetch theme "${e}": ${u instanceof Error?u.message:String(u)}`),process.exit(1)}l.stop(`Theme fetched: ${k.dim(n)}`)}else{e=await Ae({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),n=Ot(s,e);let l=await de();l.start("Creating theme...");try{mn(n,e)}catch(c){l.stop("Creation failed"),U(`Could not create theme "${e}": ${c instanceof Error?c.message:String(c)}`),process.exit(1)}l.stop(`Theme created: ${k.dim(n)}`)}await le("Checking theme compatibility");let o=Ot(n,"templates/layouts/base.html");S(o)||(U(`base.html not found at ${o}. Your theme may have a different structure.`),process.exit(1)),P("base.html found");let i=x(o),a=!1;if(i.includes("template_css"))P("template_css support");else{K("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
79
79
  `,i.indexOf("theme-overrides.css"))):i.lastIndexOf("require_css");if(l>0){let c=i.lastIndexOf(`
80
80
  `,l);i=i.slice(0,c)+`
81
81
  {% if template_css %}
82
82
  {{ require_css(get_asset_url(template_css)) }}
83
- {% endif %}`+i.slice(c),a=!0}}if(i.includes("template_js"))P("template_js support");else{W("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
84
- `,l),u=i.indexOf(`
85
- `,c+1),p=`
83
+ {% endif %}`+i.slice(c),a=!0}}if(i.includes("template_js"))P("template_js support");else{K("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
84
+ `,l),d=i.indexOf(`
85
+ `,c+1),u=`
86
86
  {% if template_js %}
87
87
  {{ require_js(get_asset_url(template_js)) }}
88
- {% endif %}`,f=i.indexOf("}}",l)+2+i.slice(i.indexOf("}}",l)+2).indexOf(`
88
+ {% endif %}`,p=i.indexOf("}}",l)+2+i.slice(i.indexOf("}}",l)+2).indexOf(`
89
89
  `)+1;i=i.slice(0,i.indexOf(`
90
- `,i.indexOf("}}",l)+2))+p+i.slice(i.indexOf(`
91
- `,i.indexOf("}}",l)+2)),a=!0}}if(a){let l=await le();l.start("Patching base.html..."),M(s,i),l.stop("base.html patched with template_css/template_js support")}let r=$t(o,".hsignore");if(b(r)){let l=v(r);l.includes("docs/")||(M(r,l+`
90
+ `,i.indexOf("}}",l)+2))+u+i.slice(i.indexOf(`
91
+ `,i.indexOf("}}",l)+2)),a=!0}}if(a){let l=await de();l.start("Patching base.html..."),F(o,i),l.stop("base.html patched with template_css/template_js support")}let r=Ot(n,".hsignore");if(S(r)){let l=x(r);l.includes("docs/")||(F(r,l+`
92
92
  docs/
93
- `),P("Added docs/ to .hsignore"))}else M(r,`docs/
93
+ `),P("Added docs/ to .hsignore"))}else F(r,`docs/
94
94
  *.md
95
95
  node_modules/
96
96
  .git
97
- `),P("Created .hsignore");return await ae("Theme ready!"),{themePath:o,themeName:t}}h();import{join as ye}from"path";import{readdirSync as kt,rmSync as ts}from"fs";h();import{spawn as Jr}from"child_process";import{join as F,basename as Fr}from"path";import{readdirSync as Ne,statSync as Zo,writeFileSync as Hr}from"fs";h();Q();var Uo=new Map;function rt(e){let t=Uo.get(e);if(t!==void 0)return t;try{t=v(Ft(e))}catch{t=""}return Uo.set(e,t),t}function de(){return rt("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function Wo(){return rt("design-guide.md")}function Ko(){return rt("content-guide.md")}function at(){return rt("hubspot-rules.md")}function Bo(){return rt("humanify-guide.md")}function Yo(e){let t=rt("page-types.md");if(!t)return"";let n={landing_page:"## Landing Page",blog_post:"## Blog Post",website_page:"## Website Page",module_only:"## Module Only"}[e];if(!n)return"";let s=t.indexOf(n);if(s<0)return"";let i=t.indexOf(`
98
- ## `,s+n.length);return i>=0?t.slice(s,i).trim():t.slice(s).trim()}function Vo(e){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
97
+ `),P("Created .hsignore");return await ce("Theme ready!"),{themePath:n,themeName:e}}f();import{join as xe}from"path";import{readdirSync as jt,rmSync as Mo}from"fs";f();import{spawn as Da}from"child_process";import{join as W,basename as Ha}from"path";import{readdirSync as Pe,statSync as To,writeFileSync as La}from"fs";f();X();var bo=new Map;function ft(t){let e=bo.get(t);if(e!==void 0)return e;try{e=x(qt(t))}catch{e=""}return bo.set(t,e),e}function re(){return ft("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function So(){return ft("design-guide.md")}function vo(){return ft("content-guide.md")}function Ve(){return ft("hubspot-rules.md")}function wo(){return ft("humanify-guide.md")}function xo(t){let e=ft("page-types.md");if(!e)return"";let s={landing_page:"## Landing Page",blog_post:"## Blog Post",website_page:"## Website Page",module_only:"## Module Only"}[t];if(!s)return"";let o=e.indexOf(s);if(o<0)return"";let i=e.indexOf(`
98
+ ## `,o+s.length);return i>=0?e.slice(o,i).trim():e.slice(o).trim()}function Co(t){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
99
99
 
100
100
  ## Rules
101
101
  Follow the conversion guide below EXACTLY. Key rules:
@@ -112,10 +112,10 @@ Follow the conversion guide below EXACTLY. Key rules:
112
112
  - Convert React hooks to vanilla JS (no React, no npm packages)
113
113
 
114
114
  ## HubSpot CMS Rules
115
- ${at()}
115
+ ${Ve()}
116
116
 
117
117
  ## Conversion Guide
118
- ${e}`}function zo(e,t,o){return`Convert this React component to a HubSpot module named "${t}".
118
+ ${t}`}function Ao(t,e,n){return`Convert this React component to a HubSpot module named "${e}".
119
119
 
120
120
  Return a JSON object with these keys:
121
121
  - fieldsJson: complete fields.json content (as JSON string)
@@ -125,73 +125,73 @@ Return a JSON object with these keys:
125
125
  - moduleJs: module.js content if interactive behavior needed, or null
126
126
 
127
127
  Design system CSS variables available:
128
- ${o}
128
+ ${n}
129
129
 
130
130
  React component source:
131
- ${e}
131
+ ${t}
132
132
 
133
- Return ONLY valid JSON, no markdown fences.`}function qo(e,t,o){return`Create a shared CSS file for a HubSpot CMS landing page.
133
+ Return ONLY valid JSON, no markdown fences.`}function Io(t,e,n){return`Create a shared CSS file for a HubSpot CMS landing page.
134
134
 
135
135
  Extract the design system from the source CSS and Tailwind config below.
136
- Use the class prefix ".${o}-" for all custom classes.
136
+ Use the class prefix ".${n}-" for all custom classes.
137
137
 
138
138
  Requirements:
139
139
  - CSS custom properties for all colors, spacing
140
- - Page wrapper styles (.${o}-page) with !important font/color
141
- - .body-wrapper:has(.${o}-page) background fix
142
- - .body-wrapper.${o}-page-active JS fallback
143
- - Scoped overrides: .${o}-page h1-h6, p, a with !important
140
+ - Page wrapper styles (.${n}-page) with !important font/color
141
+ - .body-wrapper:has(.${n}-page) background fix
142
+ - .body-wrapper.${n}-page-active JS fallback
143
+ - Scoped overrides: .${n}-page h1-h6, p, a with !important
144
144
  - .dnd-section padding: 0 !important and .row-fluid max-width: 100%
145
145
  - Form overrides for dark themes
146
146
  - Utility classes (container, section, grid, glass)
147
- - Scroll animation classes (.${o}-scroll-animate / .visible)
147
+ - Scroll animation classes (.${n}-scroll-animate / .visible)
148
148
  - Mobile breakpoint at 767px
149
149
  - Responsive grid fallbacks
150
150
 
151
151
  Source CSS:
152
- ${e}
152
+ ${t}
153
153
 
154
154
  Tailwind config:
155
- ${t}
155
+ ${e}
156
156
 
157
- Return ONLY the CSS content, no markdown fences.`}function Xo(e,t,o){return`Create a shared vanilla JS file for a HubSpot CMS landing page.
157
+ Return ONLY the CSS content, no markdown fences.`}function ko(t,e,n){return`Create a shared vanilla JS file for a HubSpot CMS landing page.
158
158
 
159
159
  Convert the React hooks and interactive components below to plain JavaScript.
160
- Use the class prefix "${o}-" to match the CSS.
160
+ Use the class prefix "${n}-" to match the CSS.
161
161
 
162
162
  Requirements:
163
163
  - IIFE wrapper with "use strict"
164
- - initBodyWrapper: add "${o}-page-active" class to .body-wrapper
165
- - initScrollAnimations: IntersectionObserver for .${o}-scroll-animate \u2192 .visible
164
+ - initBodyWrapper: add "${n}-page-active" class to .body-wrapper
165
+ - initScrollAnimations: IntersectionObserver for .${n}-scroll-animate \u2192 .visible
166
166
  - Convert any carousels, accordions, typing animations to vanilla JS
167
167
  - DOMContentLoaded / readyState check
168
168
 
169
169
  React hooks source:
170
- ${e}
170
+ ${t}
171
171
 
172
172
  Interactive component sources:
173
- ${t}
173
+ ${e}
174
174
 
175
- Return ONLY the JavaScript content, no markdown fences.`}function Qo(e,t,o){return`Create a HubSpot page template that assembles these modules:
175
+ Return ONLY the JavaScript content, no markdown fences.`}function $o(t,e,n){return`Create a HubSpot page template that assembles these modules:
176
176
 
177
- ${e.map((n,s)=>`${s+1}. ${n}.module`).join(`
177
+ ${t.map((s,o)=>`${o+1}. ${s}.module`).join(`
178
178
  `)}
179
179
 
180
180
  Template requirements:
181
181
  - templateType: page, isAvailableForNewContent: true
182
182
  - extends "./layouts/base.html"
183
- - set template_css = "../../css/${o}-theme.css"
184
- - set template_js = "../../js/${o}-animations.js"
183
+ - set template_css = "../../css/${n}-theme.css"
184
+ - set template_js = "../../js/${n}-animations.js"
185
185
  - Empty header and footer blocks (modules handle them)
186
- - Wrap content in <div class="${o}-page">
186
+ - Wrap content in <div class="${n}-page">
187
187
  - Each module in its own dnd_section with padding zeroed and full_width=true
188
- - dnd_area label: "${t} Landing Page"
188
+ - dnd_area label: "${e} Landing Page"
189
189
 
190
- Return ONLY the template HTML content, no markdown fences.`}Q();var Lr=new Set(["about.html","blog-index.html","blog-post.html","contact.html","home.html","hubdb.html","landing-page.html","pricing.html","qa-test.html","base.html"]),nn=class{model;reported=new Set;moduleCount=0;expectedModules=0;constructor(t){this.model=t}async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||de();this.reported.clear(),this.moduleCount=0,this.expectedModules=0;let a=this.countSourceComponents(o),r=this.listModules(n),l=this.listDir(F(n,"css")),c=this.listDir(F(n,"js")),u=this.listDir(F(n,"templates")),p=this.buildFullPrompt(o,n,i);s("convert",`Starting Claude Code (${a} source components found)...`);let f="",g="",y=setInterval(()=>{this.reportProgress(n,r,l,c,u,s)},3e3);try{await new Promise((E,R)=>{let X={...process.env};delete X.CLAUDECODE;let L=["--print","--max-turns","50","--allowedTools","Read,Glob,Grep,Write,Edit,Bash"];this.model&&L.push("--model",this.model);let O=Jr("claude",L,{cwd:n,stdio:["pipe","pipe","pipe"],env:X,shell:!0});O.stdout.on("data",G=>{f+=G.toString()}),O.stderr.on("data",G=>{g+=G.toString()}),O.on("error",G=>R(new Error(`Claude Code failed to start: ${G.message}`))),O.on("close",G=>{G!==0?R(new Error(`Claude Code exited with code ${G}.
190
+ Return ONLY the template HTML content, no markdown fences.`}X();var Ga=new Set(["about.html","blog-index.html","blog-post.html","contact.html","home.html","hubdb.html","landing-page.html","pricing.html","qa-test.html","base.html"]),gn=class{model;reported=new Set;moduleCount=0;expectedModules=0;constructor(e){this.model=e}async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||re();this.reported.clear(),this.moduleCount=0,this.expectedModules=0;let a=this.countSourceComponents(n),r=this.listModules(s),l=this.listDir(W(s,"css")),c=this.listDir(W(s,"js")),d=this.listDir(W(s,"templates")),u=this.buildFullPrompt(n,s,i);o("convert",`Starting Claude Code (${a} source components found)...`);let p="",g="",h=setInterval(()=>{this.reportProgress(s,r,l,c,d,o)},3e3);try{await new Promise((I,T)=>{let J={...process.env};delete J.CLAUDECODE;let D=["--print","--max-turns","50","--allowedTools","Read,Glob,Grep,Write,Edit,Bash"];this.model&&D.push("--model",this.model);let R=Da("claude",D,{cwd:s,stdio:["pipe","pipe","pipe"],env:J,shell:!0});R.stdout.on("data",L=>{p+=L.toString()}),R.stderr.on("data",L=>{g+=L.toString()}),R.on("error",L=>T(new Error(`Claude Code failed to start: ${L.message}`))),R.on("close",L=>{L!==0?T(new Error(`Claude Code exited with code ${L}.
191
191
  `+(g?`Stderr: ${g.slice(0,500)}
192
- `:"")+(f?`Output: ${f.slice(0,500)}`:"No output"))):E()}),O.stdin.on("error",()=>{}),O.stdin.write(p),O.stdin.end(),setTimeout(()=>{O.kill(),R(new Error("Claude Code timed out after 30 minutes"))},18e5)})}finally{clearInterval(y)}let S=F(n,"..","vibespot-conversion.log");try{let R=["=== vibeSpot Conversion Log ===",`Timestamp: ${new Date().toISOString()}`,`Source: ${o}`,`Theme: ${n}`,`Model: ${this.model||"default"}`,"","=== PROMPT SENT ===",p.slice(0,500)+`
193
- ... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",f||"(empty)","","=== CLAUDE CODE STDERR ===",g||"(empty)",""].join(`
194
- `);Hr(S,R,"utf-8"),s("status",`Log written to ${Fr(S)}`)}catch{}s("scan","Scanning generated files...");let w=this.scanGeneratedFiles(n);if(w.modules.filter(E=>!r.has(E.moduleName+".module")).length===0){let E=f.slice(0,1500)||"(no output)",R=g.slice(0,500);throw new Error(`Claude Code did not create any new module files.
192
+ `:"")+(p?`Output: ${p.slice(0,500)}`:"No output"))):I()}),R.stdin.on("error",()=>{}),R.stdin.write(u),R.stdin.end(),setTimeout(()=>{R.kill(),T(new Error("Claude Code timed out after 30 minutes"))},18e5)})}finally{clearInterval(h)}let b=W(s,"..","vibespot-conversion.log");try{let T=["=== vibeSpot Conversion Log ===",`Timestamp: ${new Date().toISOString()}`,`Source: ${n}`,`Theme: ${s}`,`Model: ${this.model||"default"}`,"","=== PROMPT SENT ===",u.slice(0,500)+`
193
+ ... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",p||"(empty)","","=== CLAUDE CODE STDERR ===",g||"(empty)",""].join(`
194
+ `);La(b,T,"utf-8"),o("status",`Log written to ${Ha(b)}`)}catch{}o("scan","Scanning generated files...");let y=this.scanGeneratedFiles(s);if(y.modules.filter(I=>!r.has(I.moduleName+".module")).length===0){let I=p.slice(0,1500)||"(no output)",T=g.slice(0,500);throw new Error(`Claude Code did not create any new module files.
195
195
 
196
196
  This usually means the model described the conversion instead of using Write tool to create files.
197
197
 
@@ -200,66 +200,66 @@ Possible causes:
200
200
  - Claude Code hit a rate limit or API error
201
201
  - The source directory was not accessible
202
202
 
203
- Source: ${t.sourceDir}
204
- Theme: ${n}
205
- `+(R?`
203
+ Source: ${e.sourceDir}
204
+ Theme: ${s}
205
+ `+(T?`
206
206
  Stderr:
207
- ${R}
207
+ ${T}
208
208
  `:"")+`
209
209
  Claude output:
210
- ${E}`)}return w}reportProgress(t,o,n,s,i,a){let r=0,l=this.listDir(F(t,"css"));for(let f of l){if(n.has(f)||!f.endsWith(".css"))continue;let g=`css:${f}`;this.reported.has(g)||(this.reported.add(g),a("created",`Shared CSS (${f})`),r++)}let c=this.listDir(F(t,"js"));for(let f of c){if(s.has(f)||!f.endsWith(".js"))continue;let g=`js:${f}`;this.reported.has(g)||(this.reported.add(g),a("created",`Shared JS (${f})`),r++)}this.expectedModules===0&&(this.expectedModules=this.detectExpectedModules(t,i));let u=this.listModules(t);for(let f of u){if(o.has(f))continue;let g=`module:${f}`;if(!this.reported.has(g)){this.reported.add(g),this.moduleCount++;let y=this.expectedModules>0?`[${this.moduleCount}/${this.expectedModules}]`:`[${this.moduleCount}]`;a("created",`Module ${y}: ${f.replace(".module","")}`),r++}}let p=this.listDir(F(t,"templates"));for(let f of p){if(i.has(f)||!f.endsWith(".html"))continue;let g=`template:${f}`;this.reported.has(g)||(this.reported.add(g),a("created",`Page template (${f})`),r++)}if(r===0)if(this.moduleCount>0){let f=this.expectedModules>0?`/${this.expectedModules}`:"";a("status",`${this.moduleCount}${f} modules created, conversion continuing...`)}else this.reported.size>0?a("status","Shared assets created, building modules..."):a("status","Claude Code is analyzing source files...")}buildFullPrompt(t,o,n){return`You are converting a React landing page to native HubSpot CMS modules.
210
+ ${I}`)}return y}reportProgress(e,n,s,o,i,a){let r=0,l=this.listDir(W(e,"css"));for(let p of l){if(s.has(p)||!p.endsWith(".css"))continue;let g=`css:${p}`;this.reported.has(g)||(this.reported.add(g),a("created",`Shared CSS (${p})`),r++)}let c=this.listDir(W(e,"js"));for(let p of c){if(o.has(p)||!p.endsWith(".js"))continue;let g=`js:${p}`;this.reported.has(g)||(this.reported.add(g),a("created",`Shared JS (${p})`),r++)}this.expectedModules===0&&(this.expectedModules=this.detectExpectedModules(e,i));let d=this.listModules(e);for(let p of d){if(n.has(p))continue;let g=`module:${p}`;if(!this.reported.has(g)){this.reported.add(g),this.moduleCount++;let h=this.expectedModules>0?`[${this.moduleCount}/${this.expectedModules}]`:`[${this.moduleCount}]`;a("created",`Module ${h}: ${p.replace(".module","")}`),r++}}let u=this.listDir(W(e,"templates"));for(let p of u){if(i.has(p)||!p.endsWith(".html"))continue;let g=`template:${p}`;this.reported.has(g)||(this.reported.add(g),a("created",`Page template (${p})`),r++)}if(r===0)if(this.moduleCount>0){let p=this.expectedModules>0?`/${this.expectedModules}`:"";a("status",`${this.moduleCount}${p} modules created, conversion continuing...`)}else this.reported.size>0?a("status","Shared assets created, building modules..."):a("status","Claude Code is analyzing source files...")}buildFullPrompt(e,n,s){return`You are converting a React landing page to native HubSpot CMS modules.
211
211
 
212
- SOURCE DIRECTORY: ${t}
213
- THEME DIRECTORY: ${o}
212
+ SOURCE DIRECTORY: ${e}
213
+ THEME DIRECTORY: ${n}
214
214
 
215
215
  IMPORTANT \u2014 YOU MUST CREATE REAL FILES:
216
216
  You have access to Write, Edit, Read, Glob, Grep, and Bash tools. You MUST use the Write tool to create each file. Do NOT just describe or list what files should be created \u2014 actually call the Write tool for every single file. If you do not call Write, no files will be created and the conversion will fail.
217
217
 
218
218
  STEP-BY-STEP PROCESS:
219
- 1. Use Glob to find all .tsx/.jsx files in ${t}/src/
219
+ 1. Use Glob to find all .tsx/.jsx files in ${e}/src/
220
220
  2. Use Read to read each component file and understand the page structure
221
- 3. Use Write to create a shared CSS file at ${o}/css/<name>-theme.css
221
+ 3. Use Write to create a shared CSS file at ${n}/css/<name>-theme.css
222
222
  - Include CSS custom properties, design system variables, utility classes
223
223
  - Add theme-override countermeasures (.body-wrapper:has(), scoped !important overrides)
224
- 4. Use Write to create a shared JS file at ${o}/js/<name>-animations.js
224
+ 4. Use Write to create a shared JS file at ${n}/js/<name>-animations.js
225
225
  - Convert React hooks to vanilla JS (IntersectionObserver for scroll animations)
226
226
  - IIFE wrapper, DOMContentLoaded setup
227
227
  5. For EACH visual section of the page, use Write to create ALL FOUR files:
228
- a. ${o}/modules/<name>.module/fields.json
228
+ a. ${n}/modules/<name>.module/fields.json
229
229
  - Editable fields for the section content
230
230
  - NEVER use "textarea" type (use "text" instead)
231
231
  - NEVER use "name" as a field name (use "item_name" instead)
232
232
  - Add a "styles" group with "tab": "STYLE" containing color pickers
233
- b. ${o}/modules/<name>.module/meta.json
233
+ b. ${n}/modules/<name>.module/meta.json
234
234
  - Must include: host_template_types: ["PAGE"], is_available_for_new_content: true
235
- c. ${o}/modules/<name>.module/module.html
235
+ c. ${n}/modules/<name>.module/module.html
236
236
  - HubL template that renders the section (convert JSX to HubL)
237
- d. ${o}/modules/<name>.module/module.css
237
+ d. ${n}/modules/<name>.module/module.css
238
238
  - REQUIRED \u2014 complete vanilla CSS for this section
239
239
  - Must include: layout, spacing, colors, typography, backgrounds, gradients, shadows, borders, hover effects, responsive breakpoints
240
240
  - Convert ALL Tailwind classes to BEM-style CSS. Do NOT skip this file.
241
- 6. Use Write to create a page template at ${o}/templates/lp-<name>.html
241
+ 6. Use Write to create a page template at ${n}/templates/lp-<name>.html
242
242
  - Annotation: templateType: page, isAvailableForNewContent: true
243
243
  - Extends "./layouts/base.html"
244
244
  - Sets template_css and template_js variables
245
245
  - Wraps modules in dnd_area with dnd_section containers
246
- 7. Read ${o}/templates/layouts/base.html and ensure it supports template_css and template_js variables
246
+ 7. Read ${n}/templates/layouts/base.html and ensure it supports template_css and template_js variables
247
247
 
248
248
  CSS QUALITY: The converted page must visually match the original React page. Every module.css must be self-contained with complete styling for that section.
249
249
 
250
250
  Do NOT run hs upload \u2014 I will handle that separately.
251
251
 
252
252
  HUBSPOT CMS RULES:
253
- ${at()}
253
+ ${Ve()}
254
254
 
255
255
  CONVERSION GUIDE:
256
- ${n}`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=F(t,"css");if(b(n)){for(let r of Ne(n))if(r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){o.sharedCss=v(F(n,r));break}}let s=F(t,"js");if(b(s)){for(let r of Ne(s))if(r.endsWith(".js")&&r!=="main.js"){o.sharedJs=v(F(s,r));break}}let i=F(t,"templates");if(b(i)){for(let r of Ne(i))if(r.startsWith("lp-")&&r.endsWith(".html")){o.template=v(F(i,r));break}if(!o.template){for(let r of Ne(i))if(r.endsWith(".html")&&!Lr.has(r)&&!r.startsWith("system")){let l=v(F(i,r));if(l.includes("dnd_area")){o.template=l;break}}}if(!o.template){for(let r of Ne(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=v(F(i,r));if(l.includes("dnd_area")){o.template=l;break}}}}let a=F(t,"modules");if(b(a))for(let r of Ne(a)){if(!r.endsWith(".module"))continue;let l=F(a,r);if(!Zo(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=F(l,"fields.json");b(u)&&(c.fieldsJson=v(u));let p=F(l,"meta.json");b(p)&&(c.metaJson=v(p));let f=F(l,"module.html");b(f)&&(c.moduleHtml=v(f));let g=F(l,"module.css");b(g)&&(c.moduleCss=v(g));let y=F(l,"module.js");b(y)&&(c.moduleJs=v(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}listModules(t){let o=F(t,"modules");return b(o)?new Set(Ne(o).filter(n=>n.endsWith(".module"))):new Set}listDir(t){return b(t)?new Set(Ne(t)):new Set}detectExpectedModules(t,o){let n=F(t,"templates");if(!b(n))return 0;for(let s of Ne(n))if(!o.has(s)&&!(!s.endsWith(".html")||s==="base.html"||s.startsWith("system")))try{let i=v(F(n,s));if(i.includes("dnd_area")){let a=i.match(/dnd_module/g);return a?a.length:0}}catch{}return 0}countSourceComponents(t){let o=F(t,"src");return b(o)?this.countComponentsRecursive(o):0}countComponentsRecursive(t){let o=0;for(let n of Ne(t)){let s=F(t,n);try{Zo(s).isDirectory()&&n!=="node_modules"&&n!==".git"?o+=this.countComponentsRecursive(s):/\.(tsx|jsx)$/.test(n)&&!n.includes(".test.")&&!n.includes(".spec.")&&o++}catch{}}return o}};h();import Gr from"@anthropic-ai/sdk";import{join as K,basename as Ur}from"path";import{readdirSync as es}from"fs";Q();var on=class{client;model="claude-sonnet-4-6";constructor(t){this.client=new Gr({apiKey:t||process.env.ANTHROPIC_API_KEY})}async convert(t){let{sourceDir:o,themePath:n,conversionGuide:s,onProgress:i}=t,a=Vo(s),r=Ur(o)||"page",l=r.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,15);i("css","Analyzing design system...");let c=this.findAndReadCSS(o),u=this.findAndReadTailwind(o),p=await this.complete(a,qo(c,u,l)),f=K(n,"css",`${l}-theme.css`);M(f,p),i("css-done",`Created css/${l}-theme.css`),i("js","Creating shared JavaScript...");let g=this.findAndReadHooks(o),y=this.findInteractiveComponents(o),S=await this.complete(a,Xo(g,y,l)),w=K(n,"js",`${l}-animations.js`);M(w,S),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let k=this.findComponents(o),E=[];for(let O=0;O<k.length;O++){let G=k[O],oe=G.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${oe}.module (${O+1}/${k.length})...`);let H=v(G.path),Jt=await this.complete(a,zo(H,oe,`See css/${l}-theme.css`));try{let se=JSON.parse(Jt),Se={moduleName:oe,fieldsJson:typeof se.fieldsJson=="string"?se.fieldsJson:JSON.stringify(se.fieldsJson,null,2),metaJson:typeof se.metaJson=="string"?se.metaJson:JSON.stringify(se.metaJson,null,2),moduleHtml:se.moduleHtml||"",moduleCss:se.moduleCss||"",moduleJs:se.moduleJs||void 0},He=K(n,"modules",`${oe}.module`);ge(He),M(K(He,"fields.json"),Se.fieldsJson),M(K(He,"meta.json"),Se.metaJson),M(K(He,"module.html"),Se.moduleHtml),M(K(He,"module.css"),Se.moduleCss),Se.moduleJs&&M(K(He,"module.js"),Se.moduleJs),E.push(Se),i("module-done",`${oe}.module (${this.countFiles(Se)} files)`)}catch{i("module-error",`Failed to parse ${oe} \u2014 skipping`)}}i("template","Creating page template...");let R=E.map(O=>O.moduleName),X=await this.complete(a,Qo(R,r,l)),L=K(n,"templates",`lp-${l}.html`);return M(L,X),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:p,sharedJs:S,template:X,modules:E}}async complete(t,o){return(await this.client.messages.create({model:this.model,max_tokens:8192,system:t,messages:[{role:"user",content:o}]})).content.find(i=>i.type==="text")?.text||""}findAndReadCSS(t){let o=[K(t,"src/index.css"),K(t,"src/globals.css"),K(t,"src/app/globals.css"),K(t,"app/globals.css")];for(let n of o)if(b(n))return v(n);return""}findAndReadTailwind(t){let o=[K(t,"tailwind.config.ts"),K(t,"tailwind.config.js"),K(t,"tailwind.config.mjs")];for(let n of o)if(b(n))return v(n);return""}findAndReadHooks(t){let o=K(t,"src/hooks");if(!b(o))return"";try{return es(o).filter(n=>n.endsWith(".ts")||n.endsWith(".tsx")).map(n=>`// ${n}
257
- ${v(K(o,n))}`).join(`
256
+ ${s}`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=W(e,"css");if(S(s)){for(let r of Pe(s))if(r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=x(W(s,r));break}}let o=W(e,"js");if(S(o)){for(let r of Pe(o))if(r.endsWith(".js")&&r!=="main.js"){n.sharedJs=x(W(o,r));break}}let i=W(e,"templates");if(S(i)){for(let r of Pe(i))if(r.startsWith("lp-")&&r.endsWith(".html")){n.template=x(W(i,r));break}if(!n.template){for(let r of Pe(i))if(r.endsWith(".html")&&!Ga.has(r)&&!r.startsWith("system")){let l=x(W(i,r));if(l.includes("dnd_area")){n.template=l;break}}}if(!n.template){for(let r of Pe(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=x(W(i,r));if(l.includes("dnd_area")){n.template=l;break}}}}let a=W(e,"modules");if(S(a))for(let r of Pe(a)){if(!r.endsWith(".module"))continue;let l=W(a,r);if(!To(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=W(l,"fields.json");S(d)&&(c.fieldsJson=x(d));let u=W(l,"meta.json");S(u)&&(c.metaJson=x(u));let p=W(l,"module.html");S(p)&&(c.moduleHtml=x(p));let g=W(l,"module.css");S(g)&&(c.moduleCss=x(g));let h=W(l,"module.js");S(h)&&(c.moduleJs=x(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}listModules(e){let n=W(e,"modules");return S(n)?new Set(Pe(n).filter(s=>s.endsWith(".module"))):new Set}listDir(e){return S(e)?new Set(Pe(e)):new Set}detectExpectedModules(e,n){let s=W(e,"templates");if(!S(s))return 0;for(let o of Pe(s))if(!n.has(o)&&!(!o.endsWith(".html")||o==="base.html"||o.startsWith("system")))try{let i=x(W(s,o));if(i.includes("dnd_area")){let a=i.match(/dnd_module/g);return a?a.length:0}}catch{}return 0}countSourceComponents(e){let n=W(e,"src");return S(n)?this.countComponentsRecursive(n):0}countComponentsRecursive(e){let n=0;for(let s of Pe(e)){let o=W(e,s);try{To(o).isDirectory()&&s!=="node_modules"&&s!==".git"?n+=this.countComponentsRecursive(o):/\.(tsx|jsx)$/.test(s)&&!s.includes(".test.")&&!s.includes(".spec.")&&n++}catch{}}return n}};f();import Ua from"@anthropic-ai/sdk";import{join as V,basename as Wa}from"path";import{readdirSync as Eo}from"fs";X();var hn=class{client;model="claude-sonnet-4-6";constructor(e){this.client=new Ua({apiKey:e||process.env.ANTHROPIC_API_KEY})}async convert(e){let{sourceDir:n,themePath:s,conversionGuide:o,onProgress:i}=e,a=Co(o),r=Wa(n)||"page",l=r.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,15);i("css","Analyzing design system...");let c=this.findAndReadCSS(n),d=this.findAndReadTailwind(n),u=await this.complete(a,Io(c,d,l)),p=V(s,"css",`${l}-theme.css`);F(p,u),i("css-done",`Created css/${l}-theme.css`),i("js","Creating shared JavaScript...");let g=this.findAndReadHooks(n),h=this.findInteractiveComponents(n),b=await this.complete(a,ko(g,h,l)),y=V(s,"js",`${l}-animations.js`);F(y,b),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let w=this.findComponents(n),I=[];for(let R=0;R<w.length;R++){let L=w[R],Z=L.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${Z}.module (${R+1}/${w.length})...`);let G=x(L.path),H=await this.complete(a,Ao(G,Z,`See css/${l}-theme.css`));try{let O=JSON.parse(H),te={moduleName:Z,fieldsJson:typeof O.fieldsJson=="string"?O.fieldsJson:JSON.stringify(O.fieldsJson,null,2),metaJson:typeof O.metaJson=="string"?O.metaJson:JSON.stringify(O.metaJson,null,2),moduleHtml:O.moduleHtml||"",moduleCss:O.moduleCss||"",moduleJs:O.moduleJs||void 0},ie=V(s,"modules",`${Z}.module`);we(ie),F(V(ie,"fields.json"),te.fieldsJson),F(V(ie,"meta.json"),te.metaJson),F(V(ie,"module.html"),te.moduleHtml),F(V(ie,"module.css"),te.moduleCss),te.moduleJs&&F(V(ie,"module.js"),te.moduleJs),I.push(te),i("module-done",`${Z}.module (${this.countFiles(te)} files)`)}catch{i("module-error",`Failed to parse ${Z} \u2014 skipping`)}}i("template","Creating page template...");let T=I.map(R=>R.moduleName),J=await this.complete(a,$o(T,r,l)),D=V(s,"templates",`lp-${l}.html`);return F(D,J),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:u,sharedJs:b,template:J,modules:I}}async complete(e,n){return(await this.client.messages.create({model:this.model,max_tokens:8192,system:e,messages:[{role:"user",content:n}]})).content.find(i=>i.type==="text")?.text||""}findAndReadCSS(e){let n=[V(e,"src/index.css"),V(e,"src/globals.css"),V(e,"src/app/globals.css"),V(e,"app/globals.css")];for(let s of n)if(S(s))return x(s);return""}findAndReadTailwind(e){let n=[V(e,"tailwind.config.ts"),V(e,"tailwind.config.js"),V(e,"tailwind.config.mjs")];for(let s of n)if(S(s))return x(s);return""}findAndReadHooks(e){let n=V(e,"src/hooks");if(!S(n))return"";try{return Eo(n).filter(s=>s.endsWith(".ts")||s.endsWith(".tsx")).map(s=>`// ${s}
257
+ ${x(V(n,s))}`).join(`
258
258
 
259
- `)}catch{return""}}findInteractiveComponents(t){let o=this.findComponents(t),n=[];for(let s of o){let i=v(s.path);/carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(i)&&n.push(`// ${s.name}
260
- ${i}`)}return n.join(`
259
+ `)}catch{return""}}findInteractiveComponents(e){let n=this.findComponents(e),s=[];for(let o of n){let i=x(o.path);/carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(i)&&s.push(`// ${o.name}
260
+ ${i}`)}return s.join(`
261
261
 
262
- `)}findComponents(t){let o=[K(t,"src/components/landing"),K(t,"src/components/sections"),K(t,"src/components")];for(let n of o)if(b(n))try{return es(n).filter(s=>(s.endsWith(".tsx")||s.endsWith(".jsx"))&&!s.startsWith("ui")&&s!=="index.tsx"&&s!=="index.jsx").map(s=>({name:s.replace(/\.(tsx|jsx)$/,""),path:K(n,s)}))}catch{continue}return[]}countFiles(t){let o=3;return t.moduleCss&&o++,t.moduleJs&&o++,o}};h();import{spawn as Wr}from"child_process";import{join as me}from"path";import{readdirSync as sn,statSync as Kr}from"fs";Q();var rn=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||de(),a=this.buildFullPrompt(o,n,i);return s("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Wr("gemini",["-p",a],{cwd:n,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),u="",p="";c.stdout.on("data",f=>{u+=f.toString()}),c.stderr.on("data",f=>{p+=f.toString()}),c.on("error",f=>l(new Error(`Gemini CLI failed: ${f.message}`))),c.on("close",f=>{f!==0&&p&&!u?l(new Error(`Gemini CLI failed: ${p}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Gemini CLI timed out after 10 minutes"))},6e5)}),s("scan","Scanning generated files..."),this.scanGeneratedFiles(n)}buildFullPrompt(t,o,n){return`Read the conversion guide below, then convert the React landing page at ${t} into native HubSpot CMS modules for the theme at ${o}.
262
+ `)}findComponents(e){let n=[V(e,"src/components/landing"),V(e,"src/components/sections"),V(e,"src/components")];for(let s of n)if(S(s))try{return Eo(s).filter(o=>(o.endsWith(".tsx")||o.endsWith(".jsx"))&&!o.startsWith("ui")&&o!=="index.tsx"&&o!=="index.jsx").map(o=>({name:o.replace(/\.(tsx|jsx)$/,""),path:V(s,o)}))}catch{continue}return[]}countFiles(e){let n=3;return e.moduleCss&&n++,e.moduleJs&&n++,n}};f();import{spawn as Ba}from"child_process";import{join as ye}from"path";import{readdirSync as yn,statSync as Ka}from"fs";X();var bn=class{async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||re(),a=this.buildFullPrompt(n,s,i);return o("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Ba("gemini",["-p",a],{cwd:s,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),d="",u="";c.stdout.on("data",p=>{d+=p.toString()}),c.stderr.on("data",p=>{u+=p.toString()}),c.on("error",p=>l(new Error(`Gemini CLI failed: ${p.message}`))),c.on("close",p=>{p!==0&&u&&!d?l(new Error(`Gemini CLI failed: ${u}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Gemini CLI timed out after 10 minutes"))},6e5)}),o("scan","Scanning generated files..."),this.scanGeneratedFiles(s)}buildFullPrompt(e,n,s){return`Read the conversion guide below, then convert the React landing page at ${e} into native HubSpot CMS modules for the theme at ${n}.
263
263
 
264
264
  INSTRUCTIONS:
265
265
  1. Analyze all .tsx/.jsx components in the React source
@@ -271,10 +271,10 @@ INSTRUCTIONS:
271
271
  7. Make sure base.html supports template_css and template_js variables
272
272
 
273
273
  CONVERSION GUIDE:
274
- ${n}
274
+ ${s}
275
275
 
276
276
  Do NOT run hs upload \u2014 I will handle that separately.
277
- Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=me(t,"css");if(b(n)){for(let r of sn(n))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){o.sharedCss=v(me(n,r));break}}let s=me(t,"js");if(b(s)){for(let r of sn(s))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){o.sharedJs=v(me(s,r));break}}let i=me(t,"templates");if(b(i)){for(let r of sn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=v(me(i,r));if(l.includes("dnd_area")){o.template=l;break}}}let a=me(t,"modules");if(b(a))for(let r of sn(a)){if(!r.endsWith(".module"))continue;let l=me(a,r);if(!Kr(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=me(l,"fields.json");b(u)&&(c.fieldsJson=v(u));let p=me(l,"meta.json");b(p)&&(c.metaJson=v(p));let f=me(l,"module.html");b(f)&&(c.moduleHtml=v(f));let g=me(l,"module.css");b(g)&&(c.moduleCss=v(g));let y=me(l,"module.js");b(y)&&(c.moduleJs=v(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};h();import{spawn as Br}from"child_process";import{join as pe}from"path";import{readdirSync as an,statSync as Yr}from"fs";Q();var ln=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||de(),a=this.buildFullPrompt(o,n,i);return s("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Br("codex",["exec","--full-auto",a],{cwd:n,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),u="",p="";c.stdout.on("data",f=>{u+=f.toString()}),c.stderr.on("data",f=>{p+=f.toString()}),c.on("error",f=>l(new Error(`Codex CLI failed: ${f.message}`))),c.on("close",f=>{f!==0&&p&&!u?l(new Error(`Codex CLI failed: ${p}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Codex CLI timed out after 10 minutes"))},6e5)}),s("scan","Scanning generated files..."),this.scanGeneratedFiles(n)}buildFullPrompt(t,o,n){return`Read the conversion guide below, then convert the React landing page at ${t} into native HubSpot CMS modules for the theme at ${o}.
277
+ Create all files directly in the theme directory.`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=ye(e,"css");if(S(s)){for(let r of yn(s))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=x(ye(s,r));break}}let o=ye(e,"js");if(S(o)){for(let r of yn(o))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){n.sharedJs=x(ye(o,r));break}}let i=ye(e,"templates");if(S(i)){for(let r of yn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=x(ye(i,r));if(l.includes("dnd_area")){n.template=l;break}}}let a=ye(e,"modules");if(S(a))for(let r of yn(a)){if(!r.endsWith(".module"))continue;let l=ye(a,r);if(!Ka(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=ye(l,"fields.json");S(d)&&(c.fieldsJson=x(d));let u=ye(l,"meta.json");S(u)&&(c.metaJson=x(u));let p=ye(l,"module.html");S(p)&&(c.moduleHtml=x(p));let g=ye(l,"module.css");S(g)&&(c.moduleCss=x(g));let h=ye(l,"module.js");S(h)&&(c.moduleJs=x(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}};f();import{spawn as Va}from"child_process";import{join as be}from"path";import{readdirSync as Sn,statSync as Ya}from"fs";X();var vn=class{async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||re(),a=this.buildFullPrompt(n,s,i);return o("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Va("codex",["exec","--full-auto",a],{cwd:s,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),d="",u="";c.stdout.on("data",p=>{d+=p.toString()}),c.stderr.on("data",p=>{u+=p.toString()}),c.on("error",p=>l(new Error(`Codex CLI failed: ${p.message}`))),c.on("close",p=>{p!==0&&u&&!d?l(new Error(`Codex CLI failed: ${u}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Codex CLI timed out after 10 minutes"))},6e5)}),o("scan","Scanning generated files..."),this.scanGeneratedFiles(s)}buildFullPrompt(e,n,s){return`Read the conversion guide below, then convert the React landing page at ${e} into native HubSpot CMS modules for the theme at ${n}.
278
278
 
279
279
  INSTRUCTIONS:
280
280
  1. Analyze all .tsx/.jsx components in the React source
@@ -286,92 +286,92 @@ INSTRUCTIONS:
286
286
  7. Make sure base.html supports template_css and template_js variables
287
287
 
288
288
  CONVERSION GUIDE:
289
- ${n}
289
+ ${s}
290
290
 
291
291
  Do NOT run hs upload \u2014 I will handle that separately.
292
- Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=pe(t,"css");if(b(n)){for(let r of an(n))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){o.sharedCss=v(pe(n,r));break}}let s=pe(t,"js");if(b(s)){for(let r of an(s))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){o.sharedJs=v(pe(s,r));break}}let i=pe(t,"templates");if(b(i)){for(let r of an(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=v(pe(i,r));if(l.includes("dnd_area")){o.template=l;break}}}let a=pe(t,"modules");if(b(a))for(let r of an(a)){if(!r.endsWith(".module"))continue;let l=pe(a,r);if(!Yr(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=pe(l,"fields.json");b(u)&&(c.fieldsJson=v(u));let p=pe(l,"meta.json");b(p)&&(c.metaJson=v(p));let f=pe(l,"module.html");b(f)&&(c.moduleHtml=v(f));let g=pe(l,"module.css");b(g)&&(c.moduleCss=v(g));let y=pe(l,"module.js");b(y)&&(c.moduleJs=v(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};Q();function Vr(e,t){switch(e){case"claude-code":return new nn(t);case"gemini-cli":return new rn;case"codex-cli":return new ln;case"api":return new on}}async function cn(e){await re("Converting React to HubSpot Modules"),await Ee(`AI will now analyze your React code and create
293
- HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let t=Vr(e.aiEngine,e.model),o=de(),n=await le();n.start("Starting AI conversion...");let s=Date.now(),i=await t.convert({sourceDir:e.sourceDir,themePath:e.themePath,conversionGuide:o,onProgress:(y,S)=>{y==="created"?P(S):n.message(S)}}),a=((Date.now()-s)/1e3).toFixed(0);n.stop(`AI conversion complete (${a}s)`);let r=zr(e.themePath);for(let y of r)P(`Auto-fixed: ${y}`);let l=qr(e.themePath,i),c=[];for(let y of l){let S=y.passed?"\u2705":"\u274C",w=y.passed?"":y.critical?" (CRITICAL)":" (cosmetic)";c.push(`${S} ${y.label}${w}`)}let u=l.filter(y=>y.passed).length;c.push(`
294
- ${u}/${l.length} checks passed`),await Ee(c.join(`
295
- `),"Conversion Checklist");let p=l.filter(y=>!y.passed&&y.critical),f=l.filter(y=>!y.passed&&!y.critical);if(p.length>0){if(D(`${p.length} critical issue(s) \u2014 upload will likely fail:
296
- `+p.map(S=>` - ${S.label}`).join(`
297
- `)),!await ee({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else f.length>0&&W(`${f.length} non-critical issue(s) \u2014 page will work but may look incomplete:
298
- `+f.map(y=>` - ${y.label}`).join(`
299
- `));let g=ye(e.themePath,"..","vibespot-conversion.log");return b(g)&&(await ee({message:"Keep conversion log file for debugging?",initialValue:!1})?P(`Log saved: ${g}`):ts(g)),await ae("Files ready for upload!"),i}function zr(e){let t=[];Xr(e),Qr(e);let o=ye(e,"modules");if(b(o))for(let s of kt(o)){if(!s.endsWith(".module"))continue;let i=ye(o,s,"fields.json");if(!b(i))continue;let a=s.replace(".module",""),r=v(i),l=!1;r.includes('"textarea"')&&(r=r.replace(/"textarea"/g,'"text"'),l=!0,t.push(`${a}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(r)&&(r=r.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,t.push(`${a}: reserved field name "name" \u2192 "item_name"`));try{let u=JSON.parse(r),p=!1;ns(u)&&(p=!0,t.push(`${a}: fixed choice field format`)),os(u)&&(p=!0,t.push(`${a}: fixed link field default value`)),p&&(r=JSON.stringify(u,null,2)+`
300
- `,l=!0)}catch{t.push(`${a}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&M(i,r);let c=ye(o,s,"module.html");if(b(c)){let u=v(c);u.includes("now()")&&(u=u.replace(/now\(\)/g,"local_dt"),M(c,u),t.push(`${a}: now() \u2192 local_dt`))}}let n=ye(e,"templates");if(b(n))for(let s of kt(n)){if(!s.endsWith(".html"))continue;let i=ye(n,s),a=v(i);(a.includes("hubdb_table")||a.includes("hubdb_table_rows"))&&(ts(i),t.push(`Removed ${s} (HubDB requires CMS Hub Pro/Enterprise)`))}return t}function ns(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;n.type==="choice"&&Array.isArray(n.choices)&&n.choices.some(i=>typeof i=="string")&&(n.choices=n.choices.map(i=>{if(typeof i=="string"){let a=i.charAt(0).toUpperCase()+i.slice(1);return[i,a]}return i}),t=!0),Array.isArray(n.children)&&ns(n.children)&&(t=!0)}return t}function os(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;if(n.type==="link"){let s=n.default;if(typeof s=="string"||s===void 0||s===null||typeof s=="object"&&!s.url){let a=typeof s=="string"?s:"";n.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&os(n.children)&&(t=!0)}return t}function qr(e,t){let o=[],n=t.modules.length;o.push({label:`Modules created (${n})`,passed:n>0,critical:!0});let s=!0;for(let p of t.modules)if(p.fieldsJson.includes('"textarea"')||/"name":\s*"name"/.test(p.fieldsJson)){s=!1;break}o.push({label:"fields.json valid (no textarea, no reserved names)",passed:n>0&&s,critical:!0});let i=t.modules.every(p=>p.moduleHtml.length>0);o.push({label:"module.html created for each module",passed:n>0&&i,critical:!0});let a=t.modules.filter(p=>!p.moduleCss).map(p=>p.moduleName),r=a.length===0;o.push({label:r?"module.css created for each module":`module.css missing for: ${a.join(", ")}`,passed:n>0&&r,critical:!1});let l=t.modules.some(p=>p.fieldsJson.includes('"STYLE"'));o.push({label:"Style tab fields (color pickers)",passed:l,critical:!1}),o.push({label:"Shared CSS with design system variables",passed:t.sharedCss.length>50,critical:!1}),o.push({label:"Shared JS for scroll animations",passed:t.sharedJs.length>50,critical:!1}),o.push({label:"Page template with dnd_area",passed:t.template.length>0&&t.template.includes("dnd_area"),critical:!0});let c=ye(e,"templates"),u=!1;if(b(c))for(let p of kt(c)){if(!p.endsWith(".html")||p==="base.html"||p.startsWith("system"))continue;let f=v(ye(c,p));if(f.includes("dnd_area")&&/templateType\s*:\s*page/i.test(f)){u=!0;break}}return o.push({label:"Template annotations (templateType: page)",passed:u,critical:!0}),o}function Xr(e){let t=ye(e,"templates");if(b(t))for(let o of kt(t)){if(!o.endsWith(".html")||o==="base.html"||o.startsWith("system"))continue;let n=ye(t,o),s=v(n);if(!s.includes("dnd_area")&&!s.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(s),a=/isAvailableForNewContent\s*:\s*true/i.test(s);if(i&&a)continue;let r=o.replace(".html","").replace(/[-_]/g," ").replace(/\b\w/g,l=>l.toUpperCase());if(s.includes("<!--")&&s.indexOf("-->")<200){let l=s.indexOf("-->"),c=s.slice(0,l);i||(c+=`
292
+ Create all files directly in the theme directory.`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=be(e,"css");if(S(s)){for(let r of Sn(s))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=x(be(s,r));break}}let o=be(e,"js");if(S(o)){for(let r of Sn(o))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){n.sharedJs=x(be(o,r));break}}let i=be(e,"templates");if(S(i)){for(let r of Sn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=x(be(i,r));if(l.includes("dnd_area")){n.template=l;break}}}let a=be(e,"modules");if(S(a))for(let r of Sn(a)){if(!r.endsWith(".module"))continue;let l=be(a,r);if(!Ya(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=be(l,"fields.json");S(d)&&(c.fieldsJson=x(d));let u=be(l,"meta.json");S(u)&&(c.metaJson=x(u));let p=be(l,"module.html");S(p)&&(c.moduleHtml=x(p));let g=be(l,"module.css");S(g)&&(c.moduleCss=x(g));let h=be(l,"module.js");S(h)&&(c.moduleJs=x(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}};X();function za(t,e){switch(t){case"claude-code":return new gn(e);case"gemini-cli":return new bn;case"codex-cli":return new vn;case"api":return new hn}}async function wn(t){await le("Converting React to HubSpot Modules"),await _e(`AI will now analyze your React code and create
293
+ HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let e=za(t.aiEngine,t.model),n=re(),s=await de();s.start("Starting AI conversion...");let o=Date.now(),i=await e.convert({sourceDir:t.sourceDir,themePath:t.themePath,conversionGuide:n,onProgress:(h,b)=>{h==="created"?P(b):s.message(b)}}),a=((Date.now()-o)/1e3).toFixed(0);s.stop(`AI conversion complete (${a}s)`);let r=qa(t.themePath);for(let h of r)P(`Auto-fixed: ${h}`);let l=Xa(t.themePath,i),c=[];for(let h of l){let b=h.passed?"\u2705":"\u274C",y=h.passed?"":h.critical?" (CRITICAL)":" (cosmetic)";c.push(`${b} ${h.label}${y}`)}let d=l.filter(h=>h.passed).length;c.push(`
294
+ ${d}/${l.length} checks passed`),await _e(c.join(`
295
+ `),"Conversion Checklist");let u=l.filter(h=>!h.passed&&h.critical),p=l.filter(h=>!h.passed&&!h.critical);if(u.length>0){if(U(`${u.length} critical issue(s) \u2014 upload will likely fail:
296
+ `+u.map(b=>` - ${b.label}`).join(`
297
+ `)),!await ne({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else p.length>0&&K(`${p.length} non-critical issue(s) \u2014 page will work but may look incomplete:
298
+ `+p.map(h=>` - ${h.label}`).join(`
299
+ `));let g=xe(t.themePath,"..","vibespot-conversion.log");return S(g)&&(await ne({message:"Keep conversion log file for debugging?",initialValue:!1})?P(`Log saved: ${g}`):Mo(g)),await ce("Files ready for upload!"),i}function qa(t){let e=[];Qa(t),Za(t);let n=xe(t,"modules");if(S(n))for(let o of jt(n)){if(!o.endsWith(".module"))continue;let i=xe(n,o,"fields.json");if(!S(i))continue;let a=o.replace(".module",""),r=x(i),l=!1;r.includes('"textarea"')&&(r=r.replace(/"textarea"/g,'"text"'),l=!0,e.push(`${a}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(r)&&(r=r.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,e.push(`${a}: reserved field name "name" \u2192 "item_name"`));try{let d=JSON.parse(r),u=!1;No(d)&&(u=!0,e.push(`${a}: fixed choice field format`)),_o(d)&&(u=!0,e.push(`${a}: fixed link field default value`)),u&&(r=JSON.stringify(d,null,2)+`
300
+ `,l=!0)}catch{e.push(`${a}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&F(i,r);let c=xe(n,o,"module.html");if(S(c)){let d=x(c);d.includes("now()")&&(d=d.replace(/now\(\)/g,"local_dt"),F(c,d),e.push(`${a}: now() \u2192 local_dt`))}}let s=xe(t,"templates");if(S(s))for(let o of jt(s)){if(!o.endsWith(".html"))continue;let i=xe(s,o),a=x(i);(a.includes("hubdb_table")||a.includes("hubdb_table_rows"))&&(Mo(i),e.push(`Removed ${o} (HubDB requires CMS Hub Pro/Enterprise)`))}return e}function No(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;s.type==="choice"&&Array.isArray(s.choices)&&s.choices.some(i=>typeof i=="string")&&(s.choices=s.choices.map(i=>{if(typeof i=="string"){let a=i.charAt(0).toUpperCase()+i.slice(1);return[i,a]}return i}),e=!0),Array.isArray(s.children)&&No(s.children)&&(e=!0)}return e}function _o(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="link"){let o=s.default;if(typeof o=="string"||o===void 0||o===null||typeof o=="object"&&!o.url){let a=typeof o=="string"?o:"";s.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},e=!0}}Array.isArray(s.children)&&_o(s.children)&&(e=!0)}return e}function Xa(t,e){let n=[],s=e.modules.length;n.push({label:`Modules created (${s})`,passed:s>0,critical:!0});let o=!0;for(let u of e.modules)if(u.fieldsJson.includes('"textarea"')||/"name":\s*"name"/.test(u.fieldsJson)){o=!1;break}n.push({label:"fields.json valid (no textarea, no reserved names)",passed:s>0&&o,critical:!0});let i=e.modules.every(u=>u.moduleHtml.length>0);n.push({label:"module.html created for each module",passed:s>0&&i,critical:!0});let a=e.modules.filter(u=>!u.moduleCss).map(u=>u.moduleName),r=a.length===0;n.push({label:r?"module.css created for each module":`module.css missing for: ${a.join(", ")}`,passed:s>0&&r,critical:!1});let l=e.modules.some(u=>u.fieldsJson.includes('"STYLE"'));n.push({label:"Style tab fields (color pickers)",passed:l,critical:!1}),n.push({label:"Shared CSS with design system variables",passed:e.sharedCss.length>50,critical:!1}),n.push({label:"Shared JS for scroll animations",passed:e.sharedJs.length>50,critical:!1}),n.push({label:"Page template with dnd_area",passed:e.template.length>0&&e.template.includes("dnd_area"),critical:!0});let c=xe(t,"templates"),d=!1;if(S(c))for(let u of jt(c)){if(!u.endsWith(".html")||u==="base.html"||u.startsWith("system"))continue;let p=x(xe(c,u));if(p.includes("dnd_area")&&/templateType\s*:\s*page/i.test(p)){d=!0;break}}return n.push({label:"Template annotations (templateType: page)",passed:d,critical:!0}),n}function Qa(t){let e=xe(t,"templates");if(S(e))for(let n of jt(e)){if(!n.endsWith(".html")||n==="base.html"||n.startsWith("system"))continue;let s=xe(e,n),o=x(s);if(!o.includes("dnd_area")&&!o.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(o),a=/isAvailableForNewContent\s*:\s*true/i.test(o);if(i&&a)continue;let r=n.replace(".html","").replace(/[-_]/g," ").replace(/\b\w/g,l=>l.toUpperCase());if(o.includes("<!--")&&o.indexOf("-->")<200){let l=o.indexOf("-->"),c=o.slice(0,l);i||(c+=`
301
301
  templateType: page`),a||(c+=`
302
302
  isAvailableForNewContent: true`),/label\s*:/i.test(c)||(c+=`
303
- label: ${r}`),s=c+s.slice(l)}else s=`<!--
303
+ label: ${r}`),o=c+o.slice(l)}else o=`<!--
304
304
  templateType: page
305
305
  isAvailableForNewContent: true
306
306
  label: ${r}
307
307
  -->
308
- `+s;M(n,s),P(`Template "${o}" \u2014 annotations verified`)}}function Qr(e){let t=ye(e,"modules");if(b(t))for(let o of kt(t)){if(!o.endsWith(".module"))continue;let n=ye(t,o,"meta.json");if(b(n))try{let s=JSON.parse(v(n)),i=!1;(!s.host_template_types||!s.host_template_types.includes("PAGE"))&&(s.host_template_types=["PAGE"],i=!0),s.is_available_for_new_content||(s.is_available_for_new_content=!0,i=!0),i&&M(n,JSON.stringify(s,null,2)+`
309
- `)}catch{}}}h();import{join as fs,basename as la}from"path";h();Q();import{join as te}from"path";import{readdirSync as De,rmSync as Zr}from"fs";function dn(e){let t=[];for(let o of e){let n=`${o.message}${o.detail?` \u2014 ${o.detail}`:""}`,s=!1;/textarea|unknown.*field.*type/i.test(n)&&(s=!0),/reserved.*name|missing field name|field null/i.test(n)&&(s=!0),/could not resolve.*now/i.test(n)&&(s=!0),/hubdb|do not have access/i.test(n)&&(s=!0),/invalid default value|link.*invalid|deserializ/i.test(n)&&(s=!0),/color.*invalid/i.test(n)&&(s=!0),t.push({file:o.file||"unknown",message:n,fixable:s})}return t}function un(e){let t=[];if(/textarea.*not.*valid|unknown.*field.*type/i.test(e)){let o=e.match(/(?:in|file:?)\s+(\S+fields\.json)/i);t.push({file:o?.[1]||"fields.json",message:'"textarea" is not a valid field type',fixable:!0})}if(/missing field name|field null/i.test(e)){let o=e.match(/(?:in|file:?)\s+(\S+fields\.json)/i);t.push({file:o?.[1]||"fields.json",message:'"name" is a reserved field name',fixable:!0})}if(/could not resolve.*now/i.test(e)&&t.push({file:"module.html",message:"now() is not a valid HubL function",fixable:!0}),/hubdb|do not have access to hubdb/i.test(e)&&t.push({file:"templates",message:"HubDB requires CMS Hub Pro/Enterprise",fixable:!0}),/invalid default value|link.*field.*invalid/i.test(e)){let o=e.match(/field.*?(\w+)\s+has an invalid/i);t.push({file:o?.[1]||"fields.json",message:"Link field has invalid default value",fixable:!0})}if(/failed to deserialize/i.test(e)){let o=e.match(/file '([^']+)'/i);t.push({file:o?.[1]||"fields.json",message:"fields.json deserialization error",fixable:!0})}return/format for the color value is invalid/i.test(e)&&t.push({file:"fields.json",message:"Color field has invalid format (rgba/rgb/named \u2014 must be hex)",fixable:!0}),t}function mn(e){let t=[];return is(e)&&t.push("textarea \u2192 text"),rs(e)&&t.push("name \u2192 item_name"),as(e)&&t.push("now() \u2192 local_dt"),ls(e)&&t.push("Removed HubDB templates"),cs(e)&&t.push("Fixed link field defaults"),ds(e)&&t.push("Fixed rgba/invalid color values \u2192 hex"),ea(e)&&t.push("Stripped CDN @import statements"),t}function ss(e,t){return t.message.includes("textarea")?is(e):t.message.includes("reserved field name")?rs(e):t.message.includes("now()")?as(e):t.message.includes("HubDB")?ls(e):t.message.includes("invalid default value")||t.message.includes("deserialization")?cs(e):t.message.includes("invalid format")&&t.message.includes("color")?ds(e):!1}function is(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(!b(s))continue;let i=v(s);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),M(s,i),t=!0)}return t}function rs(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(!b(s))continue;let i=v(s);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),M(s,i),t=!0)}return t}function as(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"module.html");if(!b(s))continue;let i=v(s);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),M(s,i),t=!0)}return t}function ls(e){let t=!1,o=te(e,"templates");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".html"))continue;let s=te(o,n),i=v(s);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(Zr(s),t=!0)}return t}function cs(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(b(s))try{let i=JSON.parse(v(s));ms(i)&&(M(s,JSON.stringify(i,null,2)+`
310
- `),t=!0)}catch{}}return t}function ea(e){let t=!1,o=te(e,"css");if(b(o))for(let s of De(o)){if(!s.endsWith(".css"))continue;let i=te(o,s),a=v(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(M(i,r),t=!0)}let n=te(e,"modules");if(b(n))for(let s of De(n)){if(!s.endsWith(".module"))continue;let i=te(n,s,"module.css");if(!b(i))continue;let a=v(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(M(i,r),t=!0)}if(b(n))for(let s of De(n)){if(!s.endsWith(".module"))continue;let i=te(n,s,"module.html");if(!b(i))continue;let a=v(i),r=a.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");r!==a&&(M(i,r),t=!0)}return t}function ds(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(b(s))try{let i=JSON.parse(v(s));us(i)&&(M(s,JSON.stringify(i,null,2)+`
311
- `),t=!0)}catch{}}return t}function us(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;if(n.type==="color"&&n.default&&typeof n.default=="object"){let s=n.default,i=s.color;if(typeof i=="string"&&!ta(i)){let a=na(i);a&&(s.color=a.hex,a.opacity!==void 0&&(s.opacity=a.opacity),t=!0)}}Array.isArray(n.children)&&us(n.children)&&(t=!0)}return t}function ta(e){return/^#[0-9a-fA-F]{6}$/.test(e)}function na(e){let t=e.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);if(t)return{hex:`#${t[1]}${t[1]}${t[2]}${t[2]}${t[3]}${t[3]}`};let o=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/i);if(o){let i=Math.min(255,parseInt(o[1])),a=Math.min(255,parseInt(o[2])),r=Math.min(255,parseInt(o[3])),l=`#${i.toString(16).padStart(2,"0")}${a.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}`,c=o[4]!==void 0?Math.round(parseFloat(o[4])*100):void 0;return{hex:l,opacity:c}}let n={white:"#ffffff",black:"#000000",red:"#ff0000",green:"#008000",blue:"#0000ff",yellow:"#ffff00",orange:"#ffa500",purple:"#800080",gray:"#808080",grey:"#808080",transparent:"#000000"},s=e.toLowerCase().trim();return n[s]?{hex:n[s],opacity:s==="transparent"?0:void 0}:null}function ms(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;if(n.type==="link"){let s=n.default;if(typeof s=="string"||s===void 0||s===null||typeof s=="object"&&!s.url){let a=typeof s=="string"?s:"";n.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&ms(n.children)&&(t=!0)}return t}Z();h();Ye();Ye();import{readdirSync as oa}from"fs";import{join as sa,relative as ia}from"path";var ra=new Set([".git","node_modules",".vibespot",".DS_Store"]);function ps(e){let t=[];for(let o of oa(e,{withFileTypes:!0})){if(ra.has(o.name)||o.name.startsWith(".")&&o.name!==".gitkeep")continue;let n=sa(e,o.name);o.isDirectory()?t.push(...ps(n)):o.isFile()&&t.push(n)}return t}async function aa(e,t,o){let n=0;async function s(){for(;n<e.length;){let a=n++;await o(e[a])}}let i=Array.from({length:Math.min(t,e.length)},()=>s());await Promise.all(i)}async function pn(e,t,o,n={}){let s=n.concurrency??5,i=ps(t),a=i.length,r=0,l=0,c=[];return await aa(i,s,async u=>{let p=ia(t,u).replace(/\\/g,"/"),f=`${o}/${p}`;n.onFileStart?.(p);let g=await Oo(e,f,u);if(g.success)r++,n.onFileComplete?.(p);else{l++;let y={file:p,status:g.error?.status||0,message:g.error?.message||"Unknown error",category:g.error?.category,detail:g.error?.detail};c.push(y),n.onFileError?.(p,y)}n.onProgress?.(r+l,a)}),{success:l===0,uploaded:r,failed:l,total:a,errors:c}}function ca(e){return(e.match(/^Uploaded file /gm)||[]).length}async function lt(e){await re("Uploading to HubSpot");let t=la(e)||e,o=N(),n=ue(),s=o.hubspotUploadMode!=="cli"&&!!n,i=await le(),a=3;for(let r=1;r<=a;r++){i.start(r===1?"Uploading theme...":`Retrying upload (attempt ${r}/${a})...`);let l=[],c=0,u=!1;if(s){let f=await pn(n,e,t,{onFileComplete:()=>{c++}});u=f.success,u?c=f.uploaded:l=dn(f.errors)}else{let f=A(`hs cms upload "${e}" "${t}"`,{cwd:fs(e,"..")}),g=[f.stdout,f.stderr].filter(Boolean).join(`
312
- `);c=ca(g),u=f.success,u||(l=un(g))}if(u)return i.stop(`All files uploaded! (${c} files)`),await ae("Upload complete!"),!0;if(c>0?i.stop(`${c} files uploaded, but some errors occurred`):i.stop("Upload failed"),l.length===0){if(D("Upload failed with unknown error."),c>0&&(W(`Most files uploaded successfully. The theme may already be usable in HubSpot.
313
- You can check your HubSpot Design Manager to verify.`),await ee({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(r<a){if(!await ee({message:"Try uploading again?"}))break;continue}break}let p=!1;for(let f of l)f.fixable?ss(e,f)?(P(`Auto-fixed: ${f.message}`),p=!0):W(`Could not auto-fix: ${f.message}`):D(f.message);if(!(p&&r<a)){if(c>0&&(W(`${c} files uploaded successfully despite errors.
314
- The theme may work \u2014 check HubSpot Design Manager.`),await ee({message:"Continue anyway?",initialValue:!0})))return!0;if(!p){if(i.start("Cleaning up stuck modules..."),s)try{await Jn(n,`${t}/modules`)}catch{}else A(`hs cms delete "${t}/modules"`,{cwd:fs(e,"..")});i.stop("Cleaned up modules, retrying...")}}}return D("Upload failed after multiple attempts."),!1}h();import{execSync as Un}from"child_process";import{rmSync as da}from"fs";import{basename as gs}from"path";Q();async function hs(e){let{portalId:t,sourceDir:o,themePath:n,wasCloned:s}=e;await re("You're all set!");let a=wt(t)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await Ee(`Your React page has been converted and uploaded to HubSpot.
308
+ `+o;F(s,o),P(`Template "${n}" \u2014 annotations verified`)}}function Za(t){let e=xe(t,"modules");if(S(e))for(let n of jt(e)){if(!n.endsWith(".module"))continue;let s=xe(e,n,"meta.json");if(S(s))try{let o=JSON.parse(x(s)),i=!1;(!o.host_template_types||!o.host_template_types.includes("PAGE"))&&(o.host_template_types=["PAGE"],i=!0),o.is_available_for_new_content||(o.is_available_for_new_content=!0,i=!0),i&&F(s,JSON.stringify(o,null,2)+`
309
+ `)}catch{}}}f();import{join as Uo,basename as cl}from"path";f();X();import{join as se}from"path";import{readdirSync as Ue,rmSync as el}from"fs";function xn(t){let e=[];for(let n of t){let s=`${n.message}${n.detail?` \u2014 ${n.detail}`:""}`,o=!1;/textarea|unknown.*field.*type/i.test(s)&&(o=!0),/reserved.*name|missing field name|field null/i.test(s)&&(o=!0),/could not resolve.*now/i.test(s)&&(o=!0),/hubdb|do not have access/i.test(s)&&(o=!0),/invalid default value|link.*invalid|deserializ/i.test(s)&&(o=!0),/color.*invalid/i.test(s)&&(o=!0),e.push({file:n.file||"unknown",message:s,fixable:o})}return e}function Cn(t){let e=[];if(/textarea.*not.*valid|unknown.*field.*type/i.test(t)){let n=t.match(/(?:in|file:?)\s+(\S+fields\.json)/i);e.push({file:n?.[1]||"fields.json",message:'"textarea" is not a valid field type',fixable:!0})}if(/missing field name|field null/i.test(t)){let n=t.match(/(?:in|file:?)\s+(\S+fields\.json)/i);e.push({file:n?.[1]||"fields.json",message:'"name" is a reserved field name',fixable:!0})}if(/could not resolve.*now/i.test(t)&&e.push({file:"module.html",message:"now() is not a valid HubL function",fixable:!0}),/hubdb|do not have access to hubdb/i.test(t)&&e.push({file:"templates",message:"HubDB requires CMS Hub Pro/Enterprise",fixable:!0}),/invalid default value|link.*field.*invalid/i.test(t)){let n=t.match(/field.*?(\w+)\s+has an invalid/i);e.push({file:n?.[1]||"fields.json",message:"Link field has invalid default value",fixable:!0})}if(/failed to deserialize/i.test(t)){let n=t.match(/file '([^']+)'/i);e.push({file:n?.[1]||"fields.json",message:"fields.json deserialization error",fixable:!0})}return/format for the color value is invalid/i.test(t)&&e.push({file:"fields.json",message:"Color field has invalid format (rgba/rgb/named \u2014 must be hex)",fixable:!0}),e}function An(t){let e=[];return Ro(t)&&e.push("textarea \u2192 text"),Oo(t)&&e.push("name \u2192 item_name"),jo(t)&&e.push("now() \u2192 local_dt"),Fo(t)&&e.push("Removed HubDB templates"),Jo(t)&&e.push("Fixed link field defaults"),Do(t)&&e.push("Fixed rgba/invalid color values \u2192 hex"),tl(t)&&e.push("Stripped CDN @import statements"),e}function Po(t,e){return e.message.includes("textarea")?Ro(t):e.message.includes("reserved field name")?Oo(t):e.message.includes("now()")?jo(t):e.message.includes("HubDB")?Fo(t):e.message.includes("invalid default value")||e.message.includes("deserialization")?Jo(t):e.message.includes("invalid format")&&e.message.includes("color")?Do(t):!1}function Ro(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(!S(o))continue;let i=x(o);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),F(o,i),e=!0)}return e}function Oo(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(!S(o))continue;let i=x(o);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),F(o,i),e=!0)}return e}function jo(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"module.html");if(!S(o))continue;let i=x(o);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),F(o,i),e=!0)}return e}function Fo(t){let e=!1,n=se(t,"templates");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".html"))continue;let o=se(n,s),i=x(o);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(el(o),e=!0)}return e}function Jo(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(S(o))try{let i=JSON.parse(x(o));Lo(i)&&(F(o,JSON.stringify(i,null,2)+`
310
+ `),e=!0)}catch{}}return e}function tl(t){let e=!1,n=se(t,"css");if(S(n))for(let o of Ue(n)){if(!o.endsWith(".css"))continue;let i=se(n,o),a=x(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(F(i,r),e=!0)}let s=se(t,"modules");if(S(s))for(let o of Ue(s)){if(!o.endsWith(".module"))continue;let i=se(s,o,"module.css");if(!S(i))continue;let a=x(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(F(i,r),e=!0)}if(S(s))for(let o of Ue(s)){if(!o.endsWith(".module"))continue;let i=se(s,o,"module.html");if(!S(i))continue;let a=x(i),r=a.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");r!==a&&(F(i,r),e=!0)}return e}function Do(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(S(o))try{let i=JSON.parse(x(o));Ho(i)&&(F(o,JSON.stringify(i,null,2)+`
311
+ `),e=!0)}catch{}}return e}function Ho(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="color"&&s.default&&typeof s.default=="object"){let o=s.default,i=o.color;if(typeof i=="string"&&!nl(i)){let a=sl(i);a&&(o.color=a.hex,a.opacity!==void 0&&(o.opacity=a.opacity),e=!0)}}Array.isArray(s.children)&&Ho(s.children)&&(e=!0)}return e}function nl(t){return/^#[0-9a-fA-F]{6}$/.test(t)}function sl(t){let e=t.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);if(e)return{hex:`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`};let n=t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/i);if(n){let i=Math.min(255,parseInt(n[1])),a=Math.min(255,parseInt(n[2])),r=Math.min(255,parseInt(n[3])),l=`#${i.toString(16).padStart(2,"0")}${a.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}`,c=n[4]!==void 0?Math.round(parseFloat(n[4])*100):void 0;return{hex:l,opacity:c}}let s={white:"#ffffff",black:"#000000",red:"#ff0000",green:"#008000",blue:"#0000ff",yellow:"#ffff00",orange:"#ffa500",purple:"#800080",gray:"#808080",grey:"#808080",transparent:"#000000"},o=t.toLowerCase().trim();return s[o]?{hex:s[o],opacity:o==="transparent"?0:void 0}:null}function Lo(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="link"){let o=s.default;if(typeof o=="string"||o===void 0||o===null||typeof o=="object"&&!o.url){let a=typeof o=="string"?o:"";s.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},e=!0}}Array.isArray(s.children)&&Lo(s.children)&&(e=!0)}return e}ee();f();tt();tt();import{readdirSync as ol}from"fs";import{join as il,relative as rl}from"path";var al=new Set([".git","node_modules",".vibespot",".DS_Store"]);function Go(t){let e=[];for(let n of ol(t,{withFileTypes:!0})){if(al.has(n.name)||n.name.startsWith(".")&&n.name!==".gitkeep")continue;let s=il(t,n.name);n.isDirectory()?e.push(...Go(s)):n.isFile()&&e.push(s)}return e}async function ll(t,e,n){let s=0;async function o(){for(;s<t.length;){let a=s++;await n(t[a])}}let i=Array.from({length:Math.min(e,t.length)},()=>o());await Promise.all(i)}async function In(t,e,n,s={}){let o=s.concurrency??5,i=Go(e),a=i.length,r=0,l=0,c=[];return await ll(i,o,async d=>{let u=rl(e,d).replace(/\\/g,"/"),p=`${n}/${u}`;s.onFileStart?.(u);let g=await lo(t,p,d);if(g.success)r++,s.onFileComplete?.(u);else{l++;let h={file:u,status:g.error?.status||0,message:g.error?.message||"Unknown error",category:g.error?.category,detail:g.error?.detail};c.push(h),s.onFileError?.(u,h)}s.onProgress?.(r+l,a)}),{success:l===0,uploaded:r,failed:l,total:a,errors:c}}function dl(t){return(t.match(/^Uploaded file /gm)||[]).length}async function gt(t){await le("Uploading to HubSpot");let e=cl(t)||t,n=E(),s=he(),o=n.hubspotUploadMode!=="cli"&&!!s,i=await de(),a=3;for(let r=1;r<=a;r++){i.start(r===1?"Uploading theme...":`Retrying upload (attempt ${r}/${a})...`);let l=[],c=0,d=!1;if(o){let p=await In(s,t,e,{onFileComplete:()=>{c++}});d=p.success,d?c=p.uploaded:l=xn(p.errors)}else{let p=$(`hs cms upload "${t}" "${e}"`,{cwd:Uo(t,"..")}),g=[p.stdout,p.stderr].filter(Boolean).join(`
312
+ `);c=dl(g),d=p.success,d||(l=Cn(g))}if(d)return i.stop(`All files uploaded! (${c} files)`),await ce("Upload complete!"),!0;if(c>0?i.stop(`${c} files uploaded, but some errors occurred`):i.stop("Upload failed"),l.length===0){if(U("Upload failed with unknown error."),c>0&&(K(`Most files uploaded successfully. The theme may already be usable in HubSpot.
313
+ You can check your HubSpot Design Manager to verify.`),await ne({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(r<a){if(!await ne({message:"Try uploading again?"}))break;continue}break}let u=!1;for(let p of l)p.fixable?Po(t,p)?(P(`Auto-fixed: ${p.message}`),u=!0):K(`Could not auto-fix: ${p.message}`):U(p.message);if(!(u&&r<a)){if(c>0&&(K(`${c} files uploaded successfully despite errors.
314
+ The theme may work \u2014 check HubSpot Design Manager.`),await ne({message:"Continue anyway?",initialValue:!0})))return!0;if(!u){if(i.start("Cleaning up stuck modules..."),o)try{await es(s,`${e}/modules`)}catch{}else $(`hs cms delete "${e}/modules"`,{cwd:Uo(t,"..")});i.stop("Cleaned up modules, retrying...")}}}return U("Upload failed after multiple attempts."),!1}f();import{execFileSync as is}from"child_process";import{rmSync as ul}from"fs";import{basename as Wo}from"path";X();async function Bo(t){let{portalId:e,sourceDir:n,themePath:s,wasCloned:o}=t;await le("You're all set!");let a=Et(e)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await _e(`Your React page has been converted and uploaded to HubSpot.
315
315
  The theme and modules are now in your account, but you still
316
- need to ${C.bold("create a new landing page")} that uses them.
316
+ need to ${k.bold("create a new landing page")} that uses them.
317
317
 
318
318
  Next steps:
319
319
 
320
- ${C.bold("1.")} Go to HubSpot ${C.muted("\u2192")} Content ${C.muted("\u2192")} Landing Pages ${C.muted("\u2192")} Create
321
- ${C.bold("2.")} Choose your uploaded theme from the theme picker
322
- ${C.bold("3.")} Select the landing page template that was just created
323
- ${C.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
324
- ${C.bold("5.")} Click each section to edit text, images, and colors
325
- ${C.bold("6.")} Upload images via File Manager ${C.muted("(Settings \u2192 Files)")}
326
- ${C.bold("7.")} Preview and publish!`,"What's next"),await ee({message:"Open HubSpot Landing Pages in your browser?"})){let c=t?`https://${a}/page-ui/${t}/management/pages/landing`:`https://${a}`;try{let u=process.platform;u==="darwin"?Un(`open "${c}"`):u==="win32"?Un(`cmd /c start "${c}"`):Un(`xdg-open "${c}"`),P("Opening HubSpot Landing Pages...")}catch{B(`Open this URL in your browser: ${C.info(c)}`)}}let l=[];if(s&&b(o)&&l.push({path:o,label:`Cloned source (${gs(o)})`}),b(n)&&l.push({path:n,label:`Theme directory (${gs(n)})`}),l.length>0&&await ee({message:"Clean up local working directories?"}))for(let u of l)try{da(u.path,{recursive:!0,force:!0}),P(`Removed ${u.label}`)}catch{W(`Could not remove ${u.label} \u2014 delete manually if needed.`)}await ae(`Thanks for using hub${C.vibes("Vibes")}! ${C.vibes("~")}`)}Z();async function ys(){Te();let e=await qt(),t=await Xt();z({lastSourcePath:t.sourceDir});let o=await tn();z({lastThemePath:o.themePath}),await cn({aiEngine:e.aiEngine,model:e.model,sourceDir:t.sourceDir,themePath:o.themePath}),await lt(o.themePath),await hs({portalId:e.portalId,sourceDir:t.sourceDir,themePath:o.themePath,wasCloned:t.wasCloned})}h();async function bs(){Te(),await qt()}h();Z();async function Ss(){Te();let e=N();e.aiEngine||(D("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let t=await Xt(),o=await tn();await cn({aiEngine:e.aiEngine,sourceDir:t.sourceDir,themePath:o.themePath})}h();Z();async function vs(){Te();let e=N();if(e.lastThemePath)if(await ee({message:`Upload from ${e.lastThemePath}?`}))await lt(e.lastThemePath);else{let o=await ve({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await lt(o)}else{let t=await ve({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:o=>o.trim()?void 0:"Path is required"});await lt(t)}}h();Z();async function ws(){Te(),await re("Environment Diagnostics");let e=0,t=bt();t.found?Kt(t.version)?P(`Node.js v${t.version}`):(W(`Node.js v${t.version} \u2014 too old (need 18+)`),B(" Update at https://nodejs.org"),e++):(D("Node.js \u2014 not installed"),B(" Install from https://nodejs.org"),e++);let o=St();o.found?P(`Git ${o.version}`):(D("Git \u2014 not installed"),B(" Install from https://git-scm.com"),e++);let n=$e();if(!n.found)W("HubSpot CLI \u2014 not installed (only needed for deployment)"),B(" Install: npm install -g @hubspot/cli");else if(!_o(n.version))W(`HubSpot CLI v${n.version} \u2014 too old (need v8+)`),B(" Update: npm install -g @hubspot/cli@latest"),e++;else{P(`HubSpot CLI v${n.version}`);let f=ke();f.authenticated?P(`HubSpot portal${f.portalName?`: ${f.portalName}`:""} (ID: ${f.portalId})`):(W("HubSpot \u2014 not authenticated"),B(" Run: hs init"))}let s=vt();s.found?P(`Claude Code ${s.version} at ${s.path}`):B(C.muted("Claude Code \u2014 not installed"));let i=xt();i.found?P(`Gemini CLI ${i.version} at ${i.path}`):B(C.muted("Gemini CLI \u2014 not installed"));let a=Ct();a.found?P(`OpenAI Codex ${a.version} at ${a.path}`):B(C.muted("OpenAI Codex \u2014 not installed"));let r=N(),l=!!(r.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(r.openaiApiKey||process.env.OPENAI_API_KEY),u=!!(r.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?P("Anthropic API key configured"):B(C.muted("Anthropic API key \u2014 not set")),c?P("OpenAI API key configured"):B(C.muted("OpenAI API key \u2014 not set")),u?P("Google AI API key configured"):B(C.muted("Google AI API key \u2014 not set"));let p={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"};r.aiEngine&&P(`AI engine: ${p[r.aiEngine]||r.aiEngine}`),r.lastThemePath&&B(C.muted(`Last theme: ${r.lastThemePath}`)),!s.found&&!i.found&&!a.found&&!l&&!c&&!u&&(W("No AI engine available"),B(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),B(" Or install: Claude Code \u2014 https://claude.ai/code"),B(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),B(" Codex CLI \u2014 https://github.com/openai/codex"),e++),console.log(),e===0?await ae("Everything looks good!"):await ae(C.warn(`${e} issue${e>1?"s":""} found \u2014 see above`))}h();import{join as En}from"path";import{existsSync as Jl}from"fs";import{execSync as bo}from"child_process";import Nn from"chalk";h();import{createServer as Nl}from"http";import{readFileSync as ho,existsSync as yo}from"fs";import{join as kn,extname as mr}from"path";import{createHash as _l}from"crypto";import{WebSocketServer as Rl}from"ws";h();import{readFileSync as fe,readdirSync as Ue,existsSync as J,writeFileSync as ne,mkdirSync as Ge,rmSync as Et,renameSync as Bn}from"fs";import{join as x,dirname as fa}from"path";import{homedir as ga}from"os";h();import{existsSync as Je,writeFileSync as ua,mkdirSync as ma}from"fs";import{join as _e}from"path";var fn=null;function xe(){return fn!==null||(fn=A("git --version").success),fn}function Wn(e){if(!xe())return!1;if(Je(_e(e,".git")))return xs(e),!0;let t=A("git init",{cwd:e});return t.success?(pa(e),xs(e),A("git add -A",{cwd:e}),A('git commit -m "Initial theme"',{cwd:e}),!0):(console.warn(`[project-git] git init failed in ${e}: ${t.stderr}`),!1)}function xs(e){let t=_e(e,".vibespot");Je(t)||ma(t,{recursive:!0})}function pa(e){let t=_e(e,".gitignore");ua(t,[".vibespot/","node_modules/",""].join(`
327
- `),"utf-8")}function Kn(e,t){if(!xe()||!Je(_e(e,".git"))||(A("git add -A",{cwd:e}),A("git diff --cached --quiet",{cwd:e}).success))return null;let n=t.length>72?t.slice(0,69)+"...":t,s=A(`git commit -m "${n.replace(/"/g,'\\"')}"`,{cwd:e});if(!s.success)return console.warn(`[project-git] commit failed: ${s.stderr}`),null;let i=A("git rev-parse --short HEAD",{cwd:e});return i.success?i.stdout:null}function Cs(e,t,o,n){if(!xe()||!Je(_e(e,".git")))return null;for(let p of n){let f=_e(e,p);Je(f)&&A(`git add "${p}"`,{cwd:e})}if(A("git diff --cached --quiet",{cwd:e}).success)return null;let i=`[${t}] `,a=72-i.length,r=o.length>a?o.slice(0,a-3)+"...":o,l=i+r,c=A(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:e});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let u=A("git rev-parse --short HEAD",{cwd:e});return u.success?u.stdout:null}function As(e,t=50){if(!xe())return[];if(!Je(_e(e,".git")))return[];let o=A(`git log --pretty=format:"%h|%H|%s|%at" -n ${t}`,{cwd:e});if(!o.success||!o.stdout.trim())return[];let n=[];for(let s of o.stdout.split(`
328
- `)){let i=s.split("|");if(i.length<4)continue;let a=parseInt(i[3],10)*1e3;n.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:a,date:new Date(a).toISOString()})}return n}function Is(e,t,o=50){if(!xe())return[];if(!Je(_e(e,".git")))return[];let n=t.replace(/[[\]\\]/g,"\\$&"),s=A(`git log --grep="\\[${n}\\]" --pretty=format:"%h|%H|%s|%at" -n ${o}`,{cwd:e});if(!s.success||!s.stdout.trim())return[];let i=[];for(let a of s.stdout.split(`
329
- `)){let r=a.split("|");if(r.length<4)continue;let l=parseInt(r[3],10)*1e3;i.push({hash:r[0],fullHash:r[1],message:r[2],timestamp:l,date:new Date(l).toISOString()})}return i}function Ts(e,t){if(!xe())return{success:!1,error:"Git not available"};if(!Je(_e(e,".git")))return{success:!1,error:"Not a git repo"};let o=A(`git cat-file -t ${t}`,{cwd:e});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${t} not found`};let n=A(`git log --format="%s" -1 ${t}`,{cwd:e}),s=n.success?n.stdout:t,i=A(`git checkout ${t} -- .`,{cwd:e});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let a=`Rollback to: ${s}`.slice(0,72);return A(`git commit -m "${a.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}function $s(e,t,o,n){if(!xe())return{success:!1,error:"Git not available"};if(!Je(_e(e,".git")))return{success:!1,error:"Not a git repo"};let s=A(`git cat-file -t ${o}`,{cwd:e});if(!s.success||s.stdout.trim()!=="commit")return{success:!1,error:`Commit ${o} not found`};let i=A(`git log --format="%s" -1 ${o}`,{cwd:e}),a=i.success?i.stdout:o,r=0;for(let u of n)A(`git checkout ${o} -- "${u}"`,{cwd:e}).success&&r++;if(r===0)return{success:!1,error:"No files could be restored from that commit"};A("git add -A",{cwd:e});let c=`${`[${t}] `}Rollback to: ${a}`.slice(0,72);return A(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}var q=x(ga(),".vibespot","sessions"),Yn=x(q,"_index.json"),ct=null;function gn(){if(ct)return ct;try{return J(Yn)?(ct=JSON.parse(fe(Yn,"utf-8")),ct):Vn()}catch{return Vn()}}function hn(e){ct=e;try{Ge(q,{recursive:!0}),ne(Yn,JSON.stringify(e),"utf-8")}catch{}}function Vn(){if(!J(q))return[];let e=[];for(let t of Ue(q).filter(o=>o.endsWith(".json")&&o!=="_index.json"))try{let o=JSON.parse(fe(x(q,t),"utf-8")),n=o.templates||[];e.push({id:o.id,themeName:o.themeName,updatedAt:o.updatedAt,moduleCount:n.reduce((s,i)=>s+(i.modules?.length||0),0),templateCount:n.length})}catch{}return ct=e,hn(e),e}function ha(e){let t=gn(),o=e.templates||[],n={id:e.id,themeName:e.themeName,updatedAt:e.updatedAt,moduleCount:o.reduce((i,a)=>i+(a.modules?.length||0),0),templateCount:o.length},s=t.findIndex(i=>i.id===e.id);s>=0?t[s]=n:t.push(n),hn(t)}function ya(e){let t=gn().filter(o=>o.id!==e);hn(t)}function ba(e){let t=gn().filter(o=>o.themeName!==e);hn(t)}var m=null;function Nt(e,t){let o={id:Ea(),themePath:e,themeName:t,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return m=o,Wn(e),o}function Es(e){if(e.templates&&e.templates.length>0)return;if(!e.modules||e.modules.length===0){e.templates=[],e.activeTemplateId="";return}let t=`lp-${e.themeName}`,o={id:t,label:`${e.themeName} Landing Page`,pageType:"landing_page",templateFile:`templates/lp-${e.themeName}.html`,modules:[...e.modules],moduleOrder:[...e.moduleOrder],sharedCss:e.sharedCss||"",sharedJs:e.sharedJs||"",template:e.template||"",messages:[...e.messages]};e.templates=[o],e.activeTemplateId=t}function Fe(){return!m||!m.activeTemplateId||!m.templates?.length?null:m.templates.find(e=>e.id===m.activeTemplateId)||null}function zn(e){if(!m)return!1;let t=m.templates.find(o=>o.id===e);return t?(m.activeTemplateId=e,_t(t),m.updatedAt=Date.now(),!0):!1}function Ns(e,t){if(!m)throw new Error("No active session");let o=t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),s=`${e==="blog_post"?"bp":e==="website_page"?"wp":e==="module_only"?"mo":"lp"}-${o}`,i={id:s,label:t,pageType:e,templateFile:e==="module_only"?"":`templates/${s}.html`,modules:[],moduleOrder:[],sharedCss:"",sharedJs:"",template:"",messages:[]};return m.templates.push(i),m.activeTemplateId=s,_t(i),m.updatedAt=Date.now(),i}function _s(e,t){if(!m)return null;let o=m.templates.find(l=>l.id===e);if(!o)return null;let n=t||`${o.label} (Copy)`,s=n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),a=`${o.pageType==="blog_post"?"bp":o.pageType==="website_page"?"wp":o.pageType==="module_only"?"mo":"lp"}-${s}`,r={id:a,label:n,pageType:o.pageType,templateFile:o.pageType==="module_only"?"":`templates/${a}.html`,modules:o.modules.map(l=>({...l})),moduleOrder:[...o.moduleOrder],sharedCss:o.sharedCss,sharedJs:o.sharedJs,template:o.template,messages:[]};return m.templates.push(r),m.activeTemplateId=a,_t(r),m.updatedAt=Date.now(),r}function Rs(e,t){if(!m)return!1;let o=m.templates.find(n=>n.id===e);return o?(o.label=t,m.updatedAt=Date.now(),!0):!1}function Ps(e){if(!m)return!1;let t=m.templates.findIndex(o=>o.id===e);return t<0?!1:(m.templates.splice(t,1),m.activeTemplateId===e&&(m.templates.length>0?zn(m.templates[0].id):(m.activeTemplateId="",m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",m.messages=[])),m.updatedAt=Date.now(),!0)}function dt(){if(!m)return[];let e=new Map;for(let t of m.templates)for(let o of t.modules){let n=e.get(o.moduleName);n?n.usedIn.push(t.label):e.set(o.moduleName,{module:o,usedIn:[t.label]})}return Array.from(e.values())}function _t(e){m&&(m.modules=e.modules,m.moduleOrder=e.moduleOrder,m.sharedCss=e.sharedCss,m.sharedJs=e.sharedJs,m.template=e.template,m.messages=e.messages)}function Ve(){if(!m)return;let e=Fe();e&&(e.modules=m.modules,e.moduleOrder=m.moduleOrder,e.sharedCss=m.sharedCss,e.sharedJs=m.sharedJs,e.template=m.template,e.messages=m.messages)}function $(){return m}function ze(e,t){m&&(m.messages.push({role:e,content:t,timestamp:Date.now()}),m.updatedAt=Date.now(),Ve(),wa())}function Os(e){m&&(m.assets||(m.assets=[]),m.assets.push(e),m.updatedAt=Date.now(),j())}function yn(e){if(m){if(e.sharedCss!==void 0&&(m.sharedCss=e.sharedCss),e.sharedJs!==void 0&&(m.sharedJs=e.sharedJs),e.template!==void 0&&(m.template=e.template),e.modules)for(let t of e.modules){let o=m.modules.findIndex(n=>n.moduleName===t.moduleName);o>=0?m.modules[o]=t:(m.modules.push(t),m.moduleOrder.push(t.moduleName))}m.updatedAt=Date.now(),Ve()}}function Ms(e){m&&(m.moduleOrder=e,m.updatedAt=Date.now(),Ve())}function js(e){m&&(m.modules=m.modules.filter(t=>t.moduleName!==e),m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),Ve())}function Ds(e){m&&(m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),Ve())}function Js(e,t,o){if(!m)return;let n=m.modules.find(s=>s.moduleName===e);if(n)try{let s=JSON.parse(n.fieldsJson);Us(s,t,o),n.fieldsJson=JSON.stringify(s,null,2),m.updatedAt=Date.now(),Ve()}catch{}}function be(){if(!m)return[];let e=[];for(let t of m.moduleOrder){let o=m.modules.find(n=>n.moduleName===t);o&&e.push(o)}for(let t of m.modules)m.moduleOrder.includes(t.moduleName)||e.push(t);return e}function Sa(e,t){let o=ie(e);if(!o||t==="home.html"||t.endsWith("-listing.html"))return null;let n=t.replace(/\.html$/,""),s="landing_page";n.startsWith("bp-")?s="blog_post":n.startsWith("wp-")?s="website_page":n.startsWith("mo-")&&(s="module_only");let i=n,a=o.match(/<!--[\s\S]*?label:\s*"?([^"\n]+)"?\s*[\s\S]*?-->/);a&&(i=a[1].trim());let r=/dnd_module\s+path=["']\.\.\/modules\/(.+?)\.module["']/g,l=[],c;for(;(c=r.exec(o))!==null;)l.push(c[1]);return{id:n,label:i,pageType:s,moduleNames:l,templateContent:o,filename:t}}function va(e,t,o,n,s){if(!J(e))return[];let i=[],a=Ue(e).filter(r=>r.endsWith(".html")&&r!=="home.html");for(let r of a){let l=x(e,r),c=Sa(l,r);if(!c||c.moduleNames.length===0&&i.length>0)continue;let u=[],p=[];for(let f of c.moduleNames){let g=t.get(f);g&&(u.push(g),p.push(f))}i.push({id:c.id,label:c.label,pageType:c.pageType,templateFile:`templates/${c.filename}`,modules:u,moduleOrder:p,sharedCss:o,sharedJs:n,template:c.templateContent,messages:i.length===0?[...s]:[]})}return i}function Rt(e){if(!m)return;let t=xa(e);t.length>0&&m.messages.length===0&&(m.messages=t),Wn(e);let o=x(e,"modules");if(!J(o))return;let n=Ue(o,{withFileTypes:!0});for(let g of n){if(!g.isDirectory()||!g.name.endsWith(".module"))continue;let y=x(o,g.name),S=g.name.replace(/\.module$/,""),w={moduleName:S,fieldsJson:ie(x(y,"fields.json")),metaJson:ie(x(y,"meta.json")),moduleHtml:ie(x(y,"module.html")),moduleCss:ie(x(y,"module.css")),moduleJs:ie(x(y,"module.js"))||void 0};w.fieldsJson&&w.moduleHtml&&(m.modules.push(w),m.moduleOrder.push(S))}let s=x(e,"css"),i=x(e,"js"),a="",r="";if(J(s)){let g=Ue(s).filter(y=>y.endsWith("-theme.css"));g.length>0&&(a=ie(x(s,g[0])),m.sharedCss=a)}if(J(i)){let g=Ue(i).filter(y=>y.endsWith("-animations.js"));g.length>0&&(r=ie(x(i,g[0])),m.sharedJs=r)}let l=x(e,".vibespot","styleguide.md"),c=x(e,".vibespot","brandvoice.md");(J(l)||J(c))&&(m.brandAssets||(m.brandAssets={}),J(l)&&(m.brandAssets.styleguide=ie(l)),J(c)&&(m.brandAssets.brandvoice=ie(c)));let u=x(e,"templates"),p=new Map(m.modules.map(g=>[g.moduleName,g])),f=va(u,p,a,r,m.messages);if(f.length>0){m.templates=f,m.activeTemplateId=f[0].id;let g=f[0].moduleOrder;if(g.length>0){let y=new Set(m.moduleOrder),S=g.filter(w=>y.has(w));for(let w of m.moduleOrder)S.includes(w)||S.push(w);m.moduleOrder=S}_t(f[0])}else m.templates||(m.templates=[]),m.activeTemplateId||(m.activeTemplateId=""),Es(m)}function j(){if(!m)return;Ge(q,{recursive:!0});let e=x(q,`${m.id}.json`);ne(e,JSON.stringify(m,null,2),"utf-8"),ha(m)}function bn(e){let t=x(q,e+".json");if(!J(t))return null;try{let o=JSON.parse(fe(t,"utf-8"));return o.templates||(o.templates=[]),o.activeTemplateId||(o.activeTemplateId=""),Es(o),m=o,o}catch{return null}}function ut(){return J(q)?gn():[]}function Fs(e,t=!1){let o=x(q,e+".json"),n="";if(t)try{let s=JSON.parse(fe(o,"utf-8"));n=s.themeName||"",s.themePath&&J(s.themePath)&&Et(s.themePath,{recursive:!0,force:!0})}catch{}else try{n=JSON.parse(fe(o,"utf-8")).themeName||""}catch{}try{J(o)&&Et(o)}catch{}if(n&&J(q)){for(let s of Ue(q).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(fe(x(q,s),"utf-8")).themeName===n&&Et(x(q,s))}catch{}ba(n)}else ya(e);m?.id===e&&(m=null)}function Hs(e,t){let o=x(q,e+".json");if(!J(o))return{ok:!1,error:"Session not found"};let n;try{n=JSON.parse(fe(o,"utf-8"))}catch{return{ok:!1,error:"Failed to read session"}}let s=n.themeName;if(s===t)return{ok:!0};let i=n.themePath,a=x(fa(i),t);if(J(i)){if(J(a))return{ok:!1,error:"A project with that name already exists"};try{Bn(i,a)}catch(f){return{ok:!1,error:`Failed to rename folder: ${f instanceof Error?f.message:String(f)}`}}let r=x(a,"css",`${s}-theme.css`),l=x(a,"css",`${t}-theme.css`);if(J(r))try{Bn(r,l)}catch{}let c=x(a,"js",`${s}-animations.js`),u=x(a,"js",`${t}-animations.js`);if(J(c))try{Bn(c,u)}catch{}let p=x(a,"theme.json");if(J(p))try{let f=JSON.parse(fe(p,"utf-8"));f.label=t,f.name=t,ne(p,JSON.stringify(f,null,2),"utf-8")}catch{}}if(J(q))for(let r of Ue(q).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(fe(x(q,r),"utf-8"));l.themeName===s&&(l.themeName=t,l.themePath=a,l.updatedAt=Date.now(),ne(x(q,r),JSON.stringify(l,null,2),"utf-8"))}catch{}return m&&m.themeName===s&&(m.themeName=t,m.themePath=a,m.updatedAt=Date.now()),Vn(),{ok:!0}}function We(){if(!m)return;let e=m.themePath,t=new Map;if(m.templates.length>0)for(let r of m.templates)for(let l of r.modules)t.set(l.moduleName,l);for(let r of m.modules)t.set(r.moduleName,r);let o=x(e,"modules");Ge(o,{recursive:!0});for(let r of t.values())Ge(x(o,`${r.moduleName}.module`),{recursive:!0});for(let r of t.values()){let l=x(o,`${r.moduleName}.module`);ne(x(l,"fields.json"),r.fieldsJson,"utf-8"),ne(x(l,"meta.json"),r.metaJson,"utf-8"),ne(x(l,"module.html"),r.moduleHtml,"utf-8"),ne(x(l,"module.css"),r.moduleCss,"utf-8"),r.moduleJs&&ne(x(l,"module.js"),r.moduleJs,"utf-8")}if(m.sharedCss){let r=x(e,"css");Ge(r,{recursive:!0}),ne(x(r,`${m.themeName}-theme.css`),m.sharedCss,"utf-8")}if(m.sharedJs){let r=x(e,"js");Ge(r,{recursive:!0}),ne(x(r,`${m.themeName}-animations.js`),m.sharedJs,"utf-8")}let n=x(e,"templates");Ge(n,{recursive:!0});let s=x(n,"home.html");(m.templates.length>0||m.modules.length>0)&&J(s)&&Et(s,{force:!0});let a=new Set;if(m.templates.length>0)for(let r of m.templates){if(r.pageType==="module_only"||r.modules.length===0)continue;let l=r.template||Ia(r),c=ks(l,r.label,r.pageType),u=`${r.id}.html`;ne(x(n,u),c,"utf-8"),a.add(u),r.pageType==="blog_post"&&(Ta(n,r),a.add(`${r.id}-listing.html`))}else if(m.modules.length>0){let r=m.template||ka(),l=ks(r,`${m.themeName} Landing Page`),c=`lp-${m.themeName}.html`;ne(x(n,c),l,"utf-8"),a.add(c)}try{for(let r of Ue(n))r.startsWith("lp-")&&r.endsWith(".html")&&!a.has(r)&&Et(x(n,r),{force:!0})}catch{}Ca(),Aa()}function wa(){if(m)try{let e=x(m.themePath,".vibespot");Ge(e,{recursive:!0});let t={sessionId:m.id,themeName:m.themeName,messages:m.messages,updatedAt:Date.now()};ne(x(e,"chat.json"),JSON.stringify(t,null,2),"utf-8")}catch{}}function xa(e){let t=x(e,".vibespot","chat.json");if(!J(t))return[];try{let o=JSON.parse(fe(t,"utf-8"));return Array.isArray(o.messages)?o.messages:[]}catch{return[]}}function Ls(){m&&(m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",Rt(m.themePath),m.updatedAt=Date.now(),Ve())}function Gs(){if(!m)return;let e=Fe();if(!e)return;let t=m.themePath,o=x(t,"modules");e.modules=[];for(let n of e.moduleOrder){let s=x(o,`${n}.module`);if(!J(s))continue;let i={moduleName:n,fieldsJson:ie(x(s,"fields.json")),metaJson:ie(x(s,"meta.json")),moduleHtml:ie(x(s,"module.html")),moduleCss:ie(x(s,"module.css")),moduleJs:ie(x(s,"module.js"))||void 0};i.fieldsJson&&i.moduleHtml&&e.modules.push(i)}if(e.templateFile){let n=x(t,e.templateFile);J(n)&&(e.template=ie(n))}_t(e),m.updatedAt=Date.now()}function Ca(){if(!m)return;let e=x(m.themePath,"templates","layouts","base.html");if(J(e))try{let t=fe(e,"utf-8");if(t.includes("template_js"))return;let o='{{ require_js(get_asset_url("../../js/main.js")) }}';t.includes(o)?t=t.replace(o,o+`
320
+ ${k.bold("1.")} Go to HubSpot ${k.muted("\u2192")} Content ${k.muted("\u2192")} Landing Pages ${k.muted("\u2192")} Create
321
+ ${k.bold("2.")} Choose your uploaded theme from the theme picker
322
+ ${k.bold("3.")} Select the landing page template that was just created
323
+ ${k.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
324
+ ${k.bold("5.")} Click each section to edit text, images, and colors
325
+ ${k.bold("6.")} Upload images via File Manager ${k.muted("(Settings \u2192 Files)")}
326
+ ${k.bold("7.")} Preview and publish!`,"What's next"),await ne({message:"Open HubSpot Landing Pages in your browser?"})){let c=e?`https://${a}/page-ui/${e}/management/pages/landing`:`https://${a}`;try{let d=process.platform;d==="darwin"?is("open",[c],{stdio:"ignore"}):d==="win32"?is("cmd",["/c","start","",c],{stdio:"ignore"}):is("xdg-open",[c],{stdio:"ignore"}),P("Opening HubSpot Landing Pages...")}catch{z(`Open this URL in your browser: ${k.info(c)}`)}}let l=[];if(o&&S(n)&&l.push({path:n,label:`Cloned source (${Wo(n)})`}),S(s)&&l.push({path:s,label:`Theme directory (${Wo(s)})`}),l.length>0&&await ne({message:"Clean up local working directories?"}))for(let d of l)try{ul(d.path,{recursive:!0,force:!0}),P(`Removed ${d.label}`)}catch{K(`Could not remove ${d.label} \u2014 delete manually if needed.`)}await ce(`Thanks for using hub${k.vibes("Vibes")}! ${k.vibes("~")}`)}ee();async function Ko(){Ee();let t=await cn(),e=await dn();Y({lastSourcePath:e.sourceDir});let n=await fn();Y({lastThemePath:n.themePath}),await wn({aiEngine:t.aiEngine,model:t.model,sourceDir:e.sourceDir,themePath:n.themePath}),await gt(n.themePath),await Bo({portalId:t.portalId,sourceDir:e.sourceDir,themePath:n.themePath,wasCloned:e.wasCloned})}f();async function Vo(){Ee(),await cn()}f();ee();async function Yo(){Ee();let t=E();t.aiEngine||(U("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let e=await dn(),n=await fn();await wn({aiEngine:t.aiEngine,sourceDir:e.sourceDir,themePath:n.themePath})}f();ee();async function zo(){Ee();let t=E();if(t.lastThemePath)if(await ne({message:`Upload from ${t.lastThemePath}?`}))await gt(t.lastThemePath);else{let n=await Ae({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await gt(n)}else{let e=await Ae({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:n=>n.trim()?void 0:"Path is required"});await gt(e)}}f();ee();async function qo(){Ee(),await le("Environment Diagnostics");let t=0,e=kt();e.found?sn(e.version)?P(`Node.js v${e.version}`):(K(`Node.js v${e.version} \u2014 too old (need 18+)`),z(" Update at https://nodejs.org"),t++):(U("Node.js \u2014 not installed"),z(" Install from https://nodejs.org"),t++);let n=$t();n.found?P(`Git ${n.version}`):(U("Git \u2014 not installed"),z(" Install from https://git-scm.com"),t++);let s=Me();if(!s.found)K("HubSpot CLI \u2014 not installed (only needed for deployment)"),z(" Install: npm install -g @hubspot/cli");else if(!io(s.version))K(`HubSpot CLI v${s.version} \u2014 too old (need v8+)`),z(" Update: npm install -g @hubspot/cli@latest"),t++;else{P(`HubSpot CLI v${s.version}`);let p=Ne();p.authenticated?P(`HubSpot portal${p.portalName?`: ${p.portalName}`:""} (ID: ${p.portalId})`):(K("HubSpot \u2014 not authenticated"),z(" Run: hs init"))}let o=Tt();o.found?P(`Claude Code ${o.version} at ${o.path}`):z(k.muted("Claude Code \u2014 not installed"));let i=Mt();i.found?P(`Gemini CLI ${i.version} at ${i.path}`):z(k.muted("Gemini CLI \u2014 not installed"));let a=Nt();a.found?P(`OpenAI Codex ${a.version} at ${a.path}`):z(k.muted("OpenAI Codex \u2014 not installed"));let r=E(),l=!!(r.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(r.openaiApiKey||process.env.OPENAI_API_KEY),d=!!(r.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?P("Anthropic API key configured"):z(k.muted("Anthropic API key \u2014 not set")),c?P("OpenAI API key configured"):z(k.muted("OpenAI API key \u2014 not set")),d?P("Google AI API key configured"):z(k.muted("Google AI API key \u2014 not set"));let u={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"};r.aiEngine&&P(`AI engine: ${u[r.aiEngine]||r.aiEngine}`),r.lastThemePath&&z(k.muted(`Last theme: ${r.lastThemePath}`)),!o.found&&!i.found&&!a.found&&!l&&!c&&!d&&(K("No AI engine available"),z(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),z(" Or install: Claude Code \u2014 https://claude.ai/code"),z(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),z(" Codex CLI \u2014 https://github.com/openai/codex"),t++),console.log(),t===0?await ce("Everything looks good!"):await ce(k.warn(`${t} issue${t>1?"s":""} found \u2014 see above`))}f();import{join as Vn}from"path";import{existsSync as Id}from"fs";import{execFileSync as Bs}from"child_process";import Yn from"chalk";f();import{createServer as yd}from"http";import{readFileSync as Us,existsSync as Ws}from"fs";import{join as Kn,extname as ma}from"path";import{createHash as bd}from"crypto";import{WebSocketServer as Sd}from"ws";f();f();f();f();import{readFileSync as Be,readdirSync as ps,existsSync as pe,writeFileSync as En,mkdirSync as fi,rmSync as cs,renameSync as ds}from"fs";import{join as oe,dirname as vl}from"path";import{homedir as wl}from"os";f();import{existsSync as We,writeFileSync as ml,mkdirSync as pl}from"fs";import{join as Re}from"path";function Qo(t){return/^[0-9a-f]{4,40}$/i.test(t)}var kn=null;function ke(){return kn!==null||(kn=$("git --version").success),kn}function $n(t){if(!ke())return!1;if(We(Re(t,".git")))return Xo(t),!0;let e=$("git init",{cwd:t});return e.success?(fl(t),Xo(t),$("git add -A",{cwd:t}),$('git commit -m "Initial theme"',{cwd:t}),!0):(console.warn(`[project-git] git init failed in ${t}: ${e.stderr}`),!1)}function Xo(t){let e=Re(t,".vibespot");We(e)||pl(e,{recursive:!0})}function fl(t){let e=Re(t,".gitignore");ml(e,[".vibespot/","node_modules/",""].join(`
327
+ `),"utf-8")}function rs(t,e){if(!ke()||!We(Re(t,".git"))||($("git add -A",{cwd:t}),$("git diff --cached --quiet",{cwd:t}).success))return null;let s=e.length>72?e.slice(0,69)+"...":e,o=$(`git commit -m "${s.replace(/"/g,'\\"')}"`,{cwd:t});if(!o.success)return console.warn(`[project-git] commit failed: ${o.stderr}`),null;let i=$("git rev-parse --short HEAD",{cwd:t});return i.success?i.stdout:null}function Zo(t,e,n,s){if(!ke()||!We(Re(t,".git")))return null;for(let u of s){let p=Re(t,u);We(p)&&$(`git add "${u}"`,{cwd:t})}if($("git diff --cached --quiet",{cwd:t}).success)return null;let i=`[${e}] `,a=72-i.length,r=n.length>a?n.slice(0,a-3)+"...":n,l=i+r,c=$(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:t});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let d=$("git rev-parse --short HEAD",{cwd:t});return d.success?d.stdout:null}function ei(t,e=50){if(!ke())return[];if(!We(Re(t,".git")))return[];let n=$(`git log --pretty=format:"%h|%H|%s|%at" -n ${e}`,{cwd:t});if(!n.success||!n.stdout.trim())return[];let s=[];for(let o of n.stdout.split(`
328
+ `)){let i=o.split("|");if(i.length<4)continue;let a=parseInt(i[3],10)*1e3;s.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:a,date:new Date(a).toISOString()})}return s}function ti(t,e,n=50){if(!ke())return[];if(!We(Re(t,".git")))return[];let s=e.replace(/[[\]\\]/g,"\\$&"),o=$(`git log --grep="\\[${s}\\]" --pretty=format:"%h|%H|%s|%at" -n ${n}`,{cwd:t});if(!o.success||!o.stdout.trim())return[];let i=[];for(let a of o.stdout.split(`
329
+ `)){let r=a.split("|");if(r.length<4)continue;let l=parseInt(r[3],10)*1e3;i.push({hash:r[0],fullHash:r[1],message:r[2],timestamp:l,date:new Date(l).toISOString()})}return i}function ni(t,e){if(!ke())return{success:!1,error:"Git not available"};if(!We(Re(t,".git")))return{success:!1,error:"Not a git repo"};if(!Qo(e))return{success:!1,error:"Invalid commit hash"};let n=$(`git cat-file -t ${e}`,{cwd:t});if(!n.success||n.stdout.trim()!=="commit")return{success:!1,error:`Commit ${e} not found`};let s=$(`git log --format="%s" -1 ${e}`,{cwd:t}),o=s.success?s.stdout:e,i=$(`git checkout ${e} -- .`,{cwd:t});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let a=`Rollback to: ${o}`.slice(0,72);return $(`git commit -m "${a.replace(/"/g,'\\"')}"`,{cwd:t}),{success:!0}}function si(t,e,n,s){if(!ke())return{success:!1,error:"Git not available"};if(!We(Re(t,".git")))return{success:!1,error:"Not a git repo"};if(!Qo(n))return{success:!1,error:"Invalid commit hash"};let o=$(`git cat-file -t ${n}`,{cwd:t});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${n} not found`};let i=$(`git log --format="%s" -1 ${n}`,{cwd:t}),a=i.success?i.stdout:n,r=0;for(let d of s)$(`git checkout ${n} -- "${d}"`,{cwd:t}).success&&r++;if(r===0)return{success:!1,error:"No files could be restored from that commit"};$("git add -A",{cwd:t});let c=`${`[${e}] `}Rollback to: ${a}`.slice(0,72);return $(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:t}),{success:!0}}f();f();import{readFileSync as gl,existsSync as hl,writeFileSync as yl,mkdirSync as bl}from"fs";import{join as as}from"path";function nt(t){let e=v();e&&(e.modules=t.modules,e.moduleOrder=t.moduleOrder,e.sharedCss=t.sharedCss,e.sharedJs=t.sharedJs,e.template=t.template,e.messages=t.messages)}function Ye(){let t=v();if(!t)return;let e=Se();e&&(e.modules=t.modules,e.moduleOrder=t.moduleOrder,e.sharedCss=t.sharedCss,e.sharedJs=t.sharedJs,e.template=t.template,e.messages=t.messages)}function ze(t,e,n){let s=v();if(!s)return;let o={role:t,content:e,timestamp:Date.now()};n&&(o.pipeline=n),s.messages.push(o),s.updatedAt=Date.now(),Ye(),Sl()}function oi(t){let e=v();e&&(e.assets||(e.assets=[]),e.assets.push(t),e.updatedAt=Date.now(),j())}function Oe(t){let e=v();if(e){if(t.sharedCss!==void 0&&(e.sharedCss=t.sharedCss),t.sharedJs!==void 0&&(e.sharedJs=t.sharedJs),t.template!==void 0&&(e.template=t.template),t.modules)for(let n of t.modules){let s=n.moduleName.toLowerCase(),o=e.modules.findIndex(i=>i.moduleName.toLowerCase()===s);o>=0?e.modules[o]=n:(e.modules.push(n),e.moduleOrder.some(i=>i.toLowerCase()===s)||e.moduleOrder.push(n.moduleName))}e.updatedAt=Date.now(),Ye()}}function ht(t){let e=v();e&&(e.moduleOrder=t,e.updatedAt=Date.now(),Ye())}function ii(t){let e=v();e&&(e.modules=e.modules.filter(n=>n.moduleName!==t),e.moduleOrder=e.moduleOrder.filter(n=>n!==t),e.updatedAt=Date.now(),Ye())}function ri(t){let e=v();e&&(e.moduleOrder=e.moduleOrder.filter(n=>n!==t),e.updatedAt=Date.now(),Ye())}function ai(t,e,n){let s=v();if(!s)return;let o=s.modules.find(i=>i.moduleName===t);if(o)try{let i=JSON.parse(o.fieldsJson);ci(i,e,n),o.fieldsJson=JSON.stringify(i,null,2),s.updatedAt=Date.now(),Ye()}catch{}}function ue(){let t=v();if(!t)return[];let e=[];for(let n of t.moduleOrder){let s=t.modules.find(o=>o.moduleName===n);s&&e.push(s)}for(let n of t.modules)t.moduleOrder.includes(n.moduleName)||e.push(n);return e}function Sl(){let t=v();if(t)try{let e=as(t.themePath,".vibespot");bl(e,{recursive:!0});let n={sessionId:t.id,themeName:t.themeName,messages:t.messages,updatedAt:Date.now()};yl(as(e,"chat.json"),JSON.stringify(n,null,2),"utf-8")}catch{}}function li(t){let e=as(t,".vibespot","chat.json");if(!hl(e))return[];try{let n=JSON.parse(gl(e,"utf-8"));return Array.isArray(n.messages)?n.messages:[]}catch{return[]}}function ci(t,e,n){let s=e.split("."),o=s[0],i=t.find(a=>a.name===o);i&&(s.length===1?i.default=n:i.children&&ci(i.children,s.slice(1).join("."),n))}function Tn(t){if(t.templates&&t.templates.length>0)return;if(!t.modules||t.modules.length===0){t.templates=[],t.activeTemplateId="";return}let e=`lp-${t.themeName}`,n={id:e,label:`${t.themeName} Landing Page`,pageType:"landing_page",templateFile:`templates/lp-${t.themeName}.html`,modules:[...t.modules],moduleOrder:[...t.moduleOrder],sharedCss:t.sharedCss||"",sharedJs:t.sharedJs||"",template:t.template||"",messages:[...t.messages]};t.templates=[n],t.activeTemplateId=e}function Se(){let t=v();return!t||!t.activeTemplateId||!t.templates?.length?null:t.templates.find(e=>e.id===t.activeTemplateId)||null}function ls(t){let e=v();if(!e)return!1;let n=e.templates.find(s=>s.id===t);return n?(e.activeTemplateId=t,nt(n),e.updatedAt=Date.now(),!0):!1}function di(t,e){let n=v();if(!n)throw new Error("No active session");let s=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),i=`${t==="blog_post"?"bp":t==="website_page"?"wp":t==="module_only"?"mo":"lp"}-${s}`,a={id:i,label:e,pageType:t,templateFile:t==="module_only"?"":`templates/${i}.html`,modules:[],moduleOrder:[],sharedCss:"",sharedJs:"",template:"",messages:[]};return n.templates.push(a),n.activeTemplateId=i,nt(a),n.updatedAt=Date.now(),a}function ui(t,e){let n=v();if(!n)return null;let s=n.templates.find(c=>c.id===t);if(!s)return null;let o=e||`${s.label} (Copy)`,i=o.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),r=`${s.pageType==="blog_post"?"bp":s.pageType==="website_page"?"wp":s.pageType==="module_only"?"mo":"lp"}-${i}`,l={id:r,label:o,pageType:s.pageType,templateFile:s.pageType==="module_only"?"":`templates/${r}.html`,modules:s.modules.map(c=>({...c})),moduleOrder:[...s.moduleOrder],sharedCss:s.sharedCss,sharedJs:s.sharedJs,template:s.template,messages:[]};return n.templates.push(l),n.activeTemplateId=r,nt(l),n.updatedAt=Date.now(),l}function mi(t,e){let n=v();if(!n)return!1;let s=n.templates.find(o=>o.id===t);return s?(s.label=e,n.updatedAt=Date.now(),!0):!1}function pi(t){let e=v();if(!e)return!1;let n=e.templates.findIndex(s=>s.id===t);return n<0?!1:(e.templates.splice(n,1),e.activeTemplateId===t&&(e.templates.length>0?ls(e.templates[0].id):(e.activeTemplateId="",e.modules=[],e.moduleOrder=[],e.sharedCss="",e.sharedJs="",e.template="",e.messages=[])),e.updatedAt=Date.now(),!0)}function qe(){let t=v();if(!t)return[];let e=new Map;for(let n of t.templates)for(let s of n.modules){let o=e.get(s.moduleName);o?o.usedIn.push(n.label):e.set(s.moduleName,{module:s,usedIn:[n.label]})}return Array.from(e.values())}var Q=oe(wl(),".vibespot","sessions"),us=oe(Q,"_index.json"),yt=null;function Mn(){if(yt)return yt;try{return pe(us)?(yt=JSON.parse(Be(us,"utf-8")),yt):ms()}catch{return ms()}}function Nn(t){yt=t;try{fi(Q,{recursive:!0}),En(us,JSON.stringify(t),"utf-8")}catch{}}function ms(){if(!pe(Q))return[];let t=[];for(let e of ps(Q).filter(n=>n.endsWith(".json")&&n!=="_index.json"))try{let n=JSON.parse(Be(oe(Q,e),"utf-8")),s=n.templates||[];t.push({id:n.id,themeName:n.themeName,updatedAt:n.updatedAt,moduleCount:s.reduce((o,i)=>o+(i.modules?.length||0),0),templateCount:s.length})}catch{}return yt=t,Nn(t),t}function xl(t){let e=Mn(),n=t.templates||[],s={id:t.id,themeName:t.themeName,updatedAt:t.updatedAt,moduleCount:n.reduce((i,a)=>i+(a.modules?.length||0),0),templateCount:n.length},o=e.findIndex(i=>i.id===t.id);o>=0?e[o]=s:e.push(s),Nn(e)}function Cl(t){let e=Mn().filter(n=>n.id!==t);Nn(e)}function Al(t){let e=Mn().filter(n=>n.themeName!==t);Nn(e)}var fe=null;function v(){return fe}function Il(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function Ft(t,e){let n={id:Il(),themePath:t,themeName:e,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return fe=n,$n(t),n}function j(){if(!fe)return;fi(Q,{recursive:!0});let t=oe(Q,`${fe.id}.json`);En(t,JSON.stringify(fe,null,2),"utf-8"),xl(fe)}function _n(t){let e=oe(Q,t+".json");if(!pe(e))return null;try{let n=JSON.parse(Be(e,"utf-8"));return n.templates||(n.templates=[]),n.activeTemplateId||(n.activeTemplateId=""),Tn(n),fe=n,n}catch{return null}}function bt(){return pe(Q)?Mn():[]}function gi(t,e=!1){let n=oe(Q,t+".json"),s="";if(e)try{let o=JSON.parse(Be(n,"utf-8"));s=o.themeName||"",o.themePath&&pe(o.themePath)&&cs(o.themePath,{recursive:!0,force:!0})}catch{}else try{s=JSON.parse(Be(n,"utf-8")).themeName||""}catch{}try{pe(n)&&cs(n)}catch{}if(s&&pe(Q)){for(let o of ps(Q).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(Be(oe(Q,o),"utf-8")).themeName===s&&cs(oe(Q,o))}catch{}Al(s)}else Cl(t);fe?.id===t&&(fe=null)}function hi(t,e){let n=oe(Q,t+".json");if(!pe(n))return{ok:!1,error:"Session not found"};let s;try{s=JSON.parse(Be(n,"utf-8"))}catch{return{ok:!1,error:"Failed to read session"}}let o=s.themeName;if(o===e)return{ok:!0};let i=s.themePath,a=oe(vl(i),e);if(pe(i)){if(pe(a))return{ok:!1,error:"A project with that name already exists"};try{ds(i,a)}catch(p){return{ok:!1,error:`Failed to rename folder: ${p instanceof Error?p.message:String(p)}`}}let r=oe(a,"css",`${o}-theme.css`),l=oe(a,"css",`${e}-theme.css`);if(pe(r))try{ds(r,l)}catch{}let c=oe(a,"js",`${o}-animations.js`),d=oe(a,"js",`${e}-animations.js`);if(pe(c))try{ds(c,d)}catch{}let u=oe(a,"theme.json");if(pe(u))try{let p=JSON.parse(Be(u,"utf-8"));p.label=e,p.name=e,En(u,JSON.stringify(p,null,2),"utf-8")}catch{}}if(pe(Q))for(let r of ps(Q).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(Be(oe(Q,r),"utf-8"));l.themeName===o&&(l.themeName=e,l.themePath=a,l.updatedAt=Date.now(),En(oe(Q,r),JSON.stringify(l,null,2),"utf-8"))}catch{}return fe&&fe.themeName===o&&(fe.themeName=e,fe.themePath=a,fe.updatedAt=Date.now()),ms(),{ok:!0}}f();import{readFileSync as fs,readdirSync as Dt,existsSync as ve,writeFileSync as Ce,mkdirSync as Jt,rmSync as yi}from"fs";import{join as N}from"path";function ae(t){try{return fs(t,"utf-8")}catch{return""}}function kl(t){let e=[];for(let n of t.moduleOrder){let s=t.modules.find(o=>o.moduleName===n);s&&e.push(s)}for(let n of t.modules)t.moduleOrder.includes(n.moduleName)||e.push(n);return e}function $l(t,e){let n=ae(t);if(!n||e==="home.html"||e.endsWith("-listing.html"))return null;let s=e.replace(/\.html$/,""),o="landing_page";s.startsWith("bp-")?o="blog_post":s.startsWith("wp-")?o="website_page":s.startsWith("mo-")&&(o="module_only");let i=s,a=n.match(/<!--[\s\S]*?label:\s*"?([^"\n]+)"?\s*[\s\S]*?-->/);a&&(i=a[1].trim());let r=/dnd_module\s+path=["']\.\.\/modules\/(.+?)\.module["']/g,l=[],c;for(;(c=r.exec(n))!==null;)l.push(c[1]);return{id:s,label:i,pageType:o,moduleNames:l,templateContent:n,filename:e}}function Tl(t,e,n,s,o){if(!ve(t))return[];let i=[],a=Dt(t).filter(r=>r.endsWith(".html")&&r!=="home.html");for(let r of a){let l=N(t,r),c=$l(l,r);if(!c||c.moduleNames.length===0&&i.length>0)continue;let d=[],u=[];for(let p of c.moduleNames){let g=e.get(p);g&&(d.push(g),u.push(p))}i.push({id:c.id,label:c.label,pageType:c.pageType,templateFile:`templates/${c.filename}`,modules:d,moduleOrder:u,sharedCss:n,sharedJs:s,template:c.templateContent,messages:i.length===0?[...o]:[]})}return i}function Ht(t){let e=v();if(!e)return;let n=li(t);n.length>0&&e.messages.length===0&&(e.messages=n),$n(t);let s=N(t,"modules");if(!ve(s))return;let o=Dt(s,{withFileTypes:!0});for(let h of o){if(!h.isDirectory()||!h.name.endsWith(".module"))continue;let b=N(s,h.name),y=h.name.replace(/\.module$/,""),w={moduleName:y,fieldsJson:ae(N(b,"fields.json")),metaJson:ae(N(b,"meta.json")),moduleHtml:ae(N(b,"module.html")),moduleCss:ae(N(b,"module.css")),moduleJs:ae(N(b,"module.js"))||void 0};w.fieldsJson&&w.moduleHtml&&(e.modules.push(w),e.moduleOrder.push(y))}let i=N(t,"css"),a=N(t,"js"),r="",l="";if(ve(i)){let h=Dt(i).filter(b=>b.endsWith("-theme.css"));h.length>0&&(r=ae(N(i,h[0])),e.sharedCss=r)}if(ve(a)){let h=Dt(a).filter(b=>b.endsWith("-animations.js"));h.length>0&&(l=ae(N(a,h[0])),e.sharedJs=l)}let c=N(t,".vibespot","styleguide.md"),d=N(t,".vibespot","brandvoice.md");(ve(c)||ve(d))&&(e.brandAssets||(e.brandAssets={}),ve(c)&&(e.brandAssets.styleguide=ae(c)),ve(d)&&(e.brandAssets.brandvoice=ae(d)));let u=N(t,"templates"),p=new Map(e.modules.map(h=>[h.moduleName,h])),g=Tl(u,p,r,l,e.messages);if(g.length>0){e.templates=g,e.activeTemplateId=g[0].id;let h=g[0].moduleOrder;if(h.length>0){let b=new Set(e.moduleOrder),y=h.filter(w=>b.has(w));for(let w of e.moduleOrder)y.includes(w)||y.push(w);e.moduleOrder=y}nt(g[0])}else e.templates||(e.templates=[]),e.activeTemplateId||(e.activeTemplateId=""),Tn(e)}function Xe(){let t=v();if(!t)return;let e=t.themePath,n=new Map;if(t.templates.length>0)for(let l of t.templates)for(let c of l.modules)n.set(c.moduleName,c);for(let l of t.modules)n.set(l.moduleName,l);let s=N(e,"modules");Jt(s,{recursive:!0});for(let l of n.values())Jt(N(s,`${l.moduleName}.module`),{recursive:!0});for(let l of n.values()){let c=N(s,`${l.moduleName}.module`);Ce(N(c,"fields.json"),l.fieldsJson,"utf-8"),Ce(N(c,"meta.json"),l.metaJson,"utf-8"),Ce(N(c,"module.html"),l.moduleHtml,"utf-8"),Ce(N(c,"module.css"),l.moduleCss,"utf-8"),l.moduleJs&&Ce(N(c,"module.js"),l.moduleJs,"utf-8")}if(t.sharedCss){let l=N(e,"css");Jt(l,{recursive:!0}),Ce(N(l,`${t.themeName}-theme.css`),t.sharedCss,"utf-8")}if(t.sharedJs){let l=N(e,"js");Jt(l,{recursive:!0}),Ce(N(l,`${t.themeName}-animations.js`),t.sharedJs,"utf-8")}let o=N(e,"templates");Jt(o,{recursive:!0});let i=N(o,"home.html");(t.templates.length>0||t.modules.length>0)&&ve(i)&&yi(i,{force:!0});let r=new Set;if(t.templates.length>0)for(let l of t.templates){if(l.pageType==="module_only"||l.modules.length===0)continue;let c=l.template||Nl(l),d=bi(c,l.label,l.pageType),u=`${l.id}.html`;Ce(N(o,u),d,"utf-8"),r.add(u),l.pageType==="blog_post"&&(_l(o,l),r.add(`${l.id}-listing.html`))}else if(t.modules.length>0){let l=t.template||Pl(),c=bi(l,`${t.themeName} Landing Page`),d=`lp-${t.themeName}.html`;Ce(N(o,d),c,"utf-8"),r.add(d)}try{for(let l of Dt(o))l.startsWith("lp-")&&l.endsWith(".html")&&!r.has(l)&&yi(N(o,l),{force:!0})}catch{}El(),Ml()}function Si(){let t=v();t&&(t.modules=[],t.moduleOrder=[],t.sharedCss="",t.sharedJs="",t.template="",Ht(t.themePath),t.updatedAt=Date.now(),Ye())}function vi(){let t=v();if(!t)return;let e=Se();if(!e)return;let n=t.themePath,s=N(n,"modules");e.modules=[];for(let o of e.moduleOrder){let i=N(s,`${o}.module`);if(!ve(i))continue;let a={moduleName:o,fieldsJson:ae(N(i,"fields.json")),metaJson:ae(N(i,"meta.json")),moduleHtml:ae(N(i,"module.html")),moduleCss:ae(N(i,"module.css")),moduleJs:ae(N(i,"module.js"))||void 0};a.fieldsJson&&a.moduleHtml&&e.modules.push(a)}if(e.templateFile){let o=N(n,e.templateFile);ve(o)&&(e.template=ae(o))}nt(e),t.updatedAt=Date.now()}function El(){let t=v();if(!t)return;let e=N(t.themePath,"templates","layouts","base.html");if(ve(e))try{let n=fs(e,"utf-8");if(n.includes("template_js"))return;let s='{{ require_js(get_asset_url("../../js/main.js")) }}';n.includes(s)?n=n.replace(s,s+`
330
330
  {% if template_js %}
331
331
  {{ require_js(get_asset_url(template_js)) }}
332
- {% endif %}`):t=t.replace("{{ standard_footer_includes }}",`{% if template_js %}
332
+ {% endif %}`):n=n.replace("{{ standard_footer_includes }}",`{% if template_js %}
333
333
  {{ require_js(get_asset_url(template_js)) }}
334
334
  {% endif %}
335
- {{ standard_footer_includes }}`),ne(e,t,"utf-8")}catch{}}function Aa(){if(!m)return;let e=x(m.themePath,"theme.json");if(J(e))try{let t=JSON.parse(fe(e,"utf-8"));t.label=m.themeName,t.name=m.themeName,ne(e,JSON.stringify(t,null,2),"utf-8")}catch{}}function ks(e,t,o="landing_page"){return e.includes("templateType")?e:`<!--
336
- templateType: ${o==="blog_post"?"blog_post":"page"}
335
+ {{ standard_footer_includes }}`),Ce(e,n,"utf-8")}catch{}}function Ml(){let t=v();if(!t)return;let e=N(t.themePath,"theme.json");if(ve(e))try{let n=JSON.parse(fs(e,"utf-8"));n.label=t.themeName,n.name=t.themeName,Ce(e,JSON.stringify(n,null,2),"utf-8")}catch{}}function bi(t,e,n="landing_page"){return t.includes("templateType")?t:`<!--
336
+ templateType: ${n==="blog_post"?"blog_post":"page"}
337
337
  isAvailableForNewContent: true
338
- label: "${t}"
338
+ label: "${e}"
339
339
  -->
340
- `+e}function Ia(e){if(e.modules.length===0)return"";let t=m.themeName,n=$a(e).map(i=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
341
- {% dnd_module path="../modules/${i.moduleName}.module" %}
340
+ `+t}function Nl(t){if(t.modules.length===0)return"";let n=v().themeName,o=kl(t).map(a=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
341
+ {% dnd_module path="../modules/${a.moduleName}.module" %}
342
342
  {% end_dnd_module %}
343
343
  {% end_dnd_section %}`).join(`
344
344
 
345
345
  `);return`<!--
346
- templateType: ${e.pageType==="blog_post"?"blog_post":"page"}
346
+ templateType: ${t.pageType==="blog_post"?"blog_post":"page"}
347
347
  isAvailableForNewContent: true
348
- label: "${e.label}"
348
+ label: "${t.label}"
349
349
  -->
350
350
  {% extends "./layouts/base.html" %}
351
351
 
352
- {% set template_css = "../../css/${t}-theme.css" %}
353
- {% set template_js = "../../js/${t}-animations.js" %}
352
+ {% set template_css = "../../css/${n}-theme.css" %}
353
+ {% set template_js = "../../js/${n}-animations.js" %}
354
354
 
355
355
  {% block header %}
356
356
  {% endblock header %}
357
357
 
358
358
  {% block body %}
359
- <div class="${t}-page">
360
- {% dnd_area "main_content" label="${e.label}" %}
359
+ <div class="${n}-page">
360
+ {% dnd_area "main_content" label="${t.label}" %}
361
361
 
362
- ${n}
362
+ ${o}
363
363
 
364
364
  {% end_dnd_area %}
365
365
  </div>
366
- {{ require_js(get_asset_url("../../js/${t}-animations.js")) }}
366
+ {{ require_js(get_asset_url("../../js/${n}-animations.js")) }}
367
367
  {% endblock body %}
368
368
 
369
369
  {% block footer %}
370
370
  {% endblock footer %}
371
- `}function Ta(e,t){let o=`<!--
371
+ `}function _l(t,e){let n=`<!--
372
372
  templateType: blog_listing
373
373
  isAvailableForNewContent: true
374
- label: "${t.label} - Listing"
374
+ label: "${e.label} - Listing"
375
375
  -->
376
376
  {% extends "./layouts/base.html" %}
377
377
 
@@ -393,8 +393,8 @@ ${n}
393
393
  {% endif %}
394
394
  </div>
395
395
  {% endblock body %}
396
- `;ne(x(e,`${t.id}-listing.html`),o,"utf-8")}function $a(e){let t=[];for(let o of e.moduleOrder){let n=e.modules.find(s=>s.moduleName===o);n&&t.push(n)}for(let o of e.modules)e.moduleOrder.includes(o.moduleName)||t.push(o);return t}function ka(){if(!m||m.modules.length===0)return"";let e=m.themeName,o=be().map(n=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
397
- {% dnd_module path="../modules/${n.moduleName}.module" %}
396
+ `;Ce(N(t,`${e.id}-listing.html`),n,"utf-8")}function Pl(){let t=v();if(!t||t.modules.length===0)return"";let e=t.themeName,s=ue().map(o=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
397
+ {% dnd_module path="../modules/${o.moduleName}.module" %}
398
398
  {% end_dnd_module %}
399
399
  {% end_dnd_section %}`).join(`
400
400
 
@@ -415,7 +415,7 @@ ${n}
415
415
  <div class="${e}-page">
416
416
  {% dnd_area "main_content" label="${e} Landing Page" %}
417
417
 
418
- ${o}
418
+ ${s}
419
419
 
420
420
  {% end_dnd_area %}
421
421
  </div>
@@ -424,15 +424,15 @@ ${o}
424
424
 
425
425
  {% block footer %}
426
426
  {% endblock footer %}
427
- `}function Ea(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function ie(e){try{return fe(e,"utf-8")}catch{return""}}function Us(e,t,o){let n=t.split("."),s=n[0],i=e.find(a=>a.name===s);i&&(n.length===1?i.default=o:i.children&&Us(i.children,n.slice(1).join("."),o))}h();h();function Sn(e){let t={};for(let o of e)o.type==="group"&&o.occurrence&&Array.isArray(o.default)?t[o.name]=o.default:o.type==="group"&&o.children?t[o.name]=Sn(o.children):t[o.name]=o.default??"";return t}function Xn(e,t){let o=e;return o=Ja(o),o=Ys(o,t),o=Vs(o,t),o=zs(o,t),o=Ha(o),o}function Qn(e){let t=[e.sharedCss||"",...e.moduleCssArray].filter(Boolean).map(s=>`<style>${s}</style>`).join(`
428
- `),o=[e.sharedJs||"",...e.moduleJsArray].filter(Boolean).map(s=>`<script>${s}</script>`).join(`
429
- `),n=e.renderedModules.join(`
427
+ `}f();f();function Pn(t){let e={};for(let n of t)n.type==="group"&&n.occurrence&&Array.isArray(n.default)?e[n.name]=n.default:n.type==="group"&&n.children?e[n.name]=Pn(n.children):e[n.name]=n.default??"";return e}function hs(t,e){let n=t;return n=Gl(n),n=Ai(n,e),n=Ii(n,e),n=ki(n,e),n=Wl(n),n}function ys(t){let e=[t.sharedCss||"",...t.moduleCssArray].filter(Boolean).map(o=>`<style>${o}</style>`).join(`
428
+ `),n=[t.sharedJs||"",...t.moduleJsArray].filter(Boolean).map(o=>`<script>${o}</script>`).join(`
429
+ `),s=t.renderedModules.join(`
430
430
  `);return`<!DOCTYPE html>
431
431
  <html lang="en">
432
432
  <head>
433
433
  <meta charset="utf-8">
434
434
  <meta name="viewport" content="width=device-width, initial-scale=1">
435
- ${t}
435
+ ${e}
436
436
  <style>
437
437
  html{scroll-behavior:smooth}
438
438
  .vsp-img-wrap{position:relative;display:inline-block}
@@ -440,8 +440,8 @@ html{scroll-behavior:smooth}
440
440
  </style>
441
441
  </head>
442
442
  <body>
443
+ ${s}
443
444
  ${n}
444
- ${o}
445
445
  <script>
446
446
  // Anchor link handler \u2014 smooth scroll to module sections
447
447
  document.addEventListener('click',function(e){
@@ -471,7 +471,11 @@ document.querySelectorAll('img').forEach(function(img){
471
471
  });
472
472
  </script>
473
473
  </body>
474
- </html>`}var Na=/\{%[-\s]*require_(css|js)\b.*?%\}/gs,_a=/\{%[-\s]*end_require_(css|js)\s*%\}/gs,Ra=/\{\{[-\s]*require_(css|js)\(.*?\)\s*\}\}/gs,Ws=/\{\{[-\s]*get_asset_url\(["'](?:[^"'\/]+\/)?assets\/(.*?)["']\)\s*\}\}/gs,Ks=/\{\{[-\s]*get_asset_url\(.*?\)\s*\}\}/gs,Pa=/\{%[-\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\b.*?%\}/gs,Oa=/\{%[-\s]*module\b.*?%\}/gs,Ma=/\{%[-\s]*(extends|block|endblock|set)\b.*?%\}/gs,ja=/\{#.*?#\}/gs,Da=/\{\{[-\s]*content\.\w+.*?\}\}/gs,qn=/\{%[-\s]*if\s+(.*?)\s*-?%\}([\s\S]*?)\{%[-\s]*endif\s*-?%\}/g;function Ja(e){return e=e.replace(Na,""),e=e.replace(_a,""),e=e.replace(Ra,""),Ws.lastIndex=0,e=e.replace(Ws,(t,o)=>`/theme-assets/${o}`),Ks.lastIndex=0,e=e.replace(Ks,""),e=e.replace(Pa,""),e=e.replace(Oa,""),e=e.replace(Ma,""),e=e.replace(ja,""),e=e.replace(Da,""),e}function Ys(e,t){let o=e,n=0;for(;n<30;){n++;let s=Fa(o);if(!s)break;let{varName:i,iterExpr:a,body:r,start:l,end:c}=s,u=La(a,t),p="";Array.isArray(u)&&(p=u.map((f,g)=>{let y={...t,[i]:f,loop:{index:g+1,index0:g,first:g===0,last:g===u.length-1,length:u.length}},S=Ys(r,y);return S=Vs(S,y),S=zs(S,y),S}).join("")),o=o.slice(0,l)+p+o.slice(c)}return o}function Fa(e){let t=/\{%[-\s]*for\s+(\w+)\s+in\s+([\w.]+(?:\([^)]*\))?(?:\|[\w(),"' ]+)*)\s*-?%\}/g,o=/\{%[-\s]*(for\s|endfor)\s*.*?-?%\}/g,n=t.exec(e);if(!n)return null;let s=n[1],i=n[2],a=n.index+n[0].length;o.lastIndex=a;let r=1,l;for(;(l=o.exec(e))!==null;)if(l[1].startsWith("for"))r++;else if(r--,r===0){let c=e.slice(a,l.index);return{varName:s,iterExpr:i,body:c,start:n.index,end:l.index+l[0].length}}return null}function Vs(e,t){let o=e,n=0;for(;qn.test(o)&&n<50;)n++,o=o.replace(qn,(s,i,a)=>{let r=a.split(/\{%[-\s]*else\s*-?%\}/),l=r[0],c=r[1]||"",u=l.split(/\{%[-\s]*elif\s+(.*?)\s*-?%\}/);if(u.length>1){if(mt(i,t))return u[0];for(let p=1;p<u.length;p+=2){let f=u[p],g=u[p+1]||"";if(mt(f,t))return g}return c}return mt(i,t)?l:c}),qn.lastIndex=0;return o}function zs(e,t){return e.replace(/\{\{[-\s]*(.*?)[-\s]*\}\}/g,(o,n)=>{let i=n.trim().split("|"),a=i[0].trim(),r=qe(t,a);for(let c=1;c<i.length;c++)r=Xs(r,i[c].trim());if(r==null)return"";if(typeof r=="object")return JSON.stringify(r);let l=String(r);return l=l.replace(/\\n/g," ").replace(/\n/g," "),l})}function Ha(e){return e=e.replace(/\{%.*?%\}/gs,""),e=e.replace(/\{\{.*?\}\}/gs,""),e}function La(e,t){let o=e.match(/^range\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);if(o){let s=Bs(o[1],t),i=Bs(o[2],t),a=[];for(let r=s;r<i;r++)a.push(r);return a}let n=e.match(/^(.+?)\|split\(['"](.+?)['"]\)$/);if(n){let s=qe(t,n[1].trim());return typeof s=="string"?s.split(n[2]):[]}return qe(t,e)}function Bs(e,t){let n=e.trim().split("|"),s=n[0].trim();if(!isNaN(Number(s)))return Number(s);let i=qe(t,s);for(let a=1;a<n.length;a++)i=Xs(i,n[a].trim());return Number(i)||0}function qe(e,t){let o=t.split("."),n=e;for(let s of o){if(n==null||typeof n!="object")return;n=n[s]}return n}function mt(e,t){let o=e.trim();if(o.startsWith("not "))return!mt(o.slice(4),t);if(o.includes(" and "))return o.split(" and ").every(i=>mt(i,t));if(o.includes(" or "))return o.split(" or ").some(i=>mt(i,t));let n=o.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);if(n){let i=qe(t,n[1].trim()),a=n[2],r=n[3].trim();switch(typeof r=="string"&&r.startsWith('"')&&r.endsWith('"')||typeof r=="string"&&r.startsWith("'")&&r.endsWith("'")?r=r.slice(1,-1):isNaN(Number(r))?r=qe(t,r):r=Number(r),a){case"==":return i==r;case"!=":return i!=r;case">":return Number(i)>Number(r);case"<":return Number(i)<Number(r);case">=":return Number(i)>=Number(r);case"<=":return Number(i)<=Number(r)}}let s=qe(t,o);return qs(s)}function qs(e){return!(e==null||e===""||e===0||e===!1||Array.isArray(e)&&e.length===0)}function Xs(e,t){let o=e==null?"":String(e),n=t.match(/^(\w+)\((.*)\)$/),s=n?n[1]:t,i=n?n[2].replace(/^["']|["']$/g,""):void 0;switch(s){case"escape":case"e":return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");case"lower":return o.toLowerCase();case"upper":return o.toUpperCase();case"capitalize":return o.charAt(0).toUpperCase()+o.slice(1);case"trim":return o.trim();case"truncate":if(i){let a=parseInt(i,10);return o.length>a?o.slice(0,a)+"...":o}return o;case"default":return qs(e)?e:i??"";case"length":return Array.isArray(e)?e.length:o.length;case"join":return Array.isArray(e)?e.join(i??", "):o;case"int":case"float":return Number(o)||0;case"abs":return Math.abs(Number(o));case"round":return Math.round(Number(o));default:return e}}function Zs(){let e=$();if(!e)return Qs();let t=be();if(t.length===0)return Qs();let o=[],n=[],s=[];for(let i of t){if(i.moduleHtml.includes("dnd_area")||i.moduleHtml.includes("extends "))continue;let a;try{let c=JSON.parse(i.fieldsJson);a={module:Sn(c)}}catch{a={module:{}}}let r=Xn(i.moduleHtml,a),l=i.moduleName.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");o.push(`<div class="vibespot-module" id="${l}" data-module="${i.moduleName}">${r}</div>`),i.moduleCss&&n.push(i.moduleCss),i.moduleJs&&s.push(i.moduleJs)}return Qn({renderedModules:o,sharedCss:e.sharedCss,moduleCssArray:n,sharedJs:e.sharedJs,moduleJsArray:s})}function Qs(){return`<!DOCTYPE html>
474
+ </html>`}var Rl=/\{%[-\s]*require_(css|js)\b.*?%\}/gs,Ol=/\{%[-\s]*end_require_(css|js)\s*%\}/gs,jl=/\{\{[-\s]*require_(css|js)\(.*?\)\s*\}\}/gs,wi=/\{\{[-\s]*get_asset_url\(["'](?:[^"'\/]+\/)?assets\/(.*?)["']\)\s*\}\}/gs,xi=/\{\{[-\s]*get_asset_url\(.*?\)\s*\}\}/gs,Fl=/\{%[-\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\b.*?%\}/gs,Jl=/\{%[-\s]*module\b.*?%\}/gs,Dl=/\{%[-\s]*(extends|block|endblock|set)\b.*?%\}/gs,Hl=/\{#.*?#\}/gs,Ll=/\{\{[-\s]*content\.\w+.*?\}\}/gs,gs=/\{%[-\s]*if\s+(.*?)\s*-?%\}([\s\S]*?)\{%[-\s]*endif\s*-?%\}/g;function Gl(t){return t=t.replace(Rl,""),t=t.replace(Ol,""),t=t.replace(jl,""),wi.lastIndex=0,t=t.replace(wi,(e,n)=>`/theme-assets/${n}`),xi.lastIndex=0,t=t.replace(xi,""),t=t.replace(Fl,""),t=t.replace(Jl,""),t=t.replace(Dl,""),t=t.replace(Hl,""),t=t.replace(Ll,""),t}function Ai(t,e){let n=t,s=0;for(;s<30;){s++;let o=Ul(n);if(!o)break;let{varName:i,iterExpr:a,body:r,start:l,end:c}=o,d=Bl(a,e),u="";Array.isArray(d)&&(u=d.map((p,g)=>{let h={...e,[i]:p,loop:{index:g+1,index0:g,first:g===0,last:g===d.length-1,length:d.length}},b=Ai(r,h);return b=Ii(b,h),b=ki(b,h),b}).join("")),n=n.slice(0,l)+u+n.slice(c)}return n}function Ul(t){let e=/\{%[-\s]*for\s+(\w+)\s+in\s+([\w.]+(?:\([^)]*\))?(?:\|[\w(),"' ]+)*)\s*-?%\}/g,n=/\{%[-\s]*(for\s|endfor)\s*.*?-?%\}/g,s=e.exec(t);if(!s)return null;let o=s[1],i=s[2],a=s.index+s[0].length;n.lastIndex=a;let r=1,l;for(;(l=n.exec(t))!==null;)if(l[1].startsWith("for"))r++;else if(r--,r===0){let c=t.slice(a,l.index);return{varName:o,iterExpr:i,body:c,start:s.index,end:l.index+l[0].length}}return null}function Ii(t,e){let n=t,s=0;for(;gs.test(n)&&s<50;)s++,n=n.replace(gs,(o,i,a)=>{let r=a.split(/\{%[-\s]*else\s*-?%\}/),l=r[0],c=r[1]||"",d=l.split(/\{%[-\s]*elif\s+(.*?)\s*-?%\}/);if(d.length>1){if(St(i,e))return d[0];for(let u=1;u<d.length;u+=2){let p=d[u],g=d[u+1]||"";if(St(p,e))return g}return c}return St(i,e)?l:c}),gs.lastIndex=0;return n}function ki(t,e){return t.replace(/\{\{[-\s]*(.*?)[-\s]*\}\}/g,(n,s)=>{let i=s.trim().split("|"),a=i[0].trim(),r=st(e,a);for(let c=1;c<i.length;c++)r=Ti(r,i[c].trim());if(r==null)return"";if(typeof r=="object")return JSON.stringify(r);let l=String(r);return l=l.replace(/\\n/g," ").replace(/\n/g," "),l})}function Wl(t){return t=t.replace(/\{%.*?%\}/gs,""),t=t.replace(/\{\{.*?\}\}/gs,""),t}function Bl(t,e){let n=t.match(/^range\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);if(n){let o=Ci(n[1],e),i=Ci(n[2],e),a=[];for(let r=o;r<i;r++)a.push(r);return a}let s=t.match(/^(.+?)\|split\(['"](.+?)['"]\)$/);if(s){let o=st(e,s[1].trim());return typeof o=="string"?o.split(s[2]):[]}return st(e,t)}function Ci(t,e){let s=t.trim().split("|"),o=s[0].trim();if(!isNaN(Number(o)))return Number(o);let i=st(e,o);for(let a=1;a<s.length;a++)i=Ti(i,s[a].trim());return Number(i)||0}function st(t,e){let n=e.split("."),s=t;for(let o of n){if(s==null||typeof s!="object")return;s=s[o]}return s}function St(t,e){let n=t.trim();if(n.startsWith("not "))return!St(n.slice(4),e);if(n.includes(" and "))return n.split(" and ").every(i=>St(i,e));if(n.includes(" or "))return n.split(" or ").some(i=>St(i,e));let s=n.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);if(s){let i=st(e,s[1].trim()),a=s[2],r=s[3].trim();switch(typeof r=="string"&&r.startsWith('"')&&r.endsWith('"')||typeof r=="string"&&r.startsWith("'")&&r.endsWith("'")?r=r.slice(1,-1):isNaN(Number(r))?r=st(e,r):r=Number(r),a){case"==":return i==r;case"!=":return i!=r;case">":return Number(i)>Number(r);case"<":return Number(i)<Number(r);case">=":return Number(i)>=Number(r);case"<=":return Number(i)<=Number(r)}}let o=st(e,n);return $i(o)}function $i(t){return!(t==null||t===""||t===0||t===!1||Array.isArray(t)&&t.length===0)}function Ti(t,e){let n=t==null?"":String(t),s=e.match(/^(\w+)\((.*)\)$/),o=s?s[1]:e,i=s?s[2].replace(/^["']|["']$/g,""):void 0;switch(o){case"escape":case"e":return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");case"lower":return n.toLowerCase();case"upper":return n.toUpperCase();case"capitalize":return n.charAt(0).toUpperCase()+n.slice(1);case"trim":return n.trim();case"truncate":if(i){let a=parseInt(i,10);return n.length>a?n.slice(0,a)+"...":n}return n;case"default":return $i(t)?t:i??"";case"length":return Array.isArray(t)?t.length:n.length;case"join":return Array.isArray(t)?t.join(i??", "):n;case"int":case"float":return Number(n)||0;case"abs":return Math.abs(Number(n));case"round":return Math.round(Number(n));default:return t}}function Kl(t){if(!t)return{bg:"#0f0f14",surface:"#1a1a20",text:"#ffffff",textMuted:"#666",border:"#333"};let e=(r,l)=>{for(let c of r){let d=new RegExp(`${c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\s*:\\s*([^;})]+)`,"i"),u=t.match(d);if(u)return u[1].trim()}return l},n=e(["--bg","--background","--color-bg","--bg-primary","--body-bg"],"#0f0f14"),s=e(["--surface","--bg-secondary","--card-bg","--color-surface"],n),o=e(["--text","--color-text","--text-primary","--fg","--foreground"],"#ffffff"),i=e(["--text-muted","--text-secondary","--muted","--color-text-muted"],"#666"),a=e(["--border","--border-color","--color-border"],"#333");return{bg:n,surface:s,text:o,textMuted:i,border:a}}function Mi(){let t=v();if(!t)return Ei();let e=ue(),n=t.moduleOrder||[];if(e.length===0&&n.length===0)return Ei();let s=[],o=[],i=[],a=new Set;for(let c of e){if(c.moduleHtml.includes("dnd_area")||c.moduleHtml.includes("extends "))continue;let d;try{let g=JSON.parse(c.fieldsJson);d={module:Pn(g)}}catch{d={module:{}}}let u=hs(c.moduleHtml,d),p=c.moduleName.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");s.push(`<div class="vibespot-module" id="${p}" data-module="${c.moduleName}">${u}</div>`),a.add(c.moduleName),c.moduleCss&&o.push(c.moduleCss),c.moduleJs&&i.push(c.moduleJs)}let r=Kl(t.sharedCss);for(let c of n)if(!a.has(c)){let d=c.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");s.push(`<div class="vibespot-module vibespot-module--pending" id="${d}" data-module="${c}">
475
+ <div class="vibespot-placeholder">
476
+ <div class="vibespot-placeholder__name">${c}</div>
477
+ </div>
478
+ </div>`)}let l=`body{background:${r.bg}}.vibespot-placeholder{display:flex;align-items:center;justify-content:center;min-height:200px;padding:3rem;background:${r.surface};border:1px dashed ${r.border};border-radius:12px;margin:1rem 0}.vibespot-placeholder__name{font-size:1.5rem;font-weight:600;font-family:system-ui,sans-serif;color:${r.textMuted};letter-spacing:.5px;animation:vp-fade 2s ease-in-out infinite}@keyframes vp-fade{0%,100%{opacity:.3}50%{opacity:.8}}`;return ys({renderedModules:s,sharedCss:t.sharedCss,moduleCssArray:[l,...o],sharedJs:t.sharedJs,moduleJsArray:i})}function Ei(){return`<!DOCTYPE html>
475
479
  <html lang="en">
476
480
  <head>
477
481
  <meta charset="utf-8">
@@ -522,7 +526,8 @@ document.querySelectorAll('img').forEach(function(img){
522
526
  <div class="welcome__sub">Build Something Great</div>
523
527
  </div>
524
528
  </body>
525
- </html>`}function ei(e){let t=$();if(!t)return"";let o;for(let i of t.templates)if(o=i.modules.find(a=>a.moduleName===e),o)break;if(o||(o=t.modules.find(i=>i.moduleName===e)),!o)return"";let n;try{let i=JSON.parse(o.fieldsJson);n={module:Sn(i)}}catch{n={module:{}}}let s=Xn(o.moduleHtml,n);return Qn({renderedModules:[`<div class="vibespot-module" data-module="${o.moduleName}">${s}</div>`],sharedCss:t.sharedCss,moduleCssArray:o.moduleCss?[o.moduleCss]:[],sharedJs:t.sharedJs,moduleJsArray:o.moduleJs?[o.moduleJs]:[]})}h();Z();import{execSync as ao}from"child_process";h();h();var V={info(e,t,o){let n=o?`[${e}] ${t} ${JSON.stringify(o)}`:`[${e}] ${t}`;console.log(n)},warn(e,t,o){let n=o?`[${e}] ${t} ${JSON.stringify(o)}`:`[${e}] ${t}`;console.warn(n)},error(e,t,o){let n=o instanceof Error?o.message:o?String(o):"",s=n?`[${e}] ${t}: ${n}`:`[${e}] ${t}`;console.error(s)}};function eo(e){try{return JSON.parse(e)}catch{}let t=e,o=-1;for(let n=0;n<20;n++)try{return JSON.parse(t)}catch(s){if(!(s instanceof SyntaxError))return null;let i=/position (\d+)/.exec(s.message);if(!i)return null;let a=parseInt(i[1],10);if(a<=o)return null;o=a;let r=Math.max(0,a-5),c=t.slice(r,a+1).lastIndexOf('"');if(c===-1)return null;let u=r+c;if(u>0&&t[u-1]==="\\")return null;t=t.slice(0,u)+'\\"'+t.slice(u+1)}return null}function Ga(e){let t=e.indexOf('"modules"');if(t===-1)return null;let o=e.indexOf("[",t);if(o===-1)return null;let n=-1,s=0,i=!1,a=!1;for(let u=o+1;u<e.length;u++){let p=e[u];if(a){a=!1;continue}if(p==="\\"){a=!0;continue}if(p==='"'){i=!i;continue}i||(p==="{"&&s++,p==="}"&&(s--,s===0&&(n=u)))}if(n===-1)return null;let l=e.slice(0,n+1)+"]}",c=l.trimStart().startsWith("{")?l:"{"+l;return eo(c)}function Zn(e){return{moduleName:String(e.moduleName||""),fieldsJson:typeof e.fieldsJson=="string"?e.fieldsJson:JSON.stringify(e.fieldsJson,null,2),metaJson:typeof e.metaJson=="string"?e.metaJson:JSON.stringify(e.metaJson,null,2),moduleHtml:String(e.moduleHtml||""),moduleCss:String(e.moduleCss||""),moduleJs:e.moduleJs?String(e.moduleJs):void 0}}function ti(e,t){let o=!1,n,s=/```vibespot-modules\s*\n?([\s\S]*?)```/g;for(;(n=s.exec(e))!==null;)try{V.info("parse","Found vibespot-modules block",{length:n[1].length});let i=eo(n[1]);if(!i||typeof i!="object")throw V.warn("parse","tryParseJSON returned non-object",{result:typeof i}),new Error("Invalid JSON after repair");let a=i;a.modules&&Array.isArray(a.modules)&&(yn({modules:a.modules.map(r=>Zn(r)),sharedCss:a.sharedCss!==void 0?String(a.sharedCss):void 0,sharedJs:a.sharedJs!==void 0?String(a.sharedJs):void 0}),o=!0)}catch(i){V.warn("parse","Failed to parse vibespot-modules block",{error:i instanceof Error?i.message:String(i)})}if(!o){let i=/```(?:json)?\s*\n([\s\S]*?)```/g;for(;(n=i.exec(e))!==null;)if(n[1].includes('"modules"'))try{let a=eo(n[1]);if(!a||typeof a!="object")throw new Error("Invalid JSON after repair");let r=a;r.modules&&Array.isArray(r.modules)&&(yn({modules:r.modules.map(l=>Zn(l)),sharedCss:r.sharedCss!==void 0?String(r.sharedCss):void 0,sharedJs:r.sharedJs!==void 0?String(r.sharedJs):void 0}),o=!0)}catch(a){V.warn("parse","Failed to parse JSON module block",{error:a instanceof Error?a.message:String(a)})}}if(!o&&(e.match(/```/g)||[]).length%2!==0&&e.includes('"modules"')){V.info("parse","Detected truncated response (odd fence count), attempting salvage");let a=e.lastIndexOf("```"),r=e.slice(a+3);r=r.replace(/^[\w-]*\s*\n?/,"");let l=Ga(r);if(l){let c=l;c.modules&&Array.isArray(c.modules)&&c.modules.length>0&&(V.info("parse","Salvaged modules from truncated response",{count:c.modules.length}),yn({modules:c.modules.map(u=>Zn(u)),sharedCss:c.sharedCss!==void 0?String(c.sharedCss):void 0,sharedJs:c.sharedJs!==void 0?String(c.sharedJs):void 0}),o=!0,t&&t("Response was truncated \u2014 some modules may be incomplete. Try sending your request again for the full set."))}}if(!o){V.info("parse","No modules applied",{responseLength:e.length,hasVibespot:e.includes("vibespot-modules"),hasModules:e.includes('"modules"'),fenceCount:(e.match(/```/g)||[]).length});let i=e.includes("vibespot-modules")||e.includes('"modules"'),a=/\bmodule|modul/i.test(e)&&(/\bcreated?\b|\berstellt\b|\bgenerat/i.test(e)||/\|.*\|.*\|/m.test(e));if(i||a){let r=i?"Module changes could not be applied \u2014 the AI response contained invalid JSON. Try sending your request again.":"The AI described modules but did not include the required structured data. Try sending your request again.";V.warn("parse",r),t&&t(r)}}}h();import{spawn as Ua}from"child_process";Z();h();function pt(){let e=$();return e?{pageType:Fe()?.pageType,brandAssets:e.brandAssets}:{}}function ft(e,t,o=!1,n,s){let i=`You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.
529
+ </html>`}function Ni(t){let e=v();if(!e)return"";let n;for(let i of e.templates)if(n=i.modules.find(a=>a.moduleName===t),n)break;if(n||(n=e.modules.find(i=>i.moduleName===t)),!n)return"";let s;try{let i=JSON.parse(n.fieldsJson);s={module:Pn(i)}}catch{s={module:{}}}let o=hs(n.moduleHtml,s);return ys({renderedModules:[`<div class="vibespot-module" data-module="${n.moduleName}">${o}</div>`],sharedCss:e.sharedCss,moduleCssArray:n.moduleCss?[n.moduleCss]:[],sharedJs:e.sharedJs,moduleJsArray:n.moduleJs?[n.moduleJs]:[]})}f();ee();import{execSync as Ps}from"child_process";f();f();import{appendFileSync as Vl,mkdirSync as Yl,readdirSync as zl,unlinkSync as ql}from"fs";import{join as ws}from"path";import{homedir as Xl}from"os";var Rn=ws(Xl(),".vibespot","logs"),Ql=7,Ss=!1,vs=!1;function Zl(){if(!Ss)try{Yl(Rn,{recursive:!0}),Ss=!0}catch{}}function ec(){if(!vs){vs=!0;try{let t=Date.now()-Ql*864e5;for(let e of zl(Rn)){if(!e.startsWith("vibespot-")||!e.endsWith(".log"))continue;let n=e.slice(9,19),s=new Date(n).getTime();if(s&&s<t)try{ql(ws(Rn,e))}catch{}}}catch{}}}function tc(){let e=new Date().toISOString().slice(0,10);return ws(Rn,`vibespot-${e}.log`)}function nc(){return new Date().toISOString().slice(11,23)}function bs(t,e){if(Zl(),!!Ss){vs||ec();try{Vl(tc(),`${nc()} ${t} ${e}
530
+ `)}catch{}}}var M={info(t,e,n){let s=n?`[${t}] ${e} ${JSON.stringify(n)}`:`[${t}] ${e}`;console.log(s),bs("INFO",s)},warn(t,e,n){let s=n?`[${t}] ${e} ${JSON.stringify(n)}`:`[${t}] ${e}`;console.warn(s),bs("WARN",s)},error(t,e,n){let s=n instanceof Error?n.message:n?String(n):"",o=s?`[${t}] ${e}: ${s}`:`[${t}] ${e}`;console.error(o),bs("ERROR",o)}};function je(t){try{return JSON.parse(t)}catch{}let e=t,n=-1;for(let s=0;s<20;s++)try{return JSON.parse(e)}catch(o){if(!(o instanceof SyntaxError))return null;let i=/position (\d+)/.exec(o.message);if(!i)return null;let a=parseInt(i[1],10);if(a<=n)return null;n=a;let r=Math.max(0,a-5),c=e.slice(r,a+1).lastIndexOf('"');if(c===-1)return null;let d=r+c;if(d>0&&e[d-1]==="\\")return null;e=e.slice(0,d)+'\\"'+e.slice(d+1)}return null}function Lt(t){let e=t.indexOf('"modules"');if(e===-1)return null;let n=t.indexOf("[",e);if(n===-1)return null;let s=-1,o=0,i=!1,a=!1;for(let d=n+1;d<t.length;d++){let u=t[d];if(a){a=!1;continue}if(u==="\\"){a=!0;continue}if(u==='"'){i=!i;continue}i||(u==="{"&&o++,u==="}"&&(o--,o===0&&(s=d)))}if(s===-1)return null;let l=t.slice(0,s+1)+"]}",c=l.trimStart().startsWith("{")?l:"{"+l;return je(c)}function xs(t){return{moduleName:String(t.moduleName||""),fieldsJson:typeof t.fieldsJson=="string"?t.fieldsJson:JSON.stringify(t.fieldsJson,null,2),metaJson:typeof t.metaJson=="string"?t.metaJson:JSON.stringify(t.metaJson,null,2),moduleHtml:String(t.moduleHtml||""),moduleCss:String(t.moduleCss||""),moduleJs:t.moduleJs?String(t.moduleJs):void 0}}function _i(t,e){let n=!1,s,o=/```vibespot-modules\s*\n?([\s\S]*?)```/g;for(;(s=o.exec(t))!==null;)try{M.info("parse","Found vibespot-modules block",{length:s[1].length});let i=je(s[1]);if(!i||typeof i!="object")throw M.warn("parse","tryParseJSON returned non-object",{result:typeof i}),new Error("Invalid JSON after repair");let a=i;a.modules&&Array.isArray(a.modules)&&(Oe({modules:a.modules.map(r=>xs(r)),sharedCss:a.sharedCss!==void 0?String(a.sharedCss):void 0,sharedJs:a.sharedJs!==void 0?String(a.sharedJs):void 0}),n=!0)}catch(i){M.warn("parse","Failed to parse vibespot-modules block",{error:i instanceof Error?i.message:String(i)})}if(!n){let i=/```(?:json)?\s*\n([\s\S]*?)```/g;for(;(s=i.exec(t))!==null;)if(s[1].includes('"modules"'))try{let a=je(s[1]);if(!a||typeof a!="object")throw new Error("Invalid JSON after repair");let r=a;r.modules&&Array.isArray(r.modules)&&(Oe({modules:r.modules.map(l=>xs(l)),sharedCss:r.sharedCss!==void 0?String(r.sharedCss):void 0,sharedJs:r.sharedJs!==void 0?String(r.sharedJs):void 0}),n=!0)}catch(a){M.warn("parse","Failed to parse JSON module block",{error:a instanceof Error?a.message:String(a)})}}if(!n&&(t.match(/```/g)||[]).length%2!==0&&t.includes('"modules"')){M.info("parse","Detected truncated response (odd fence count), attempting salvage");let a=t.lastIndexOf("```"),r=t.slice(a+3);r=r.replace(/^[\w-]*\s*\n?/,"");let l=Lt(r);if(l){let c=l;c.modules&&Array.isArray(c.modules)&&c.modules.length>0&&(M.info("parse","Salvaged modules from truncated response",{count:c.modules.length}),Oe({modules:c.modules.map(d=>xs(d)),sharedCss:c.sharedCss!==void 0?String(c.sharedCss):void 0,sharedJs:c.sharedJs!==void 0?String(c.sharedJs):void 0}),n=!0,e&&e("Response was truncated \u2014 some modules may be incomplete. Try sending your request again for the full set."))}}if(!n){M.info("parse","No modules applied",{responseLength:t.length,hasVibespot:t.includes("vibespot-modules"),hasModules:t.includes('"modules"'),fenceCount:(t.match(/```/g)||[]).length});let i=t.includes("vibespot-modules")||t.includes('"modules"'),a=/\bmodule|modul/i.test(t)&&(/\bcreated?\b|\berstellt\b|\bgenerat/i.test(t)||/\|.*\|.*\|/m.test(t));if(i||a){let r=i?"Module changes could not be applied \u2014 the AI response contained invalid JSON. Try sending your request again.":"The AI described modules but did not include the required structured data. Try sending your request again.";M.warn("parse",r),e&&e(r)}}}f();import{spawn as sc}from"child_process";ee();f();function vt(){let t=v();return t?{pageType:Se()?.pageType,brandAssets:t.brandAssets}:{}}function wt(t,e,n=!1,s,o){let i=`You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.
526
531
 
527
532
  ## Your Role
528
533
  You generate native HubSpot CMS modules directly from user descriptions. Every module you create is immediately compatible with HubSpot's drag-and-drop page editor.
@@ -564,8 +569,8 @@ NEVER respond with only a text summary. The vibespot-modules JSON block is manda
564
569
  - NEVER use "name": "name" (reserved) \u2014 use "item_name" instead
565
570
  - NEVER put literal \\n newline sequences in field default values \u2014 use plain text without line breaks
566
571
  - Wrap style fields in a "styles" group with "tab": "STYLE"
567
- - All CSS classes must use a unique prefix "${t}-" to avoid theme conflicts
568
- - Use BEM naming: ${t}-module__element--modifier
572
+ - All CSS classes must use a unique prefix "${e}-" to avoid theme conflicts
573
+ - Use BEM naming: ${e}-module__element--modifier
569
574
  - metaJson must include: host_template_types: ["PAGE"], is_available_for_new_content: true
570
575
  - For repeater groups, use "occurrence": { "min": 0, "max": 100 } and iterate with {% for %}
571
576
  - Color fields: type "color", default { "color": "#hex", "opacity": 100 }
@@ -574,9 +579,9 @@ NEVER respond with only a text summary. The vibespot-modules JSON block is manda
574
579
 
575
580
  ## Images & Media
576
581
  - Users can upload images that get placed in the theme's assets/ folder automatically
577
- - When the user uploads an image and wants it on the page, reference it with: {{ get_asset_url("${t}/assets/filename.ext") }}
578
- - IMPORTANT: get_asset_url() paths must include the theme name prefix "${t}/" because HubSpot resolves from the Design Manager root
579
- - For background images with uploaded assets: style="background-image: url('{{ get_asset_url(\\"${t}/assets/filename.ext\\") }}')"
582
+ - When the user uploads an image and wants it on the page, reference it with: {{ get_asset_url("${e}/assets/filename.ext") }}
583
+ - IMPORTANT: get_asset_url() paths must include the theme name prefix "${e}/" because HubSpot resolves from the Design Manager root
584
+ - For background images with uploaded assets: style="background-image: url('{{ get_asset_url(\\"${e}/assets/filename.ext\\") }}')"
580
585
  - For images without an uploaded asset, use image fields (type "image") with placehold.co defaults
581
586
  - ALWAYS use image fields (type "image") so users can swap images in the page editor
582
587
  - Use placehold.co URLs as defaults so the preview looks complete (e.g. https://placehold.co/800x600/1a1a2e/ffffff?text=Hero+Image)
@@ -601,25 +606,25 @@ The current template's modules are listed in page order in the user message. Thi
601
606
  - **Rearrange**: When the user asks to reorder sections, include a "moduleOrder" array in the vibespot-modules JSON with the new sequence of module names.
602
607
  - **Remove**: When the user asks to remove a section, omit it from the output.
603
608
  - **Preserve**: Always include ALL modules you want to keep (modified + unchanged) in your output. Modules omitted from the output will be removed from the page.
604
- - **Design consistency**: Match the existing theme's design language \u2014 reuse the same CSS custom properties, class naming prefix, spacing scale, and typography.`,a=n?Yo(n):"",r=a?`
609
+ - **Design consistency**: Match the existing theme's design language \u2014 reuse the same CSS custom properties, class naming prefix, spacing scale, and typography.`,a=s?xo(s):"",r=a?`
605
610
 
606
611
  ## Page Type Context
607
- ${a}`:"",l="";if(s?.styleguide&&(l+=`
612
+ ${a}`:"",l="";if(o?.styleguide&&(l+=`
608
613
 
609
614
  ## Brand Style Guide
610
- ${s.styleguide}`),s?.brandvoice&&(l+=`
615
+ ${o.styleguide}`),o?.brandvoice&&(l+=`
611
616
 
612
617
  ## Brand Voice
613
- ${s.brandvoice}`),s?.humanify!==!1){let c=Bo();c&&(l+=`
618
+ ${o.brandvoice}`),o?.humanify!==!1){let d=wo();d&&(l+=`
614
619
 
615
620
  ## Anti-AI Copy Rules (Humanify)
616
- ${c}`)}return o?i+r+l+`
621
+ ${d}`)}let c="\n\n## REMINDER \u2014 Output Format (CRITICAL)\nYour response MUST contain a ```vibespot-modules code block with the full JSON. Without this block, no modules will be created. Do NOT respond with only text, tables, or descriptions. The JSON block is mandatory.";return n?i+r+l+`
617
622
 
618
623
  ## HubSpot CMS Rules
619
- ${at()}
624
+ ${Ve()}
620
625
 
621
626
  ## Conversion Guide Reference
622
- ${e}`:i+r+l+`
627
+ ${t}`+c:i+r+l+`
623
628
 
624
629
  ## Design Quality
625
630
  - Use modern, clean design with proper spacing and typography
@@ -644,118 +649,669 @@ When using scroll-animate classes (opacity: 0 \u2192 visible), you MUST include
644
649
  This makes elements appear after 3 seconds if JS never adds the .visible class. Once JS runs normally and adds .visible, the animation is cancelled.
645
650
 
646
651
  ## Design Guide
647
- ${Wo()}
652
+ ${So()}
648
653
 
649
654
  ## Content & Copywriting Guide
650
- ${Ko()}
655
+ ${vo()}
651
656
 
652
657
  ## HubSpot CMS Rules
653
- ${at()}
658
+ ${Ve()}
654
659
 
655
660
  ## Conversion Guide Reference
656
- ${e}`}function Pt(){let e=$(),t=[],o=e.modules,n=o.length;if(n>0){t.push(`
661
+ ${t}`+c}function Gt(){let t=v(),e=[],n=t.modules,s=n.length;if(s>0){e.push(`
657
662
 
658
663
  ## Page Narrative (module sequence)
659
- `),t.push(`This template has ${n} module${n===1?"":"s"} in this order:
660
- `);for(let r=0;r<n;r++)t.push(`${r+1}. ${o[r].moduleName}
661
- `);t.push(`
664
+ `),e.push(`This template has ${s} module${s===1?"":"s"} in this order:
665
+ `);for(let r=0;r<s;r++)e.push(`${r+1}. ${n[r].moduleName}
666
+ `);e.push(`
662
667
  When the user asks to modify this page, decide whether to MODIFY existing modules, ADD new ones at the right narrative position, REARRANGE the sequence, or REMOVE sections. Always include ALL modules you want to keep in your output.
663
- `),t.push(`
668
+ `),e.push(`
664
669
  ## Current Module State
665
- `);for(let r=0;r<n;r++){let l=o[r];t.push(`
666
- ### ${r+1}/${n}: ${l.moduleName}.module
667
- `),t.push(`**fields.json:**
670
+ `);for(let r=0;r<s;r++){let l=n[r];e.push(`
671
+ ### ${r+1}/${s}: ${l.moduleName}.module
672
+ `),e.push(`**fields.json:**
668
673
  \`\`\`json
669
674
  ${l.fieldsJson}
670
675
  \`\`\`
671
- `),t.push(`**module.html:**
676
+ `),e.push(`**module.html:**
672
677
  \`\`\`html
673
678
  ${l.moduleHtml}
674
679
  \`\`\`
675
- `),t.push(`**module.css:**
680
+ `),e.push(`**module.css:**
676
681
  \`\`\`css
677
682
  ${l.moduleCss}
678
683
  \`\`\`
679
- `),l.moduleJs&&t.push(`**module.js:**
684
+ `),l.moduleJs&&e.push(`**module.js:**
680
685
  \`\`\`js
681
686
  ${l.moduleJs}
682
687
  \`\`\`
683
- `)}e.sharedCss&&t.push(`
688
+ `)}t.sharedCss&&e.push(`
684
689
  ### Shared CSS
685
690
  \`\`\`css
686
- ${e.sharedCss}
691
+ ${t.sharedCss}
687
692
  \`\`\`
688
- `),e.sharedJs&&t.push(`
693
+ `),t.sharedJs&&e.push(`
689
694
  ### Shared JS
690
695
  \`\`\`js
691
- ${e.sharedJs}
696
+ ${t.sharedJs}
692
697
  \`\`\`
693
- `)}let s=dt(),i=new Set(e.modules.map(r=>r.moduleName)),a=s.filter(r=>!i.has(r.module.moduleName));if(a.length>0){t.push(`
698
+ `)}let o=qe(),i=new Set(t.modules.map(r=>r.moduleName)),a=o.filter(r=>!i.has(r.module.moduleName));if(a.length>0){e.push(`
694
699
 
695
700
  ## Available modules in this theme (reusable)
696
- `);for(let r of a)t.push(`- ${r.module.moduleName} (used in: ${r.usedIn.join(", ")})
697
- `);t.push(`
701
+ `);for(let r of a)e.push(`- ${r.module.moduleName} (used in: ${r.usedIn.join(", ")})
702
+ `);e.push(`
698
703
  The user can ask to reuse any of these modules by name.
699
- `)}return t.join("")}function to(e,t){let o=$(),n=o.messages.slice(-20);n.length>0&&n[n.length-1].role==="user"&&n[n.length-1].content===e&&(n=n.slice(0,-1));let s=n.map(u=>({role:u.role,content:u.content})),i=Pt(),a="";if(o.assets?.length){let u=o.assets.filter(p=>p.type==="image"&&p.usage==="asset");u.length>0&&(a=`
704
+ `)}return e.join("")}function Cs(t,e){let n=v(),s=n.messages.slice(-20);s.length>0&&s[s.length-1].role==="user"&&s[s.length-1].content===t&&(s=s.slice(0,-1));let o=s.map(d=>({role:d.role,content:d.content})),i=Gt(),a="";if(n.assets?.length){let d=n.assets.filter(u=>u.type==="image"&&u.usage==="asset");d.length>0&&(a=`
700
705
 
701
706
  ## Available Theme Assets
702
- These images are in the theme's assets/ folder. Reference them with get_asset_url("${o.themeName}/assets/filename"):
703
- ${u.map(p=>`- ${p.filename} (${p.originalName}) \u2192 get_asset_url("${o.themeName}/assets/${p.filename}")`).join(`
704
- `)}`)}let r=e;i&&(r+=`
707
+ These images are in the theme's assets/ folder. Reference them with get_asset_url("${n.themeName}/assets/filename"):
708
+ ${d.map(u=>`- ${u.filename} (${u.originalName}) \u2192 get_asset_url("${n.themeName}/assets/${u.filename}")`).join(`
709
+ `)}`)}let r=t;i&&(r+=`
705
710
 
706
711
  ---
707
- ${i}`),a&&(r+=a);let l=t&&t.length>0;if(l)for(let u of t)u.type==="document"&&u.extractedText&&(r+=`
712
+ ${i}`),a&&(r+=a),r+="\n\n---\nRemember: respond with a ```vibespot-modules JSON block containing ALL modules. No text-only responses.";let l=e&&e.length>0;if(l)for(let d of e)d.type==="document"&&d.extractedText&&(r+=`
708
713
 
709
714
  ---
710
- [Attached document: ${u.originalName}]
711
- ${u.extractedText}`),u.type==="image"&&u.usage==="asset"&&u.assetPath&&(r+=`
715
+ [Attached document: ${d.originalName}]
716
+ ${d.extractedText}`),d.type==="image"&&d.usage==="asset"&&d.assetPath&&(r+=`
712
717
 
713
- [Uploaded image: ${u.originalName} \u2192 available as get_asset_url("${u.assetPath}")]`);let c=l?t.filter(u=>u.type==="image"&&u.base64):[];if(c.length>0){let u=[];for(let p of c)u.push({type:"image",source:{type:"base64",media_type:p.mimeType,data:p.base64}});u.push({type:"text",text:r}),s.push({role:"user",content:u})}else s.push({role:"user",content:r});return s}var no=null;async function Wa(){return no||(no=(await import("@anthropic-ai/sdk")).default),no}function ni(e){if(!e?.length)return"";let t=[];for(let o of e)o.type==="image"&&o.usage==="asset"&&o.assetPath&&t.push(`
714
- [Uploaded image: ${o.originalName} \u2192 use get_asset_url("${o.assetPath}")]`),o.type==="document"&&o.extractedText&&t.push(`
718
+ [Uploaded image: ${d.originalName} \u2192 available as get_asset_url("${d.assetPath}")]`);let c=l?e.filter(d=>d.type==="image"&&d.base64):[];if(c.length>0){let d=[];for(let u of c)d.push({type:"image",source:{type:"base64",media_type:u.mimeType,data:u.base64}});d.push({type:"text",text:r}),o.push({role:"user",content:d})}else o.push({role:"user",content:r});return o}var As=null;async function oc(){return As||(As=(await import("@anthropic-ai/sdk")).default),As}function Pi(t){if(!t?.length)return"";let e=[];for(let n of t)n.type==="image"&&n.usage==="asset"&&n.assetPath&&e.push(`
719
+ [Uploaded image: ${n.originalName} \u2192 use get_asset_url("${n.assetPath}")]`),n.type==="document"&&n.extractedText&&e.push(`
715
720
 
716
721
  ---
717
- [Attached document: ${o.originalName}]
718
- ${o.extractedText}`);return t.join("")}var ce=["Analyzing your request...","Reading the conversion guide...","Planning module structure...","Generating HTML templates...","Writing CSS styles...","Creating field definitions...","Building module metadata...","Assembling theme assets...","Polishing the output...","Almost there \u2014 hang tight..."],oo=[10,20,40,60,120];async function oi(e,t,o,n,s,i,a,r){let l=await Wa(),c=new l({apiKey:t}),u=de(),f=$().modules.length>0,g=to(e,r),y=pt(),S=ft(u,o,f,y.pageType,y.brandAssets);V.info("anthropic","API call",{model:n,systemPromptLength:S.length,messageCount:g.length,messageRoles:g.map(w=>w.role),lastMessageLength:typeof g[g.length-1]?.content=="string"?g[g.length-1].content.length:"multimodal",conversionGuideLength:u.length});for(let w=0;;w++)try{let k="",E=0,R=i||(()=>{});R(ce[0]);let X=setInterval(()=>{E++,R(ce[Math.min(E,ce.length-1)])},6e3);try{let L=c.messages.stream({model:n,max_tokens:48e3,system:S,messages:g});for await(let O of L)if(O.type==="content_block_delta"&&O.delta.type==="text_delta"){let G=O.delta.text;k+=G,s(G)}}finally{clearInterval(X)}a&&a(k);return}catch(k){let E=k.status,R=k.error?.type;if(!(E===429||R==="rate_limit_error"||k instanceof Error&&k.message.includes("429"))||w>=oo.length)throw k;let L=oo[w];V.warn("ai-engine",`Rate limited (429), attempt ${w+1}/${oo.length} \u2014 waiting ${L}s`),i&&i(`Rate limited by Anthropic API \u2014 retrying in ${L}s...`),await new Promise(O=>setTimeout(O,L*1e3)),i&&i("Retrying...")}}async function si(e,t,o,n,s,i,a,r){let l=de(),c=$().modules.length>0,u=to(e,r),p=pt(),f=u.map(L=>typeof L.content=="string"?L:{role:L.role,content:L.content.map(O=>O.type==="text"?{type:"text",text:O.text}:{type:"image_url",image_url:{url:`data:${O.source.media_type};base64,${O.source.data}`}})}),g=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:n,max_tokens:48e3,stream:!0,messages:[{role:"system",content:ft(l,o,c,p.pageType,p.brandAssets)},...f]})});if(!g.ok){let L=await g.text();throw new Error(`OpenAI API error (${g.status}): ${L}`)}let y=0,S=i||(()=>{});S(ce[0]);let w=setInterval(()=>{y++,S(ce[Math.min(y,ce.length-1)])},6e3),k="",E=g.body.getReader(),R=new TextDecoder,X="";try{for(;;){let{done:L,value:O}=await E.read();if(L)break;X+=R.decode(O,{stream:!0});let G=X.split(`
719
- `);X=G.pop()||"";for(let oe of G){if(!oe.startsWith("data: "))continue;let H=oe.slice(6).trim();if(H==="[DONE]")break;try{let se=JSON.parse(H).choices?.[0]?.delta?.content;se&&(k+=se,s(se))}catch{}}}}finally{clearInterval(w)}a&&a(k)}async function ii(e,t,o,n,s,i,a){let r=de(),l=$(),c=l.modules.length>0,u=Pt(),p=pt(),f=[];for(let H of l.messages.slice(-20))f.push({role:H.role==="assistant"?"model":"user",parts:[{text:H.content}]});let g=u?`${e}
722
+ [Attached document: ${n.originalName}]
723
+ ${n.extractedText}`);return e.join("")}var me=["Analyzing your request...","Reading the conversion guide...","Planning module structure...","Generating HTML templates...","Writing CSS styles...","Creating field definitions...","Building module metadata...","Assembling theme assets...","Polishing the output...","Almost there \u2014 hang tight..."],Is=[10,20,40,60,120];async function Ri(t,e,n,s,o,i,a,r){let l=await oc(),c=new l({apiKey:e}),d=re(),p=v().modules.length>0,g=Cs(t,r),h=vt(),b=wt(d,n,p,h.pageType,h.brandAssets);M.info("anthropic","API call",{model:s,systemPromptLength:b.length,messageCount:g.length,messageRoles:g.map(y=>y.role),lastMessageLength:typeof g[g.length-1]?.content=="string"?g[g.length-1].content.length:"multimodal",conversionGuideLength:d.length});for(let y=0;;y++)try{let w="",I=0,T=i||(()=>{});T(me[0]);let J=setInterval(()=>{I++,T(me[Math.min(I,me.length-1)])},6e3);try{let D=c.messages.stream({model:s,max_tokens:48e3,system:b,messages:g});for await(let R of D)if(R.type==="content_block_delta"&&R.delta.type==="text_delta"){let L=R.delta.text;w+=L,o(L)}}finally{clearInterval(J)}a&&a(w);return}catch(w){let I=w.status,T=w.error?.type;if(!(I===429||T==="rate_limit_error"||w instanceof Error&&w.message.includes("429"))||y>=Is.length)throw w;let D=Is[y];M.warn("ai-engine",`Rate limited (429), attempt ${y+1}/${Is.length} \u2014 waiting ${D}s`),i&&i(`Rate limited by Anthropic API \u2014 retrying in ${D}s...`),await new Promise(R=>setTimeout(R,D*1e3)),i&&i("Retrying...")}}async function Oi(t,e,n,s,o,i,a,r){let l=re(),c=v().modules.length>0,d=Cs(t,r),u=vt(),p=d.map(D=>typeof D.content=="string"?D:{role:D.role,content:D.content.map(R=>R.type==="text"?{type:"text",text:R.text}:{type:"image_url",image_url:{url:`data:${R.source.media_type};base64,${R.source.data}`}})}),g=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:s,max_tokens:48e3,stream:!0,messages:[{role:"system",content:wt(l,n,c,u.pageType,u.brandAssets)},...p]})});if(!g.ok){let D=await g.text();throw new Error(`OpenAI API error (${g.status}): ${D}`)}let h=0,b=i||(()=>{});b(me[0]);let y=setInterval(()=>{h++,b(me[Math.min(h,me.length-1)])},6e3),w="",I=g.body.getReader(),T=new TextDecoder,J="";try{for(;;){let{done:D,value:R}=await I.read();if(D)break;J+=T.decode(R,{stream:!0});let L=J.split(`
724
+ `);J=L.pop()||"";for(let Z of L){if(!Z.startsWith("data: "))continue;let G=Z.slice(6).trim();if(G==="[DONE]")break;try{let O=JSON.parse(G).choices?.[0]?.delta?.content;O&&(w+=O,o(O))}catch{}}}}finally{clearInterval(y)}a&&a(w)}async function ji(t,e,n,s,o,i,a){let r=re(),l=v(),c=l.modules.length>0,d=Gt(),u=vt(),p=[];for(let G of l.messages.slice(-20))p.push({role:G.role==="assistant"?"model":"user",parts:[{text:G.content}]});let g=d?`${t}
720
725
 
721
726
  ---
722
- ${u}`:e;if(a?.length)for(let H of a)H.type==="document"&&H.extractedText&&(g+=`
727
+ ${d}`:t;if(a?.length)for(let G of a)G.type==="document"&&G.extractedText&&(g+=`
723
728
 
724
729
  ---
725
- [Attached document: ${H.originalName}]
726
- ${H.extractedText}`),H.type==="image"&&H.usage==="asset"&&H.assetPath&&(g+=`
730
+ [Attached document: ${G.originalName}]
731
+ ${G.extractedText}`),G.type==="image"&&G.usage==="asset"&&G.assetPath&&(g+=`
727
732
 
728
- [Uploaded image: ${H.originalName} \u2192 available as get_asset_url("${H.assetPath}")]`);let y=[];if(a?.length)for(let H of a)H.type==="image"&&H.base64&&y.push({inlineData:{mimeType:H.mimeType,data:H.base64}});y.push({text:g}),f.push({role:"user",parts:y});let w=`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse&key=${t}`,k=await fetch(w,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({systemInstruction:{parts:[{text:ft(r,o,c,p.pageType,p.brandAssets)}]},contents:f,generationConfig:{maxOutputTokens:48e3}})});if(!k.ok){let H=await k.text();throw new Error(`Gemini API error (${k.status}): ${H}`)}let E=0,R=s||(()=>{});R(ce[0]);let X=setInterval(()=>{E++,R(ce[Math.min(E,ce.length-1)])},6e3),L="",O=k.body.getReader(),G=new TextDecoder,oe="";try{for(;;){let{done:H,value:Jt}=await O.read();if(H)break;oe+=G.decode(Jt,{stream:!0});let se=oe.split(`
729
- `);oe=se.pop()||"";for(let Se of se){if(!Se.startsWith("data: "))continue;let He=Se.slice(6).trim();try{let _n=JSON.parse(He).candidates?.[0]?.content?.parts?.[0]?.text;_n&&(L+=_n,n(_n))}catch{}}}}finally{clearInterval(X)}i&&i(L)}function ri(e,t,o,n){return new Promise((s,i)=>{let a={...process.env};delete a.CLAUDECODE;let r=Ua(e,t,{stdio:["pipe","pipe","pipe"],env:a,shell:!0}),l="",c="";r.stdout.on("data",u=>{let p=u.toString();l+=p,n&&n(p)}),r.stderr.on("data",u=>{c+=u.toString()}),r.on("error",u=>i(new Error(`${e} failed to start: ${u.message}`))),r.on("close",u=>{u!==0?i(new Error(`${e} exited with code ${u}.
733
+ [Uploaded image: ${G.originalName} \u2192 available as get_asset_url("${G.assetPath}")]`);let h=[];if(a?.length)for(let G of a)G.type==="image"&&G.base64&&h.push({inlineData:{mimeType:G.mimeType,data:G.base64}});h.push({text:g}),p.push({role:"user",parts:h});let y=`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse&key=${e}`,w=await fetch(y,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({systemInstruction:{parts:[{text:wt(r,n,c,u.pageType,u.brandAssets)}]},contents:p,generationConfig:{maxOutputTokens:48e3}})});if(!w.ok){let G=await w.text();throw new Error(`Gemini API error (${w.status}): ${G}`)}let I=0,T=o||(()=>{});T(me[0]);let J=setInterval(()=>{I++,T(me[Math.min(I,me.length-1)])},6e3),D="",R=w.body.getReader(),L=new TextDecoder,Z="";try{for(;;){let{done:G,value:H}=await R.read();if(G)break;Z+=L.decode(H,{stream:!0});let O=Z.split(`
734
+ `);Z=O.pop()||"";for(let te of O){if(!te.startsWith("data: "))continue;let ie=te.slice(6).trim();try{let It=JSON.parse(ie).candidates?.[0]?.content?.parts?.[0]?.text;It&&(D+=It,s(It))}catch{}}}}finally{clearInterval(J)}i&&i(D)}function On(t,e,n,s){return new Promise((o,i)=>{let a={...process.env};delete a.CLAUDECODE;let r=sc(t,e,{stdio:["pipe","pipe","pipe"],env:a}),l="",c="",d=!1,u=h=>{d||(d=!0,h())};r.stdout.on("data",h=>{let b=h.toString();l+=b,s&&s(b)}),r.stderr.on("data",h=>{c+=h.toString()}),r.on("error",h=>u(()=>i(new Error(`${t} failed to start: ${h.message}`)))),r.on("close",h=>{u(()=>{h!==0?i(new Error(`${t} exited with code ${h}.
730
735
  `+(c?`Stderr: ${c.slice(0,500)}
731
- `:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):s(l)}),r.stdin.on("error",()=>{}),r.stdin.write(o),r.stdin.end(),setTimeout(()=>{r.kill(),i(new Error(`${e} timed out after 10 minutes`))},6e5)})}async function ai(e,t,o,n,s,i){let a=de(),r=N(),l=$().modules.length>0,c=pt(),u=ft(a,t,l,c.pageType,c.brandAssets);u+=`
736
+ `:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):o(l)})}),r.stdin.on("error",()=>{}),r.stdin.write(n)?r.stdin.end():r.stdin.once("drain",()=>r.stdin.end());let g=setTimeout(()=>{r.kill(),u(()=>i(new Error(`${t} timed out after 5 minutes.
737
+ `+(c?`Stderr: ${c.slice(0,500)}
738
+ `:"")+`Partial output (${l.length} chars): ${l.slice(0,500)}`)))},3e5);r.on("close",()=>clearTimeout(g))})}async function Fi(t,e,n,s,o,i){let a=re(),r=E(),l=v().modules.length>0,c=vt(),d=wt(a,e,l,c.pageType,c.brandAssets);d+=`
732
739
 
733
740
  ## User Request
734
- `+e,u+=Pt(),u+=ni(i);let p=["--print"];r.claudeCodeModel&&p.push("--model",r.claudeCodeModel);let f=0,g=n||(()=>{});g(ce[0]);let y=setInterval(()=>{f++;let S=ce[Math.min(f,ce.length-1)];g(S)},6e3);try{let S=await ri("claude",p,u,w=>{o(w)});s&&s(S)}finally{clearInterval(y)}}async function so(e,t,o,n,s,i,a){let r=de(),l=$().modules.length>0,c=pt(),u=ft(r,o,l,c.pageType,c.brandAssets);u+=`
741
+ `+t,d+=Gt(),d+=Pi(i),d+="\n\n---\nRemember: respond with a ```vibespot-modules JSON block containing ALL modules. No text-only responses.";let u=["--print"];r.claudeCodeModel&&u.push("--model",r.claudeCodeModel);let p=0,g=s||(()=>{});g(me[0]);let h=setInterval(()=>{p++;let b=me[Math.min(p,me.length-1)];g(b)},6e3);try{let b=await On("claude",u,d,y=>{n(y)});o&&o(b)}finally{clearInterval(h)}}async function ks(t,e,n,s,o,i,a){let r=re(),l=v().modules.length>0,c=vt(),d=wt(r,n,l,c.pageType,c.brandAssets);d+=`
735
742
 
736
743
  ## User Request
737
- `+t,u+=Pt(),u+=ni(a);let p,f;e==="gemini"?(p="gemini",f=[]):(p="codex",f=["exec","--full-auto"]);let g=0,y=s||(()=>{});y(ce[0]);let S=setInterval(()=>{g++;let w=ce[Math.min(g,ce.length-1)];y(w)},6e3);try{let w=await ri(p,f,u,k=>{n(k)});i&&i(w)}finally{clearInterval(S)}}h();import{createWriteStream as Ka,mkdirSync as li,existsSync as io,readFileSync as ro}from"fs";import{join as Xe,extname as Ba}from"path";import{randomUUID as Ya}from"crypto";import Va from"busboy";h();function d(e,t,o){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(o))}function _(e,t){let o=[];e.on("data",n=>o.push(n)),e.on("end",()=>t(Buffer.concat(o).toString("utf-8")))}var za=10*1024*1024,ci=new Set(["image/png","image/jpeg","image/jpg","image/svg+xml","image/webp","image/gif"]),qa=new Set(["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/markdown","text/plain"]),Xa=new Set([...ci,...qa]);function Qa(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_").replace(/_{2,}/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function Za(e,t){if(!io(Xe(e,t)))return t;let o=Ba(t),n=t.slice(0,-o.length||void 0),s=1;for(;io(Xe(e,`${n}-${s}${o}`));)s++;return`${n}-${s}${o}`}async function el(e){let t=(await import("pdf-parse")).default,o=ro(e);return(await t(o)).text}async function tl(e){return(await(await import("mammoth")).extractRawText({path:e})).value}function nl(e){return ro(e,"utf-8")}function di(e,t){let o=$();if(!o){d(t,400,{error:"No active session"});return}if(!(e.headers["content-type"]||"").includes("multipart/form-data")){d(t,400,{error:"Expected multipart/form-data"});return}let s=[],i=[],a=0,r=[],l=Va({headers:e.headers,limits:{fileSize:za,files:10}});l.on("file",(c,u,p)=>{let{filename:f,mimeType:g}=p;if(a++,!Xa.has(g)){i.push(`Unsupported file type: ${f} (${g})`),u.resume();return}let y=ci.has(g),S=Qa(f),w=Ya(),k,E;y?(k=Xe(o.themePath,"assets"),li(k,{recursive:!0}),E=Za(k,S)):(k=Xe(o.themePath,".vibespot","uploads"),li(k,{recursive:!0}),E=`${w}-${S}`);let R=Xe(k,E),X=Ka(R),L=0,O=!1;u.on("data",G=>{L+=G.length}),u.on("limit",()=>{O=!0,i.push(`File too large (>10MB): ${f}`)}),u.pipe(X),r.push(new Promise(G=>{X.on("finish",()=>{if(!O){let oe={id:w,filename:E,originalName:f,type:y?"image":"document",usage:y?"asset":"context",mimeType:g,size:L,addedAt:new Date().toISOString()};s.push(oe),Os(oe)}G()}),X.on("error",()=>{i.push(`Failed to write: ${f}`),G()})}))}),l.on("finish",async()=>{await Promise.all(r);for(let c of s)if(c.type==="document"){let u=Xe(o.themePath,".vibespot","uploads",c.filename);try{c.mimeType==="application/pdf"?c.extractedText=await el(u):c.mimeType==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"?c.extractedText=await tl(u):c.extractedText=nl(u),V.info("upload",`Extracted text from ${c.originalName} (${c.extractedText.length} chars)`)}catch(p){V.warn("upload",`Failed to extract text from ${c.originalName}: ${p}`),c.extractedText=`[Could not extract text from ${c.originalName}]`}}if(a===0){d(t,400,{error:"No files uploaded"});return}d(t,200,{files:s.map(c=>({id:c.id,filename:c.filename,originalName:c.originalName,type:c.type,usage:c.usage,size:c.size})),errors:i.length>0?i:void 0})}),l.on("error",c=>{V.error("upload",`Busboy error: ${c}`),d(t,500,{error:"Upload failed"})}),e.pipe(l)}function ui(e){let t=$();return t?.assets?e.map(o=>{let n=t.assets.find(i=>i.id===o);if(!n)return null;let s={id:n.id,filename:n.filename,originalName:n.originalName,type:n.type,usage:n.usage,mimeType:n.mimeType};if(n.type==="image"){let i=Xe(t.themePath,"assets",n.filename);io(i)&&(s.base64=ro(i).toString("base64")),s.assetPath=`${t.themeName}/assets/${n.filename}`}else n.type==="document"&&(s.extractedText=n.extractedText);return s}).filter(o=>o!==null):[]}var lo=null;function mi(e){lo=e}var Ot=null;function Mt(){return Ot!==null}function gt(e){if(Ot){let t=$();if(!t||t.id!==Ot){V.warn("ai-handler","Session changed during generation \u2014 discarding AI output");return}}ze("assistant",e),ti(e,lo||void 0),j()}async function co(e,t,o,n){let s=$();if(!s)throw new Error("No active session");Ot=s.id;let a=n?.length?ui(n):void 0;try{let r=N(),l=r.aiEngine||ol();switch(l){case"anthropic-api":case"api":{let c=he("anthropic-api",r);if(!c)throw new Error("Anthropic API key not configured. Open Settings to add one.");await oi(e,c,s.themeName,r.anthropicApiModel||"claude-sonnet-4-6",t,o,gt,a);break}case"openai-api":{let c=he("openai-api",r);if(!c)throw new Error("OpenAI API key not configured. Open Settings to add one.");await si(e,c,s.themeName,r.openaiApiModel||"gpt-4o",t,o,gt,a);break}case"gemini-api":{let c=he("gemini-api",r);if(!c)throw new Error("Gemini API key not configured. Open Settings to add one.");await ii(e,c,s.themeName,t,o,gt,a);break}case"claude-code":await ai(e,s.themeName,t,o,gt,a);break;case"gemini-cli":await so("gemini",e,s.themeName,t,o,gt,a);break;case"codex-cli":await so("codex",e,s.themeName,t,o,gt,a);break;default:throw new Error(`Unknown AI engine: ${l}. Open Settings to configure one.`)}}finally{Ot=null,lo=null}}function ol(){let e=N();if(e.anthropicApiKey||process.env.ANTHROPIC_API_KEY)return"anthropic-api";if(e.openaiApiKey||process.env.OPENAI_API_KEY)return"openai-api";if(e.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY)return"gemini-api";try{return ao("claude --version",{stdio:"pipe"}),"claude-code"}catch{}try{return ao("gemini --version",{stdio:"pipe"}),"gemini-cli"}catch{}try{return ao("codex --version",{stdio:"pipe"}),"codex-cli"}catch{}throw new Error("No AI engine available. Open Settings to configure one.")}Z();h();import{spawn as pi}from"child_process";var Qe=new Map;function Ce(e,t,o){let n=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,s={id:n,command:e,description:t,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null};Qe.set(n,s);let i=e.split(" "),a=pi(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0});a.stdout?.on("data",l=>{s.output+=l.toString()}),a.stderr?.on("data",l=>{s.output+=l.toString()}),a.on("close",l=>{s.status=l===0?"completed":"failed",s.exitCode=l,s.completedAt=Date.now()}),a.on("error",l=>{s.status="failed",s.output+=`
738
- Process error: ${l.message}`,s.completedAt=Date.now()});let r=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(a.kill(),s.status="failed",s.output+=`
739
- Process timed out`,s.completedAt=Date.now())},r),n}function vn(e){return Qe.get(e)}function sl(){let e=Date.now()-18e5;for(let[t,o]of Qe)o.completedAt&&o.completedAt<e&&Qe.delete(t)}setInterval(sl,600*1e3);function wn(e,t,o){let n=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,s={id:n,command:e,description:t,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null,listeners:new Set};Qe.set(n,s);let i=e.split(" "),a=pi(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0}),r=c=>{for(let u of s.listeners)try{u(c)}catch{}};a.stdout?.on("data",c=>{let u=c.toString();s.output+=u,r(u)}),a.stderr?.on("data",c=>{let u=c.toString();s.output+=u,r(u)}),a.on("close",c=>{s.status=c===0?"completed":"failed",s.exitCode=c,s.completedAt=Date.now()}),a.on("error",c=>{s.status="failed",s.output+=`
740
- Process error: ${c.message}`,s.completedAt=Date.now()});let l=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(a.kill(),s.status="failed",s.output+=`
741
- Process timed out`,s.completedAt=Date.now())},l),n}function fi(e,t){let o=Qe.get(e);if(!o||!("listeners"in o))return;let n=o;if(n.output)try{t(n.output)}catch{}n.listeners.add(t)}function gi(e,t){let o=Qe.get(e);!o||!("listeners"in o)||o.listeners.delete(t)}h();import{existsSync as ht,readdirSync as hi,rmSync as il}from"fs";import{join as yt,basename as rl}from"path";import{homedir as al}from"os";import{execSync as yi}from"child_process";Z();en();Ye();Z();Q();var Ae=yt(al(),"vibespot-themes"),xn=null,ll=5e3;function Cn(){if(xn&&Date.now()-xn.ts<ll)return xn.data;let e=[];if(ht(Ae))try{for(let t of hi(Ae,{withFileTypes:!0}))if(t.isDirectory()){let o=yt(Ae,t.name,"theme.json");if(ht(o)){let n=0,s=yt(Ae,t.name,"modules");if(ht(s))try{n=hi(s,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}e.push({name:t.name,moduleCount:n})}}}catch{}return xn={data:e,ts:Date.now()},e}function bi(e){let t=$(),o=Bt(),n=!1;try{yi("hs --version",{encoding:"utf-8",stdio:"pipe"}),n=!0}catch{}let s=ut().sort((a,r)=>r.updatedAt-a.updatedAt).slice(0,10),i=Cn();d(e,200,{hasActiveSession:!!t,activeSession:t?{id:t.id,themeName:t.themeName,moduleCount:t.modules.length}:null,hsInstalled:n,aiAvailable:o.availableEngines.length>0,availableEngines:o.availableEngines,activeEngine:o.activeEngine,sessions:s,localThemes:i})}function Si(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme name is required"});return}let s=n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,""),i=yt(Ae,s);ge(Ae),ht(i)&&il(i,{recursive:!0,force:!0}),Zt(i,s),Nt(i,s),j(),d(t,200,{ok:!0,themeName:s,themePath:i})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function vi(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme name is required"});return}let s=n.replace(/^\/+|\/+$/g,"");if(!s){d(t,400,{error:"Theme name is required"});return}let i=ue(),a=N(),r=s.includes("/")||s.includes("@")?s.replace(/[@/]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""):s,l=yt(Ae,r);ge(Ae),a.hubspotUploadMode==="cli"||!i?(yi(`hs cms fetch "${s}" "${l}"`,{encoding:"utf-8",stdio:"pipe"}),Nt(l,r),Rt(l),j(),d(t,200,{ok:!0,themeName:r,themePath:l,moduleCount:$()?.modules.length||0})):Tt(i,s,l).then(()=>{Nt(l,r),Rt(l),j(),d(t,200,{ok:!0,themeName:r,themePath:l,moduleCount:$()?.modules.length||0})}).catch(c=>{d(t,500,{error:c instanceof Error?c.message:String(c)})})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function wi(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{path:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme path is required"});return}let s=n;if(ht(s)||(s=yt(Ae,n)),!ht(s)){d(t,400,{error:`Theme folder not found: ${n}`});return}let i=rl(s);Nt(s,i),Rt(s),j(),d(t,200,{ok:!0,themeName:i,themePath:s,moduleCount:$()?.modules.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function xi(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{sessionId:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Session ID is required"});return}let s=bn(n);if(!s){d(t,404,{error:"Session not found"});return}d(t,200,{ok:!0,themeName:s.themeName,themePath:s.themePath,moduleCount:s.modules.length,messageCount:s.messages.length})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ci(e,t){_(e,o=>{try{let{apiKey:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"API key is required"});return}z({anthropicApiKey:n}),d(t,200,{ok:!0})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ai(e){let t=ue();if(!t){d(e,200,{themes:[],error:"No HubSpot account connected"});return}(async()=>{let o=await jo(t);if(o.length===0){d(e,200,{themes:[]});return}let n=[],s=o.map(async r=>{let l=r.path||r.name;try{let c=await zt(t,`${l}/theme.json`);c&&!c.folder&&n.push({name:r.name,path:l})}catch{}});await Promise.all(s),n.sort((r,l)=>r.name.localeCompare(l.name));let i=Cn(),a=new Set(i.map(r=>r.name));d(e,200,{themes:n.map(r=>({...r,existsLocally:a.has(r.name)}))})})().catch(o=>{d(e,200,{themes:[],error:o instanceof Error?o.message:String(o)})})}h();import{existsSync as cl,readFileSync as dl,appendFileSync as ul}from"fs";import{join as Ii}from"path";import{homedir as Ti}from"os";Z();Ye();Q();var jt={data:{},ts:0},ml=600*1e3,$i={"claude-code":[{id:"sonnet",label:"Claude Sonnet (default)"},{id:"opus",label:"Claude Opus"},{id:"haiku",label:"Claude Haiku"}],"codex-cli":[{id:"o4-mini",label:"o4 Mini (default)"},{id:"o3",label:"o3"},{id:"gpt-4o",label:"GPT-4o"}]};async function pl(e){let t=await fetch("https://api.anthropic.com/v1/models",{headers:{"x-api-key":e,"anthropic-version":"2023-06-01"}});return t.ok?(await t.json()).data.filter(n=>!n.id.startsWith("claude-3-")&&!n.id.startsWith("claude-2")).map(n=>({id:n.id,label:n.display_name})):[]}async function fl(e){let t=await fetch("https://api.openai.com/v1/models",{headers:{Authorization:`Bearer ${e}`}});if(!t.ok)return[];let o=await t.json(),n=/^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;return o.data.filter(s=>n.test(s.id)).sort((s,i)=>s.id.localeCompare(i.id)).map(s=>({id:s.id,label:s.id}))}async function gl(e){let t=await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${e}`);return t.ok?(await t.json()).models.filter(n=>n.name.includes("gemini-2")).map(n=>({id:n.name.replace("models/",""),label:n.displayName})):[]}async function hl(){if(Date.now()-jt.ts<ml&&Object.keys(jt.data).length>0)return jt.data;let e=N(),t={...$i},o=[],n=he("anthropic-api",e);n&&o.push(pl(n).then(a=>{a.length&&(t["anthropic-api"]=a)}).catch(()=>{}));let s=he("openai-api",e);s&&o.push(fl(s).then(a=>{a.length&&(t["openai-api"]=a)}).catch(()=>{}));let i=he("gemini-api",e);return i&&o.push(gl(i).then(a=>{a.length&&(t["gemini-api"]=a,t["gemini-cli"]=a)}).catch(()=>{})),await Promise.all(o),jt.data=t,jt.ts=Date.now(),t}function ki(e){let t=Bt(),o=N(),n={aiEngine:o.aiEngine||null,claudeCodeModel:o.claudeCodeModel||null,anthropicApiModel:o.anthropicApiModel||null,openaiApiModel:o.openaiApiModel||null,hubspotUploadMode:o.hubspotUploadMode||"api",hubspotAccounts:(o.hubspotAccounts||[]).map(r=>({portalId:r.portalId,portalName:r.portalName,dataCenter:r.dataCenter})),activeHubSpotAccount:o.activeHubSpotAccount||null,enabledCLITools:o.enabledCLITools||[]},s=ut().length,i=Cn().length,a=ot();hl().then(r=>{d(e,200,{version:a,environment:t,config:n,models:r,sessionCount:s,localThemeCount:i})}).catch(()=>{d(e,200,{version:a,environment:t,config:n,models:$i,sessionCount:s,localThemeCount:i})})}function Ei(e,t){_(e,o=>{try{let{engine:n,model:s}=JSON.parse(o);if(!["claude-code","anthropic-api","openai-api","gemini-cli","gemini-api","codex-cli"].includes(n)){d(t,400,{error:`Invalid engine: ${n}`});return}let a={aiEngine:n};if(s)switch(n){case"claude-code":a.claudeCodeModel=s;break;case"anthropic-api":a.anthropicApiModel=s;break;case"openai-api":a.openaiApiModel=s;break}z(a),d(t,200,{ok:!0,engine:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ni(e,t){_(e,o=>{try{let{provider:n,apiKey:s}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"provider is required"});return}if(!s){let l={};switch(n){case"anthropic":l.anthropicApiKey="";break;case"openai":l.openaiApiKey="";break;case"gemini":l.geminiApiKey="";break;default:d(t,400,{error:`Unknown provider: ${n}`});return}z(l),d(t,200,{ok:!0,provider:n,deleted:!0});return}let i={};switch(n){case"anthropic":i.anthropicApiKey=s;break;case"openai":i.openaiApiKey=s;break;case"gemini":i.geminiApiKey=s;break;default:d(t,400,{error:`Unknown provider: ${n}`});return}z(i);let a=null;if(!N().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[n];c&&(z({aiEngine:c}),a=c)}d(t,200,{ok:!0,provider:n,autoSelectedEngine:a})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function _i(e,t){_(e,o=>{try{let{tool:n}=JSON.parse(o),s={hubspot:{cmd:"npm install -g @hubspot/cli",desc:"Installing HubSpot CLI"},claude:{cmd:"npm install -g @anthropic-ai/claude-code",desc:"Installing Claude Code"},gemini:{cmd:"npm install -g @google/gemini-cli",desc:"Installing Gemini CLI"},codex:{cmd:process.platform==="darwin"?"brew install --cask codex":"npm install -g @openai/codex",desc:"Installing OpenAI Codex"},gh:{cmd:process.platform==="darwin"?"brew install gh":"npm install -g @cli/gh",desc:"Installing GitHub CLI"}},i=s[n];if(!i){d(t,400,{error:`Unknown tool: ${n}. Valid: ${Object.keys(s).join(", ")}`});return}let a=Ce(i.cmd,i.desc,{timeout:12e4});d(t,200,{ok:!0,jobId:a})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ri(e,t){_(e,o=>{try{let n=JSON.parse(o||"{}"),s=N(),i=s.hubspotUploadMode||"api";if(n.personalAccessKey)if(i==="api"){Vt(n.personalAccessKey).then(a=>{Ht(n.personalAccessKey,a.portalId,a.portalName,a.dataCenter),d(t,200,{ok:!0,portalName:a.portalName,portalId:a.portalId,dataCenter:a.dataCenter})}).catch(a=>{d(t,400,{error:a instanceof Error?a.message:String(a)})});return}else{if(!$e().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Ce(`hs auth --pak="${n.personalAccessKey}"`,"Authenticating with HubSpot",{timeout:3e4});d(t,200,{ok:!0,jobId:r});return}if(i==="api"){let a=s.hubspotAccounts||[];if(a.length>0&&!n.force){let r=a.find(l=>l.portalId===s.activeHubSpotAccount)||a[0];d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}else{if(!$e().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=ke();if(r.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}d(t,200,{needsKey:!0,instructions:"Create a personal access key in HubSpot",url:"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key",steps:["Click the link above to open HubSpot","Select your account","Create a Personal Access Key with CMS permissions","Copy the key and paste it below"]})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Pi(e,t){_(e,o=>{try{let n=JSON.parse(o||"{}");if(!jn().found){d(t,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=Dn();if(i.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(n.token){let r=Ce(`echo "${n.token}" | gh auth login --with-token`,"Authenticating with GitHub",{timeout:3e4});d(t,200,{ok:!0,jobId:r});return}let a=Ce("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});d(t,200,{ok:!0,jobId:a,browserAuthRequired:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Oi(e,t){_(e,o=>{try{let{portalId:n,action:s}=JSON.parse(o);if((N().hubspotUploadMode||"api")==="api"){if(s==="remove"&&n){To(n),d(t,200,{ok:!0});return}if(n){$o(n),d(t,200,{ok:!0});return}}else{if(!$e().found){d(t,400,{error:"HubSpot CLI not installed"});return}if(s==="remove"&&n){let l=Ce(`hs accounts remove ${n}`,`Removing HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:l});return}if(n){let l=Ce(`hs accounts use ${n}`,`Switching to HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:l});return}}d(t,400,{error:"portalId required"})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Mi(e){let t=Ce("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});d(e,200,{ok:!0,jobId:t})}function ji(e,t){_(e,o=>{try{let{cli:n,apiKey:s}=JSON.parse(o||"{}");switch(n){case"claude":{let i=Ce("CLAUDECODE= claude --print -p 'reply OK'","Authenticating Claude Code (check your browser if prompted)",{timeout:12e4});d(t,200,{ok:!0,jobId:i,hint:"If Claude Code opens a browser window, complete the sign-in there."});break}case"gemini":{let i=Ce("gemini -p 'reply OK'","Authenticating Gemini CLI (check your browser if prompted)",{timeout:12e4});d(t,200,{ok:!0,jobId:i,hint:"If Gemini opens a browser window, complete the sign-in there."});break}case"codex":{if(s&&s.trim()){let i=s.trim();if(process.env.OPENAI_API_KEY=i,z({openaiApiKey:i}),process.platform!=="win32"){let a=`export OPENAI_API_KEY="${i}"`,r=process.env.SHELL?.includes("zsh")?Ii(Ti(),".zshrc"):Ii(Ti(),".bashrc");try{(cl(r)?dl(r,"utf-8"):"").includes("OPENAI_API_KEY")||ul(r,`
744
+ `+e,d+=Gt(),d+=Pi(a),d+="\n\n---\nRemember: respond with a ```vibespot-modules JSON block containing ALL modules. No text-only responses.";let u,p;t==="gemini"?(u="gemini",p=[]):(u="codex",p=["exec","--full-auto"]);let g=0,h=o||(()=>{});h(me[0]);let b=setInterval(()=>{g++;let y=me[Math.min(g,me.length-1)];h(y)},6e3);try{let y=await On(u,p,d,w=>{s(w)});i&&i(y)}finally{clearInterval(b)}}f();import{createWriteStream as ic,mkdirSync as Ji,existsSync as Ts,readFileSync as Es}from"fs";import{join as ot,extname as rc}from"path";import{randomUUID as ac}from"crypto";import lc from"busboy";f();function m(t,e,n){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}function _(t,e){let n=[];t.on("data",s=>n.push(s)),t.on("end",()=>e(Buffer.concat(n).toString("utf-8")))}function $s(t,e,n){_(t,s=>{try{n(JSON.parse(s||"{}"))}catch{m(e,400,{error:"Invalid JSON in request body"})}})}var cc=10*1024*1024,Di=new Set(["image/png","image/jpeg","image/jpg","image/svg+xml","image/webp","image/gif"]),dc=new Set(["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/markdown","text/plain"]),uc=new Set([...Di,...dc]);function mc(t){return t.replace(/[^a-zA-Z0-9._-]/g,"_").replace(/_{2,}/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function pc(t,e){if(!Ts(ot(t,e)))return e;let n=rc(e),s=e.slice(0,-n.length||void 0),o=1;for(;Ts(ot(t,`${s}-${o}${n}`));)o++;return`${s}-${o}${n}`}async function fc(t){let e=(await import("pdf-parse")).default,n=Es(t);return(await e(n)).text}async function gc(t){return(await(await import("mammoth")).extractRawText({path:t})).value}function hc(t){return Es(t,"utf-8")}function Hi(t,e){let n=v();if(!n){m(e,400,{error:"No active session"});return}if(!(t.headers["content-type"]||"").includes("multipart/form-data")){m(e,400,{error:"Expected multipart/form-data"});return}let o=[],i=[],a=0,r=[],l=lc({headers:t.headers,limits:{fileSize:cc,files:10}});l.on("file",(c,d,u)=>{let{filename:p,mimeType:g}=u;if(a++,!uc.has(g)){i.push(`Unsupported file type: ${p} (${g})`),d.resume();return}let h=Di.has(g),b=mc(p),y=ac(),w,I;h?(w=ot(n.themePath,"assets"),Ji(w,{recursive:!0}),I=pc(w,b)):(w=ot(n.themePath,".vibespot","uploads"),Ji(w,{recursive:!0}),I=`${y}-${b}`);let T=ot(w,I),J=ic(T),D=0,R=!1;d.on("data",L=>{D+=L.length}),d.on("limit",()=>{R=!0,i.push(`File too large (>10MB): ${p}`)}),d.pipe(J),r.push(new Promise(L=>{J.on("finish",()=>{if(!R){let Z={id:y,filename:I,originalName:p,type:h?"image":"document",usage:h?"asset":"context",mimeType:g,size:D,addedAt:new Date().toISOString()};o.push(Z),oi(Z)}L()}),J.on("error",()=>{i.push(`Failed to write: ${p}`),L()})}))}),l.on("finish",async()=>{await Promise.all(r);for(let c of o)if(c.type==="document"){let d=ot(n.themePath,".vibespot","uploads",c.filename);try{c.mimeType==="application/pdf"?c.extractedText=await fc(d):c.mimeType==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"?c.extractedText=await gc(d):c.extractedText=hc(d),M.info("upload",`Extracted text from ${c.originalName} (${c.extractedText.length} chars)`)}catch(u){M.warn("upload",`Failed to extract text from ${c.originalName}: ${u}`),c.extractedText=`[Could not extract text from ${c.originalName}]`}}if(a===0){m(e,400,{error:"No files uploaded"});return}m(e,200,{files:o.map(c=>({id:c.id,filename:c.filename,originalName:c.originalName,type:c.type,usage:c.usage,size:c.size})),errors:i.length>0?i:void 0})}),l.on("error",c=>{M.error("upload",`Busboy error: ${c}`),m(e,500,{error:"Upload failed"})}),t.pipe(l)}function Li(t){let e=v();return e?.assets?t.map(n=>{let s=e.assets.find(i=>i.id===n);if(!s)return null;let o={id:s.id,filename:s.filename,originalName:s.originalName,type:s.type,usage:s.usage,mimeType:s.mimeType};if(s.type==="image"){let i=ot(e.themePath,"assets",s.filename);Ts(i)&&(o.base64=Es(i).toString("base64")),o.assetPath=`${e.themeName}/assets/${s.filename}`}else s.type==="document"&&(o.extractedText=s.extractedText);return o}).filter(n=>n!==null):[]}f();f();ee();var Ms=[10,20,40,60,120];async function Gi(t,e){for(let n=0;;n++)try{return await t()}catch(s){let o=s.status,i=s.error?.type;if(!(o===429||i==="rate_limit_error"||s instanceof Error&&s.message.includes("429"))||n>=Ms.length)throw s;let r=Ms[n];M.warn("agent-adapter",`Rate limited (429), attempt ${n+1}/${Ms.length} \u2014 waiting ${r}s`),e&&e(`Rate limited \u2014 retrying in ${r}s...`),await new Promise(l=>setTimeout(l,r*1e3)),e&&e("Retrying...")}}function jn(t){if(t&&typeof t=="object"&&!Array.isArray(t)){let e=t;for(let n of["fieldsJson","metaJson"])e[n]&&typeof e[n]=="object"&&(e[n]=JSON.stringify(e[n]))}return t}var Ns=null;async function yc(){return Ns||(Ns=(await import("@anthropic-ai/sdk")).default),Ns}async function bc(t,e,n){let s=await yc(),o=new s({apiKey:t}),i=n.messages;if(n.structuredOutput){let a={name:n.structuredOutput.name,description:`Return the result as structured JSON matching the ${n.structuredOutput.name} schema.`,input_schema:n.structuredOutput.schema};return Gi(async()=>{let r=await o.messages.create({model:e,max_tokens:n.maxTokens||16e3,system:n.systemPrompt,messages:i,tools:[a],tool_choice:{type:"tool",name:n.structuredOutput.name}});for(let c of r.content)if(c.type==="tool_use")return{type:"structured",data:jn(c.input)};return{type:"text",text:r.content.filter(c=>c.type==="text").map(c=>c.text).join("")}},n.onStatus)}return Gi(async()=>{let a="",r=o.messages.stream({model:e,max_tokens:n.maxTokens||16e3,system:n.systemPrompt,messages:i});for await(let l of r)l.type==="content_block_delta"&&l.delta.type==="text_delta"&&(a+=l.delta.text,n.onChunk&&n.onChunk(l.delta.text));return{type:"text",text:a}},n.onStatus)}function _s(t){let e={...t};if(e.type==="object"&&(e.additionalProperties=!1,e.properties&&typeof e.properties=="object")){let n={};for(let[s,o]of Object.entries(e.properties))n[s]=o&&typeof o=="object"?_s(o):o;e.properties=n}return e.items&&typeof e.items=="object"&&(e.items=_s(e.items)),e}async function Sc(t,e,n){let s=[{role:"system",content:n.systemPrompt},...n.messages.map(l=>({role:l.role,content:typeof l.content=="string"?l.content:l.content.map(c=>({type:"text",text:c.text}))}))],o={model:e,max_tokens:n.maxTokens||16e3,messages:s};n.structuredOutput&&(o.response_format={type:"json_schema",json_schema:{name:n.structuredOutput.name,strict:!0,schema:_s(n.structuredOutput.schema)}});let i=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(!i.ok){let l=await i.text(),c=i.status;if(c===429){let d=new Error(`OpenAI rate limit: ${l}`);throw d.status=429,d}throw new Error(`OpenAI API error (${c}): ${l}`)}let r=(await i.json()).choices?.[0]?.message?.content||"";if(n.structuredOutput)try{return{type:"structured",data:jn(JSON.parse(r))}}catch{return M.warn("agent-adapter","OpenAI structured output parse failed, returning raw text"),{type:"text",text:r}}return{type:"text",text:r}}async function vc(t,e,n){let s=e||"gemini-2.5-flash",o=n.messages.map(d=>({role:d.role==="assistant"?"model":"user",parts:typeof d.content=="string"?[{text:d.content}]:d.content.map(u=>({text:u.text}))})),i={systemInstruction:{parts:[{text:n.systemPrompt}]},contents:o,generationConfig:{maxOutputTokens:n.maxTokens||16e3,...n.structuredOutput?{responseMimeType:"application/json",responseSchema:n.structuredOutput.schema}:{}}},a=`https://generativelanguage.googleapis.com/v1beta/models/${s}:generateContent?key=${t}`,r=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!r.ok){let d=await r.text(),u=r.status;if(u===429){let p=new Error(`Gemini rate limit: ${d}`);throw p.status=429,p}throw new Error(`Gemini API error (${u}): ${d}`)}let c=(await r.json()).candidates?.[0]?.content?.parts?.[0]?.text||"";if(n.structuredOutput)try{return{type:"structured",data:jn(JSON.parse(c))}}catch{return M.warn("agent-adapter","Gemini structured output parse failed, returning raw text"),{type:"text",text:c}}return{type:"text",text:c}}function wc(t){switch(t){case"claude-code":{let e=E(),n=["--print"];return e.claudeCodeModel&&n.push("--model",e.claudeCodeModel),{bin:"claude",args:n}}case"gemini-cli":return{bin:"gemini",args:[]};case"codex-cli":return{bin:"codex",args:["exec","--full-auto"]};default:throw new Error(`Not a CLI engine: ${t}`)}}function xc(t){let e=[t.systemPrompt];for(let n of t.messages){let s=n.role==="user"?"User":"Assistant",o=typeof n.content=="string"?n.content:n.content.map(i=>i.text).join(`
745
+ `);e.push(`
746
+
747
+ ## ${s}
748
+ ${o}`)}if(t.structuredOutput){let n=Ui(t.structuredOutput.schema);e.push(`
749
+
750
+ ## Output Format \u2014 CRITICAL
751
+ Respond with a JSON code block. Wrap your JSON in \`\`\`json fences. No prose or explanation before or after the code block.
752
+
753
+ The JSON must match this structure:
754
+ ${n}`)}return e.join("")}function Ui(t,e=0){let n=" ".repeat(e),s=t.properties,o=t.required||[];if(!s)return`${n}${JSON.stringify(t)}`;let i=["{"];for(let[a,r]of Object.entries(s)){let l=o.includes(a)?" (required)":"",c=r.type||"any",d=r.description?` \u2014 ${r.description}`:"",u=r.enum?` [${r.enum.join(", ")}]`:"";if(c==="array"&&r.items){let p=r.items.type||"object";i.push(`${n} "${a}": ${c}<${p}>${l}${d}${u}`)}else c==="object"&&r.properties?i.push(`${n} "${a}": ${Ui(r,e+1)}${l}${d}`):i.push(`${n} "${a}": ${c}${l}${d}${u}`)}return i.push(`${n}}`),i.join(`
755
+ `)}function Cc(t){let e=t.trim(),n=je(e);if(n&&typeof n=="object")return n;let s=e.match(/```(?:json|vibespot-modules)?\s*\n([\s\S]*?)```/i);if(s){let r=s[1].trim(),l=je(r);if(l&&typeof l=="object")return l;let c=Lt(r);if(c&&typeof c=="object")return c}let o=e.indexOf("{"),i=e.lastIndexOf("}");if(o!==-1&&i>o){let r=e.slice(o,i+1),l=je(r);if(l&&typeof l=="object")return l;let c=Lt(r);if(c&&typeof c=="object")return c}let a=Lt(e);return a&&typeof a=="object"?a:null}async function Ac(t,e,n){let{bin:s,args:o}=wc(t),i=xc(n),a=await On(s,o,i,n.onChunk);if(!n.structuredOutput)return{type:"text",text:a};let r=Cc(a);return r?{type:"structured",data:jn(r)}:(M.warn("agent-cli",`${t}: failed to parse structured output, returning text`,{outputPreview:a.slice(0,500),outputLength:a.length}),{type:"text",text:a})}var Ic=new Set(["anthropic-api","openai-api","gemini-api"]);async function kc(t,e,n,s){switch(M.info("agent-adapter",`${t} API call`,{model:n,structured:!!s.structuredOutput,schemaName:s.structuredOutput?.name,systemPromptLength:s.systemPrompt.length,messageCount:s.messages.length}),t){case"anthropic-api":return bc(e,n,s);case"openai-api":return Sc(e,n,s);case"gemini-api":return vc(e,n,s);default:throw new Error(`Unsupported API engine: ${t}`)}}async function it(t,e,n,s){return Ic.has(t)?kc(t,e,n,s):(M.info("agent-adapter",`${t} CLI call`,{structured:!!s.structuredOutput,schemaName:s.structuredOutput?.name,systemPromptLength:s.systemPrompt.length,messageCount:s.messages.length}),Ac(t,n,s))}function Fn(t){return t==="anthropic-api"||t==="openai-api"||t==="gemini-api"||t==="claude-code"||t==="gemini-cli"||t==="codex-cli"}function Ut(t){return t==="claude-code"||t==="gemini-cli"||t==="codex-cli"}f();f();function Wi(t,e,n){let s=e.length>0?`Current template modules (in page order):
756
+ ${e.map((i,a)=>`${a+1}. ${i}`).join(`
757
+ `)}`:"No modules yet (new page).",o=n.length>0?`
758
+
759
+ Module library (reusable from other templates):
760
+ ${n.map(i=>`- ${i.name} (used in: ${i.usedIn.join(", ")})`).join(`
761
+ `)}`:"";return`You are the Intent Analyzer for vibeSpot, a HubSpot CMS page builder.
762
+
763
+ Your job: classify the user's request and plan which modules need work. You do NOT generate module code \u2014 you only plan.
764
+
765
+ ## Theme: "${t}"
766
+
767
+ ${s}${o}
768
+
769
+ ## Classification Rules
770
+
771
+ 1. **create** \u2014 User wants a new page from scratch (e.g., "build me a landing page for...")
772
+ 2. **modify** \u2014 User wants to change existing modules (e.g., "make the hero button red", "update the pricing")
773
+ 3. **add** \u2014 User wants new modules added to the existing page (e.g., "add a testimonials section")
774
+ 4. **remove** \u2014 User wants modules removed (e.g., "remove the footer")
775
+ 5. **rearrange** \u2014 User wants to reorder modules (e.g., "move pricing above features")
776
+ 6. **style_change** \u2014 User wants design system changes that affect shared CSS/multiple modules (e.g., "change the color scheme to blue")
777
+ 7. **question** \u2014 User is asking a question, not requesting changes (e.g., "what modules do I have?"). Provide the answer directly.
778
+
779
+ ## Key Rules
780
+
781
+ - For **modify**: list only the modules that actually need changes in \`affectedModules\`. Everything else goes in \`unchangedModules\`.
782
+ - For **add**: new modules go in \`newModules\` with a descriptive name, brief description, and position index (0-based).
783
+ - For **reuse**: if the user references a module from the library, put it in \`reuseModules\` with the source template name. Reused modules are copied as-is \u2014 their structure (fields, HTML, CSS) MUST NOT change.
784
+ - For **style_change**: set \`designSystemChanges: true\`. All modules become affected since they need the updated design system.
785
+ - For **question**: set \`intent: "question"\` and provide the answer in the \`answer\` field. The pipeline will short-circuit.
786
+ - \`guidesNeeded\` determines which reference guides downstream stages receive. Only include what's actually needed:
787
+ - "design" \u2014 for new pages, layout changes, design system work
788
+ - "content" \u2014 for new pages, content-heavy changes
789
+ - "conversion" \u2014 for any module code generation
790
+ - "hubspot_rules" \u2014 for any module code generation
791
+ - "humanify" \u2014 when generating user-facing copy
792
+
793
+ ## Compound Requests
794
+
795
+ If the user asks for multiple things (e.g., "make hero taller AND add testimonials"), capture ALL parts:
796
+ - Affected existing modules in \`affectedModules\`
797
+ - New modules in \`newModules\`
798
+ - Set the broadest applicable intent (prefer "modify" + newModules over splitting)`}var Bi={type:"object",properties:{intent:{type:"string",enum:["create","modify","add","remove","rearrange","style_change","question"]},affectedModules:{type:"array",items:{type:"string"},description:"Names of existing modules that need changes"},unchangedModules:{type:"array",items:{type:"string"},description:"Names of existing modules that stay as-is"},newModules:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:{type:"string"},position:{type:"number"}},required:["name","description","position"]},description:"New modules to create"},reuseModules:{type:"array",items:{type:"object",properties:{name:{type:"string"},sourceTemplate:{type:"string"},position:{type:"number"}},required:["name","sourceTemplate","position"]},description:"Modules to copy from the library (immutable structure)"},guidesNeeded:{type:"array",items:{type:"string",enum:["design","content","conversion","hubspot_rules","humanify"]}},designSystemChanges:{type:"boolean",description:"True if shared CSS / design system needs regeneration"},answer:{type:"string",description:'For "question" intent only \u2014 the answer to return directly'}},required:["intent","affectedModules","unchangedModules","newModules","guidesNeeded","designSystemChanges"]};async function Ki(t,e,n,s,o,i,a){i({type:"agent_step",step:"analyzing",label:"Analyzing your request..."});let r=e.modules.map(u=>u.moduleName),l=Wi(e.themeName,r,a),c=await it(n,s,o,{systemPrompt:l,messages:[{role:"user",content:t}],structuredOutput:{schema:Bi,name:"pipeline_plan"},maxTokens:2e3});if(c.type!=="structured"){M.warn("intent-analyzer","Did not get structured output, falling back");let u=e.modules.length===0;return{intent:u?"create":"modify",affectedModules:u?[]:r,unchangedModules:[],newModules:[],guidesNeeded:["design","content","conversion","hubspot_rules","humanify"],designSystemChanges:u}}let d=c.data;return d.affectedModules=d.affectedModules||[],d.unchangedModules=d.unchangedModules||[],d.newModules=d.newModules||[],d.guidesNeeded=d.guidesNeeded||[],M.info("intent-analyzer","Plan",{intent:d.intent,affected:d.affectedModules.length,unchanged:d.unchangedModules.length,new:d.newModules.length,reuse:d.reuseModules?.length||0,designSystem:d.designSystemChanges}),i({type:"agent_decision",step:"analyzing",decision:$c(d)}),d}function $c(t){let e=[`Intent: ${t.intent}`];return t.affectedModules.length>0&&e.push(`Modifying: ${t.affectedModules.join(", ")}`),t.unchangedModules.length>0&&e.push(`Unchanged: ${t.unchangedModules.join(", ")}`),t.newModules.length>0&&e.push(`New: ${t.newModules.map(n=>n.name).join(", ")}`),t.reuseModules?.length&&e.push(`Reuse: ${t.reuseModules.map(n=>`${n.name} from ${n.sourceTemplate}`).join(", ")}`),t.designSystemChanges&&e.push("Design system changes: yes"),e.join(" | ")}f();f();function Vi(t,e){let n=[];return n.push(`You are the Design System Architect for vibeSpot, a HubSpot CMS page builder.
799
+
800
+ Your job: create a complete, production-ready CSS design system for a landing page theme. You produce the :root custom properties, shared utility/component CSS, and optional shared JS (scroll animations). Downstream agents will use YOUR CSS classes and variables to build individual modules.
801
+
802
+ ## Theme: "${t}"
803
+
804
+ ## Output Requirements
805
+
806
+ ### cssVariables
807
+ A flat object mapping CSS custom property names to values. Every variable your CSS references MUST be defined here. Include ALL of these categories:
808
+
809
+ **Colors** (at minimum):
810
+ - --${t}-color-bg: page background
811
+ - --${t}-color-surface: card/section background
812
+ - --${t}-color-dark: dark section background
813
+ - --${t}-color-dark-surface: card bg inside dark sections
814
+ - --${t}-color-text: primary text color
815
+ - --${t}-color-text-inverse: text on dark backgrounds
816
+ - --${t}-color-text-muted: secondary/muted text
817
+ - --${t}-color-primary: primary brand color
818
+ - --${t}-color-primary-dark: darker variant for hover states
819
+ - --${t}-color-accent: accent/highlight color
820
+ - --${t}-color-accent-light: light tint for pill/badge backgrounds
821
+ - --${t}-color-border: default border color
822
+ - --${t}-color-border-hover: border on hover
823
+
824
+ **Typography**:
825
+ - --${t}-font-display: display/heading font stack (system fonts only)
826
+ - --${t}-font-body: body text font stack (system fonts only)
827
+ - --${t}-size-h1 through --${t}-size-h3: heading sizes using clamp()
828
+ - --${t}-size-body, --${t}-size-lg, --${t}-size-small, --${t}-size-label
829
+ - --${t}-leading-tight, --${t}-leading-snug, --${t}-leading-body: line heights
830
+ - --${t}-tracking-tight, --${t}-tracking-wide: letter spacing
831
+
832
+ **Spacing**:
833
+ - --${t}-space-xs through --${t}-space-xl, --${t}-space-section
834
+ - --${t}-max-width: content max-width (1152-1280px)
835
+
836
+ **Effects**:
837
+ - --${t}-radius-sm, --${t}-radius-md, --${t}-radius-lg, --${t}-radius-full
838
+ - --${t}-shadow-card-hover, --${t}-shadow-button
839
+ - --${t}-transition-fast, --${t}-transition-base, --${t}-transition-slow
840
+
841
+ ### sharedCss
842
+ Complete CSS file content. MUST include:
843
+ 1. A \`:root {}\` block with ALL variables from cssVariables
844
+ 2. Reset (box-sizing, margin, padding)
845
+ 3. Body styles referencing your variables
846
+ 4. Typography rules (h1-h6, p)
847
+ 5. Layout utilities (.${t}-container, .${t}-section, .${t}-section--dark)
848
+ 6. Grid system (.${t}-grid, .${t}-grid--2/3/4 with responsive breakpoints)
849
+ 7. Card component (.${t}-card with hover lift)
850
+ 8. Button component (.${t}-btn, .${t}-btn--primary, .${t}-btn--secondary)
851
+ CRITICAL: Re-declare color, text-decoration:none, and font-family on :hover/:focus \u2014 HubSpot overrides link hover styles
852
+ 9. Pill/badge (.${t}-pill)
853
+ 10. Decorative elements (at least one background treatment: grid pattern, noise, gradient orb)
854
+ 11. Scroll animation CSS ([data-animate], [data-animate-stagger]) with 3s CSS-only fallback
855
+ 12. Section label (.${t}-label) \u2014 uppercase, letter-spacing, accent color
856
+ 13. Stat number styling
857
+ 14. Responsive mobile styles (@media max-width: 767px)
858
+
859
+ ### sharedJs (optional)
860
+ IntersectionObserver-based scroll animation JS. Wrap in IIFE.
861
+
862
+ ## CSS Rules \u2014 CRITICAL
863
+ - All classes MUST use prefix "${t}-"
864
+ - Use BEM naming: ${t}-module__element--modifier
865
+ - Use system font stacks ONLY (no Google Fonts @import, no external CDN)
866
+ - Every var() reference in CSS must have a matching declaration in :root
867
+ - No Tailwind, no Sass, no PostCSS
868
+ - Use clamp() for fluid typography sizing
869
+
870
+ ## Font Strategy
871
+ Use system font stacks that approximate the desired aesthetic. Pick TWO stacks:
872
+ - Display: for headings (e.g., Georgia, "Times New Roman", serif for editorial)
873
+ - Body: for text (e.g., system-ui, -apple-system, "Segoe UI", sans-serif)
874
+
875
+ Good system font stacks by style:
876
+ | Style | Display Stack | Body Stack |
877
+ |-------|--------------|------------|
878
+ | Editorial | Georgia, Cambria, "Times New Roman", serif | system-ui, -apple-system, "Segoe UI", sans-serif |
879
+ | Modern | system-ui, -apple-system, sans-serif | "Segoe UI", Roboto, sans-serif |
880
+ | Warm | Optima, Candara, "Noto Sans", sans-serif | "Trebuchet MS", system-ui, sans-serif |
881
+ | Monospace/Tech | "SF Mono", "Cascadia Code", "Fira Code", monospace | system-ui, sans-serif |
882
+ | Geometric | Futura, "Century Gothic", "Trebuchet MS", sans-serif | system-ui, sans-serif |`),n.push(`
883
+
884
+ ## Design Guide
885
+ ${Tc()}`),e?.styleguide&&n.push(`
886
+
887
+ ## Brand Style Guide
888
+ ${e.styleguide}`),n.join("")}var Yi={type:"object",properties:{cssVariables:{type:"object",description:"CSS custom property name \u2192 value map. Every var() used in sharedCss must be defined here."},sharedCss:{type:"string",description:"Complete shared CSS file. MUST start with :root {} block defining all cssVariables, followed by reset, typography, layout, components, animations, and responsive styles."},sharedJs:{type:"string",description:"Optional shared JS for scroll animations (IntersectionObserver). Wrap in IIFE. Empty string if not needed."},aesthetic:{type:"string",description:"Brief description of the chosen aesthetic direction (e.g., 'dark luxury with warm gold accents')"}},required:["cssVariables","sharedCss","aesthetic"]};function zi(t,e,n,s){let o=[];return o.push(`You are the Module Planner for vibeSpot, a HubSpot CMS page builder.
889
+
890
+ Your job: plan the modules for a landing page. You define what each module contains (content brief) and how it should be laid out. You do NOT write module code \u2014 downstream Module Developers handle that.
891
+
892
+ The Design System has already been created. Your module plans MUST reference the existing CSS classes and variables.
893
+
894
+ ## Theme: "${t}"
895
+
896
+ ## Available CSS Classes
897
+ The following shared CSS classes are available for modules to use. Reference these in your layoutNotes:
898
+
899
+ \`\`\`css
900
+ ${e}
901
+ \`\`\`
902
+
903
+ ## Output Rules
904
+ - Module names: descriptive, title-case (e.g., "Hero Banner", "Pricing Cards")
905
+ - Content briefs: describe the actual copy/content each module needs (headlines, body text, CTAs, stats)
906
+ - Layout notes: describe the visual layout using the available CSS classes above
907
+ - Reference specific CSS classes from the shared CSS in your layout notes (e.g., "Use ${t}-grid--3 for card layout, ${t}-section--dark for background")
908
+ - moduleOrder: list module names in the order they should appear on the page`),(!s||s.includes("content"))&&o.push(`
909
+
910
+ ## Content & Copywriting Guide
911
+ ${Ec()}`),n?.brandvoice&&o.push(`
912
+
913
+ ## Brand Voice
914
+ ${n.brandvoice}`),n?.humanify!==!1&&s?.includes("humanify")&&o.push(`
915
+
916
+ ## Anti-AI Copy Rules
917
+ ${Mc()}`),o.join("")}var qi={type:"object",properties:{modules:{type:"array",items:{type:"object",properties:{name:{type:"string",description:"Module name in title-case"},description:{type:"string",description:"What this module does"},contentBrief:{type:"string",description:"Specific content: headlines, body copy, stats, CTAs"},layoutNotes:{type:"string",description:"Visual layout approach referencing shared CSS classes"}},required:["name","description","contentBrief","layoutNotes"]}},moduleOrder:{type:"array",items:{type:"string"},description:"Module names in page display order"},narrative:{type:"string",description:"Brief description of the page story/flow"}},required:["modules","moduleOrder","narrative"]};function Tc(){return`### Design Philosophy
918
+ You are a senior UI designer. Every page must look professionally designed, not like AI output.
919
+ Avoid "AI slop": purple gradients on white, cookie-cutter card grids, no personality.
920
+
921
+ Before designing, decide on:
922
+ - **Aesthetic direction**: minimal editorial? bold brutalist? warm organic? luxury dark-mode? Pick one and commit.
923
+ - **One memorable element**: unusual layout, clever animation, striking color, unexpected typography.
924
+ - **Audience**: the audience shapes the vibe. A SaaS dashboard \u2260 a restaurant landing page.
925
+
926
+ When a user gives a simple prompt like "build me a landing page for a coffee shop," internally expand it:
927
+ - Pick an aesthetic (warm, editorial, slightly vintage)
928
+ - Pick specific colors (cream bg #faf7f2, espresso #3c1e0e, gold accent #c4956a)
929
+ - Decide hero style (full-bleed image background, overlaid text)
930
+ - Choose layout approach (asymmetric sections, large visual areas)
931
+ - Add texture (subtle paper/grain noise overlay)
932
+ - Set animations (scroll-triggered reveals)
933
+ The user gives the "what," you decide the "how it should look and feel."
934
+
935
+ ### Typography Scale
936
+ Include these in the CSS custom properties:
937
+ \`\`\`
938
+ h1: clamp(2.5rem, 5vw, 4.5rem) /* Hero headlines \u2014 BIG */
939
+ h2: clamp(1.75rem, 3vw, 3rem) /* Section headings */
940
+ h3: clamp(1.25rem, 2vw, 1.75rem) /* Card titles, subheadings */
941
+ body: 1rem - 1.125rem /* 16-18px body text */
942
+ small: 0.875rem /* Captions, labels */
943
+ line-height: 1.1-1.2 for headings, 1.5-1.7 for body
944
+ letter-spacing: -0.02em to -0.04em for large headings (tighter = more premium)
945
+ \`\`\`
946
+
947
+ ### Color Palettes
948
+ Pick a dominant (70%), secondary (25%), accent (5%). Ensure WCAG AA contrast (4.5:1 body, 3:1 large text).
949
+
950
+ \`\`\`
951
+ DARK LUXURY: --bg: #0a0a0a; --surface: #141414; --text: #e8e8e8; --primary: #c9a84c; --accent: #e8d5a3
952
+ WARM EARTH: --bg: #faf7f2; --surface: #f0ebe3; --text: #2d2418; --primary: #8b5e3c; --accent: #c4956a
953
+ COOL MINIMAL: --bg: #fafafa; --surface: #f1f1f1; --text: #1a1a1a; --primary: #0055ff; --accent: #00c4ff
954
+ FOREST: --bg: #0f1a0f; --surface: #1a2e1a; --text: #d4e8d0; --primary: #4ade80; --accent: #22c55e
955
+ EDITORIAL CREAM:--bg: #fffdf5; --surface: #f5f0e8; --text: #1c1917; --primary: #dc2626; --accent: #f97316
956
+ NOIR: --bg: #000000; --surface: #111111; --text: #ffffff; --primary: #ffffff; --accent: #666666
957
+ \`\`\`
958
+
959
+ ### Layout Patterns
960
+ 1. **Split hero**: Content left, visual right (50/50 or 60/40)
961
+ 2. **Full-bleed hero**: Edge-to-edge background with centered content overlay
962
+ 3. **Bento grid**: Asymmetric grid with mixed card sizes (span-2, span-1)
963
+ 4. **Staggered/offset**: Content blocks not perfectly aligned, adds dynamism
964
+ 5. **Overlapping elements**: Cards/images that break grid lines, overlap sections
965
+ 6. **Scroll-based reveal**: Content appears as you scroll
966
+
967
+ ### Background Treatments (pick 1-2 per page)
968
+ Include these in shared CSS:
969
+ - **Subtle grid pattern**: linear-gradient with thin lines at 60px intervals
970
+ - **Noise texture overlay**: SVG feTurbulence filter at 0.03 opacity, fixed position
971
+ - **Gradient orb/blob**: 600px radial-gradient circle, blurred 80px, absolute positioned
972
+ - **Radial gradient on sections**: radial-gradient(ellipse at top, rgba(primary, 0.05), transparent 70%)
973
+ - **Background alternation**: alternate section backgrounds every 2-3 sections to create visual "chapters"
974
+
975
+ ### Micro-Interactions (include in shared CSS)
976
+ - **Card hover**: translateY(-4px) + box-shadow 20px 40px rgba(0,0,0,0.1), transition 0.3s ease
977
+ - **Button hover**: translateY(-1px) + box-shadow 4px 12px rgba(primary, 0.3), transition 0.2s
978
+ - **Link underline**: pseudo-element width 0 \u2192 100% on hover, transition 0.3s
979
+ - **Scroll animations**: data-animate elements start opacity:0 translateY(20px), animate to visible via IntersectionObserver. Include CSS fallback: elements become visible after 3s even if JS fails.
980
+ - **Stagger children**: transition-delay: calc(var(--index) * 100ms)
981
+
982
+ ### Component Requirements
983
+ - **Hero**: Visually dominant headline (largest on page), subheading with lower contrast, clear CTA with hover, visual interest (gradient/image/pattern/animation), min 80vh. Every hero needs a "wow."
984
+ - **Navigation**: Sticky with backdrop-blur-md bg-white/80, logo left, CTA right, active state indicator, smooth transition on scroll (shrink, shadow, bg change)
985
+ - **Cards**: Subtle border OR shadow (not both heavy), rounded-xl to rounded-2xl, consistent padding, hover lift. Optional: subtle gradient border with pseudo-element
986
+ - **Buttons**: Primary filled + secondary outlined/ghost, generous padding (px-6 py-3 min). CRITICAL: Re-declare color, text-decoration:none, and font-family on :hover/:focus/:active \u2014 HubSpot overrides link hover styles
987
+ - **Footer**: Darker than page, multi-column (3-4 cols), stacked on mobile, subtle separator from main content
988
+
989
+ ### Spacing
990
+ - Section padding: 80-128px vertical
991
+ - Content max-width: 1152-1280px centered
992
+ - Card padding: 24-32px, gap: 24-32px
993
+ - Between heading and body: 16-24px
994
+ - Generous whitespace = premium. Cramped = amateur.
995
+ - Mobile: always responsive, use clamp() for fluid sizing
996
+
997
+ ### Quality Checklist
998
+ - [ ] Color palette has personality (not generic blue/purple on white)
999
+ - [ ] Typography scale is consistent (headings use clamp(), body 16-18px)
1000
+ - [ ] Spacing is generous (sections have 80px+ padding)
1001
+ - [ ] At least one "wow" element (animation, unusual layout, bold color)
1002
+ - [ ] Backgrounds aren't flat (subtle pattern, gradient, or texture)
1003
+ - [ ] Hover states exist (cards lift, buttons shift, links animate)
1004
+ - [ ] Scroll animations present with CSS fallback
1005
+ - [ ] Mobile responsive (works at 375px)
1006
+ - [ ] Contrast ratios pass WCAG AA
1007
+ - [ ] Page feels cohesive (one aesthetic direction, not a Frankenstein)
1008
+
1009
+ ### Anti-Patterns
1010
+
1011
+ | Don't | Do Instead |
1012
+ |-------|-----------|
1013
+ | Purple gradient on white | Choose a palette with personality |
1014
+ | Symmetric 3-col grids for everything | Mix layouts: bento, split, offset, overlapping |
1015
+ | Flat white/gray backgrounds | Add subtle texture, gradient, or pattern |
1016
+ | Tiny padding between sections | Use 80-128px for breathing room |
1017
+ | All animations same speed | Stagger with increasing delays |
1018
+ | Skip hover/focus states | Every interactive element needs feedback |
1019
+ | Use \`<br>\` tags for spacing | Use proper margin/padding |
1020
+ | Put everything in a shadowed card | Vary: full-bleed, contained, floating |`}function Ec(){return`### Mandatory Page Sections (generate all)
1021
+ 1. **Navigation Bar** \u2014 Logo, 4-5 nav links, CTA button, sticky on scroll
1022
+ 2. **Hero** \u2014 Badge/pill, primary headline, subheadline, primary + secondary CTA, trust signals, visual element
1023
+ 3. **Social Proof Bar** \u2014 Logo strip of 4-6 clients OR stats bar (compact, py-8)
1024
+ 4. **Features/Services** \u2014 Section label + headline, 3-6 cards with icon/title/description/metric
1025
+ 5. **How It Works** \u2014 3-4 numbered steps with titles, descriptions, visuals, connected flow
1026
+ 6. **Testimonials** \u2014 At least 3 with full quotes, names, roles, ratings
1027
+ 7. **Pricing/Value** \u2014 Pricing tiers or key metrics in large text with context + CTA
1028
+ 8. **FAQ** \u2014 4-6 real questions with specific, helpful answers
1029
+ 9. **Final CTA** \u2014 Strong headline, subtext, primary + secondary buttons, visually distinct
1030
+ 10. **Footer** \u2014 Brand name, 3-4 link columns with 3-5 links each, contact info, social icons, copyright
1031
+
1032
+ ### Optional Sections (include 1-2 when they fit)
1033
+ - Comparison table ("Us vs. Them")
1034
+ - Case study highlight
1035
+ - Team/About strip
1036
+ - Blog/Resource teasers
1037
+ - Partners/Integrations logo grid
1038
+
1039
+ ### Headline Rules \u2014 The "Bar Test"
1040
+ Every headline should pass this test: if you shouted it across a bar, would someone turn their head?
1041
+
1042
+ | Don't | Do Instead |
1043
+ |-------|-----------|
1044
+ | "Our Services" | "What We Actually Do" |
1045
+ | "How It Works" | "Unclogged in 3 Steps" |
1046
+ | "Pricing" | "Cheaper Than Your Uber Eats Habit" |
1047
+ | "Testimonials" | "Don't Take Our Word For It" |
1048
+ | "Get Started" | "Blocked Drain? Text Us a Photo." |
1049
+ | "Features" | "Everything You Get, Nothing You Don't" |
1050
+
1051
+ ### CTA Button Copy
1052
+ Never use "Submit" or "Learn More." Tie CTAs to specific outcomes:
1053
+ "Book Now \u2014 From \u20AC49 \u2192" \xB7 "Start Free Trial \xB7 No Card Required" \xB7 "Get My Custom Quote in 10 Min" \xB7 "Join 2,000+ Happy Customers"
1054
+
1055
+ ### Minimum Content Quantities
1056
+
1057
+ | Element | Min | Why |
1058
+ |---------|-----|-----|
1059
+ | Testimonials | 3 | One looks fake, two looks thin |
1060
+ | Feature cards | 4 | Three is a wireframe |
1061
+ | FAQ items | 4 | Fewer looks like hiding something |
1062
+ | Process steps | 3 | Natural narrative arc |
1063
+ | Stats/metrics | 3 | Singles look accidental |
1064
+ | Footer columns | 3 | Fewer = side project |
1065
+ | Nav links | 4-5 | Establishes depth |
1066
+ | CTA repetitions | 3 | Hero, mid-page, closing |
1067
+
1068
+ ### Business Type Content Templates
1069
+
1070
+ **Local Service** (plumber, electrician, cleaner): Hero = pain point + speed promise. Must-have: service area, response time, pricing. CTAs: phone, WhatsApp, booking. Stats: response time, jobs done, satisfaction.
1071
+
1072
+ **SaaS/Tech Product**: Hero = outcome-first ("Save 10hrs/week"). Must-have: feature grid, integration logos, product visual. CTAs: free trial, demo. Stats: performance, customer count, uptime.
1073
+
1074
+ **Restaurant/Food**: Hero = sensory/emotional ("Farm-to-table since 2019"). Must-have: menu highlights with prices, hours, location. CTAs: reserve, order, menu. Stats: years open, dishes served.
1075
+
1076
+ **E-commerce/DTC**: Hero = benefit + social proof ("Join 50K+ happy sleepers"). Must-have: features, comparison, guarantee. CTAs: shop, add to cart, "Try risk-free." Stats: units sold, return rate.
1077
+
1078
+ **Agency/Consultancy**: Hero = expertise + outcome ("Scaled 40+ brands past \u20AC1M"). Must-have: services, case studies, process. CTAs: book call, see cases, get proposal. Stats: clients, revenue, years.
1079
+
1080
+ ### Content Density \u2014 Never Leave Empty Space
1081
+ At every viewport-height (100vh), the user should see:
1082
+ - At least one piece of **specific data** (number, price, time, rating)
1083
+ - At least one piece of **social proof** (quote, logo, rating, customer count)
1084
+ - At least one **visual element** (icon, illustration, decorative shape, gradient block)
1085
+ - A clear sense of **what section they're in** (label + headline visible)
1086
+
1087
+ Every card must contain ALL of: icon/visual, title (3-6 words), description (2-3 sentences with specific detail), optional link/metric. Never generate a card that is just a title and one sentence.
1088
+
1089
+ ### Content Rhythm & Visual Pacing
1090
+ Alternate section density \u2014 don't make every section the same weight:
1091
+ - HERO: Full, rich, attention-grabbing (100vh)
1092
+ - TRUST BAR: Compact (py-8 to py-12)
1093
+ - FEATURES: Dense, multi-card grid (tall section)
1094
+ - HOW IT WORKS: Medium, 3-4 steps with breathing room
1095
+ - TESTIMONIALS: Dense, 3+ cards
1096
+ - PRICING: Medium, 2-3 focused cards
1097
+ - FAQ: Compact (accordion saves space)
1098
+ - FINAL CTA: Full width, bold, short (50vh max)
1099
+ - FOOTER: Dense with links, compact
1100
+
1101
+ Alternate backgrounds every 2-3 sections to create visual "chapters." Sprinkle trust signals throughout (not just one section).
1102
+
1103
+ ### Body Copy Rules
1104
+ - Never write generic filler. Every sentence needs a SPECIFIC detail.
1105
+ - Invent plausible specifics: neighborhood names, "48 hours" not "quickly", "\u20AC49" not "affordable"
1106
+ - Keep paragraphs to 2-3 sentences max
1107
+ - Aim for 6th-grade reading level
1108
+ - Include section labels (UPPERCASE, letter-spacing 0.1em, accent color, 2-3 words) above every headline`}function Mc(){return`### Banned Punctuation
1109
+ - **Em dashes (\u2014)**: NEVER use. Biggest AI tell. Replace with periods, commas, or parentheses.
1110
+ - **Semicolons**: Feel academic, not conversational. Use periods instead.
1111
+ - **Exclamation marks**: One per page maximum. Zero is ideal for B2B.
1112
+
1113
+ ### Banned Words
1114
+ **HARD BANNED (always rewrite):**
1115
+ delve, tapestry, multifaceted, utilize, harness, bolster, underscore, illuminate, facilitate, fostering, garner, pivotal, commence, endeavor, myriad, plethora, pertinent, aforementioned, wherein, henceforth, beacon, synergy, paradigm, bespoke, holistic, spearhead, embark, reimagine, cultivate, cornerstone
1116
+
1117
+ **SOFT BANNED (rewrite unless truly specific):**
1118
+ seamless, cutting-edge, groundbreaking, game-changer, revolutionary, transformative, innovative, robust, comprehensive, foundational, nuanced, landscape (abstract), realm, catalyst, empower, elevate, unlock, streamline, optimize, curated, navigate (abstract)
1119
+
1120
+ ### Banned Openers
1121
+ "In today's", "In an era", "In the realm", "Whether you're", "Are you tired", "Imagine a world", "Picture this", "Here's the thing", "Let's face it", "Look no further", "Say goodbye to", "Gone are the days", "It's no secret", "At its core", "At the end of the day", "When it comes to"
1122
+
1123
+ ### Banned Closers
1124
+ "The future of [X] is here", "Your journey starts here", "Join the revolution", "Experience the difference", "See what's possible", "Ready to take the next step"
1125
+
1126
+ ### Banned Structures
1127
+ - "It's not about X, it's about Y" (second biggest AI tell after em dashes)
1128
+ - "It's not just X, it's Y"
1129
+ - "[X]. Here's why." / "[X]. And it matters."
1130
+ - "Despite the challenges"
1131
+ - Tricolon abuse ("Fast, reliable, revolutionary") \u2014 once per page max
1132
+
1133
+ ### Positive Rules
1134
+ - Be concrete, not abstract: "42 minutes" not "fast", "\u20AC29/month" not "affordable"
1135
+ - Use plain short words: use > utilize, start > commence, help > facilitate
1136
+ - Vary sentence length aggressively: mix 3-word, 12-word, and 25-word sentences
1137
+ - Front-load the benefit in the first 5 words
1138
+ - Write like you'd explain it in a bar \u2014 if you wouldn't say it holding a beer, rewrite it`}async function Xi(t,e,n,s,o,i,a){a({type:"agent_step",step:"designing",label:"Creating design system..."});let r=Vi(n.themeName,n.brandAssets),l=`## User Request
1139
+ ${t}`;n.modules.length>0&&e.designSystemChanges&&(l+=`
1140
+
1141
+ ## Current Shared CSS (update this)
1142
+ \`\`\`css
1143
+ ${n.sharedCss}
1144
+ \`\`\``);let c=await it(s,o,i,{systemPrompt:r,messages:[{role:"user",content:l}],structuredOutput:{schema:Yi,name:"design_system"},maxTokens:16e3}),d;c.type!=="structured"?(M.warn("page-architect","Design system: did not get structured output, using fallback"),d={cssVariables:{},sharedCss:n.sharedCss||"",sharedJs:n.sharedJs||"",aesthetic:"default"}):(d=c.data,M.info("page-architect","Design system created",{aesthetic:d.aesthetic,varCount:Object.keys(d.cssVariables||{}).length,cssLength:d.sharedCss?.length||0}));let u=d.sharedCss||"",p=d.cssVariables;p&&typeof p=="object"&&Object.keys(p).length>0&&(u.includes(":root")||(u=`:root {
1145
+ ${Object.entries(p).map(([I,T])=>` ${I.startsWith("--")?I:`--${I}`}: ${T};`).join(`
1146
+ `)}
1147
+ }
1148
+
1149
+ ${u}`)),a({type:"agent_decision",step:"designing",decision:`Design system: ${d.aesthetic||"created"} | ${Object.keys(p||{}).length} variables, ${u.length} chars CSS`}),a({type:"design_system_ready",sharedCss:u,sharedJs:d.sharedJs||"",aesthetic:d.aesthetic||""}),a({type:"agent_step",step:"designing",label:"Planning modules..."});let g=zi(n.themeName,u,n.brandAssets,e.guidesNeeded),h=`## User Request
1150
+ ${t}`;e.newModules.length>0&&(h+=`
1151
+
1152
+ ## Planned Modules
1153
+ ${e.newModules.map((w,I)=>`${I+1}. **${w.name}** \u2014 ${w.description}`).join(`
1154
+ `)}`),n.modules.length>0&&!e.designSystemChanges&&(h+=`
1155
+
1156
+ ## Existing Modules (keeping)
1157
+ ${n.modules.map(w=>`- ${w.moduleName}`).join(`
1158
+ `)}`);let b=await it(s,o,i,{systemPrompt:g,messages:[{role:"user",content:h}],structuredOutput:{schema:qi,name:"module_plan"},maxTokens:8e3}),y;return b.type!=="structured"?(M.warn("page-architect","Module planner: did not get structured output, using fallback"),y={modules:e.newModules.map(w=>({name:w.name,description:w.description,contentBrief:"Generate appropriate content",layoutNotes:"Use responsive layout"})),moduleOrder:e.newModules.map(w=>w.name),narrative:"Page generated from user request"}):(y=b.data,M.info("page-architect","Module plan",{moduleCount:y.modules.length})),a({type:"agent_decision",step:"designing",decision:`Page: ${y.narrative} | ${y.modules.length} modules planned`}),{designSystem:{cssVariables:d.cssVariables||{},sharedCss:u,sharedJs:d.sharedJs},modules:y.modules,moduleOrder:y.moduleOrder,narrative:y.narrative}}f();f();function Qi(t){let e=0,n=[];return async function(o){e>=t&&await new Promise(i=>n.push(i)),e++;try{return await o()}finally{e--,n.length>0&&n.shift()()}}}f();function Zi(t,e,n,s){let o=[];return o.push(`You are a Module Developer for vibeSpot, a HubSpot CMS page builder.
1159
+
1160
+ Your job: generate ONE HubSpot CMS module. You receive a module specification and must produce the complete module code.
1161
+
1162
+ ## Theme: "${t}"
1163
+
1164
+ ## Output Rules \u2014 CRITICAL
1165
+ You produce a single module with these fields:
1166
+ - **moduleName**: Exact module name (title-case, e.g., "Hero Banner")
1167
+ - **fieldsJson**: Valid JSON string \u2014 the module's fields.json content
1168
+ - **metaJson**: Valid JSON string \u2014 must include host_template_types: ["PAGE"], is_available_for_new_content: true
1169
+ - **moduleHtml**: HubL template ({{ module.field_name }} syntax)
1170
+ - **moduleCss**: Vanilla CSS (no Tailwind, no Sass, no CDN imports)
1171
+ - **moduleJs**: Optional vanilla JS wrapped in IIFE, or null
1172
+
1173
+ ## CSS Rules
1174
+ - All CSS classes must use prefix "${t}-"
1175
+ - Use BEM naming: ${t}-moduleName__element--modifier
1176
+ - Reference the theme's CSS custom properties (shown below)
1177
+ - No CDN imports (@import url(), external <link> tags)
1178
+ - Use system font stacks \u2014 no Google Fonts
1179
+
1180
+ ## Field Rules
1181
+ - Use "type": "text" (NEVER "textarea" \u2014 it's deprecated)
1182
+ - NEVER use "name": "name" (reserved) \u2014 use "item_name" instead
1183
+ - NEVER use "name": "label" (reserved) \u2014 use "section_label" instead
1184
+ - NEVER put literal \\n in field defaults
1185
+ - Wrap style fields in a "styles" group with "tab": "STYLE"
1186
+ - Color fields: type "color", default { "color": "#hex", "opacity": 100 }
1187
+ - Link fields: type "link", default { "url": { "href": "#", "type": "EXTERNAL" }, "open_in_new_tab": false, "no_follow": false }
1188
+ - Image fields: type "image", default { "src": "https://placehold.co/800x600/1a1a2e/ffffff?text=Replace+in+HubSpot", "alt": "Placeholder", "width": 800, "height": 600 }
1189
+ - For repeater groups, use "occurrence": { "min": 0, "max": 100 }
1190
+
1191
+ ## Images & Assets
1192
+ - Use get_asset_url("${t}/assets/filename.ext") for uploaded assets
1193
+ - For placeholder images, use image fields with placehold.co defaults
1194
+ - Size placeholders appropriately (hero: 1920x800, cards: 600x400, icons: 200x200)
1195
+
1196
+ ## Navigation & Anchors
1197
+ - Add id attribute on module root element: id="module-name-lowercased"
1198
+ - For nav modules, use anchor links (#features, #pricing, etc.)
1199
+ - Include smooth scroll behavior in nav click handlers
1200
+
1201
+ ## metaJson Template
1202
+ { "host_template_types": ["PAGE"], "is_available_for_new_content": true }`),e&&o.push(`
1203
+
1204
+ ## Theme Shared CSS (use these custom properties)
1205
+ \`\`\`css
1206
+ ${e}
1207
+ \`\`\``),(!n||n.includes("hubspot_rules"))&&o.push(`
1208
+
1209
+ ## HubSpot CMS Rules
1210
+ ${Ve()}`),(!n||n.includes("conversion"))&&o.push(`
1211
+
1212
+ ## Conversion Guide
1213
+ ${re()}`),s?.humanify!==!1&&n?.includes("humanify")&&o.push(`
1214
+
1215
+ ## Anti-AI Copy Rules
1216
+ ${Nc()}`),o.join("")}function Nc(){return`### Banned Punctuation
1217
+ - **Em dashes (\u2014)**: NEVER use. Replace with periods, commas, or parentheses. Hyphens for compounds fine.
1218
+ - **Semicolons**: Use periods instead in marketing copy.
1219
+ - **Exclamation marks**: One per page max. Zero ideal for B2B.
1220
+
1221
+ ### Banned Words
1222
+ **HARD BANNED:**
1223
+ delve, tapestry, multifaceted, utilize, harness, bolster, underscore, illuminate, facilitate, fostering, garner, pivotal, commence, endeavor, myriad, plethora, pertinent, aforementioned, wherein, henceforth, beacon, synergy, paradigm, bespoke, holistic, spearhead, embark, reimagine, cultivate, cornerstone
1224
+
1225
+ **SOFT BANNED (rewrite unless truly earned):**
1226
+ seamless, cutting-edge, groundbreaking, game-changer, revolutionary, transformative, innovative, robust, comprehensive, foundational, nuanced, landscape (abstract), realm, catalyst, empower, elevate, unlock, streamline, optimize, curated, navigate (abstract)
1227
+
1228
+ ### Banned Openers
1229
+ Never start a heading or paragraph with: "In today's", "In an era", "In the realm", "Whether you're", "Are you tired", "Imagine a world", "Picture this", "Here's the thing", "Let's face it", "Look no further", "Say goodbye to", "Gone are the days", "It's no secret", "At its core", "At the end of the day", "When it comes to"
1230
+
1231
+ ### Banned Closers
1232
+ Never end with: "The future of [X] is here", "Your journey starts here", "Join the revolution", "Experience the difference", "See what's possible", "Ready to take the next step"
1233
+
1234
+ ### Banned Structures
1235
+ - "It's not about X, it's about Y" \u2014 just state Y
1236
+ - "It's not just X, it's Y" \u2014 just state Y
1237
+ - "[X]. Here's why." / "[X]. And it matters."
1238
+ - "Despite the challenges"
1239
+ - Tricolon abuse ("Fast, reliable, revolutionary") \u2014 max once per page
1240
+
1241
+ ### Positive Writing Rules
1242
+ - Be concrete: "42 minutes" not "fast", "\u20AC29/month" not "affordable", "2,847 teams" not "thousands"
1243
+ - Use plain words: use > utilize, start > commence, help > facilitate, enough > sufficient
1244
+ - Vary sentence length: mix 3-word, 12-word, and 25-word sentences
1245
+ - Front-load the benefit in the first 5 words
1246
+ - Write like you'd say it in a bar. If you wouldn't say it holding a beer, rewrite it.
1247
+ - One adjective per noun max. Zero is often better.
1248
+
1249
+ ### Testimonial Rules
1250
+ - Include a specific problem that was solved
1251
+ - Include a concrete detail (time saved, money saved, specific task)
1252
+ - Keep slightly imperfect (fragments OK, mild hedging like "honestly didn't think")
1253
+ - Full names, specific roles (not "John D., CEO")
1254
+ - Never start with "This product is..." \u2014 start with the person's situation
1255
+ - Vary length and voice across testimonials`}function er(t,e,n){let s=[];return s.push(`## User Request
1256
+ ${t}`),s.push(`
1257
+
1258
+ ## Module Specification
1259
+ - **Name**: ${e.name}
1260
+ - **Description**: ${e.description}
1261
+ - **Content Brief**: ${e.contentBrief}
1262
+ - **Layout Notes**: ${e.layoutNotes}`),n&&(s.push(`
1263
+
1264
+ ## Existing Module Code (modify this)
1265
+ **fields.json:**
1266
+ \`\`\`json
1267
+ ${n.fieldsJson}
1268
+ \`\`\`
1269
+
1270
+ **module.html:**
1271
+ \`\`\`html
1272
+ ${n.moduleHtml}
1273
+ \`\`\`
1274
+
1275
+ **module.css:**
1276
+ \`\`\`css
1277
+ ${n.moduleCss}
1278
+ \`\`\``),n.moduleJs&&s.push(`
1279
+ **module.js:**
1280
+ \`\`\`js
1281
+ ${n.moduleJs}
1282
+ \`\`\``)),s.join("")}var tr={type:"object",properties:{moduleName:{type:"string"},fieldsJson:{type:"string",description:"Complete fields.json content as a JSON string"},metaJson:{type:"string",description:"Complete meta.json content as a JSON string"},moduleHtml:{type:"string",description:"Complete module.html HubL template content"},moduleCss:{type:"string",description:"Complete module.css vanilla CSS content"},moduleJs:{type:"string",description:"Optional module.js vanilla JS content, or empty string if not needed"}},required:["moduleName","fieldsJson","metaJson","moduleHtml","moduleCss"]};async function nr(t,e,n,s,o,i,a,r,l,c,d){l({type:"agent_step",step:"developing",label:`Generating ${e.length} module${e.length===1?"":"s"}...`});let u=Zi(s,n,c,d),p=Qi(r),g=e.length,h=e.map((y,w)=>p(async()=>{l({type:"module_progress",module:y.name,status:"generating",current:w+1,total:g});let I="";for(let T=0;T<2;T++)try{T>0&&(M.warn("module-developer",`${y.name}: retrying after failure (attempt ${T+1})`),l({type:"module_progress",module:y.name,status:"retrying",current:w+1,total:g}));let J=await sr(t,y,u,o,i,a);return l({type:"module_progress",module:y.name,status:"complete",current:w+1,total:g,moduleFiles:J}),{moduleName:y.name,module:J}}catch(J){I=J instanceof Error?J.message:typeof J=="object"&&J!==null?JSON.stringify(J):String(J),M.error("module-developer",`Failed: ${y.name} (attempt ${T+1})`,{error:I})}return l({type:"module_progress",module:y.name,status:"failed",current:w+1,total:g}),{moduleName:y.name,error:I}}));return(await Promise.allSettled(h)).map(y=>y.status==="fulfilled"?y.value:{moduleName:"unknown",error:y.reason instanceof Error?y.reason.message:String(y.reason)})}async function sr(t,e,n,s,o,i,a=0){let r=er(t,e,e.existingCode),l=await it(s,o,i,{systemPrompt:n,messages:[{role:"user",content:r}],structuredOutput:{schema:tr,name:"module_output"},maxTokens:16e3});if(l.type!=="structured"){if(a<2)return M.warn("module-developer",`${e.name}: no structured output, retry ${a+1}`),sr(t,e,n,s,o,i,a+1);throw new Error(`Module "${e.name}" failed to produce structured output after ${a+1} attempts`)}let c=l.data,d=typeof c.fieldsJson=="string"?c.fieldsJson:JSON.stringify(c.fieldsJson,null,2),u=typeof c.metaJson=="string"?c.metaJson:JSON.stringify(c.metaJson,null,2);return{moduleName:e.name,fieldsJson:d,metaJson:u,moduleHtml:String(c.moduleHtml||""),moduleCss:String(c.moduleCss||""),moduleJs:c.moduleJs?String(c.moduleJs):void 0}}f();function ir(t,e,n){return n({type:"agent_step",step:"quality_check",label:"Quality check \u2014 fixing common issues..."}),t.map(s=>{let o=[],i={...s};i.fieldsJson=or(i.fieldsJson,i.moduleName,"fieldsJson",o),i.metaJson=or(i.metaJson,i.moduleName,"metaJson",o),i.fieldsJson=_c(i.fieldsJson,i.moduleName,o),i.fieldsJson=Pc(i.fieldsJson,i.moduleName,o),i.moduleCss=Rc(i.moduleCss,i.moduleName,"moduleCss",o),Oc(i.moduleCss,i.moduleName,e,o),i.moduleHtml=jc(i.moduleHtml,i.moduleName,o),i.metaJson=Fc(i.metaJson,i.moduleName,o);let a=o.every(r=>r.autoFixed);return o.length>0&&M.info("validator",`${i.moduleName}: ${o.length} issues`,{autoFixed:o.filter(r=>r.autoFixed).length,unfixed:o.filter(r=>!r.autoFixed).length}),{module:i,issues:o,valid:a}})}function or(t,e,n,s){return!t||t.trim()===""?(s.push({module:e,field:n,message:`Empty ${n}`,autoFixed:n==="metaJson"}),n==="metaJson"?JSON.stringify({host_template_types:["PAGE"],is_available_for_new_content:!0}):t):(je(t)===null&&s.push({module:e,field:n,message:`Invalid JSON in ${n}`,autoFixed:!1}),t)}function _c(t,e,n){let s=t;return/"name"\s*:\s*"name"/g.test(s)&&(n.push({module:e,field:"fieldsJson",message:'"name" is a reserved field name \u2192 renamed to "item_name"',autoFixed:!0}),s=s.replace(/"name"\s*:\s*"name"/g,'"name": "item_name"')),/"name"\s*:\s*"label"/g.test(s)&&(n.push({module:e,field:"fieldsJson",message:'"label" is a reserved field name \u2192 renamed to "section_label"',autoFixed:!0}),s=s.replace(/"name"\s*:\s*"label"/g,'"name": "section_label"')),s}function Pc(t,e,n){let s=t;return/"type"\s*:\s*"textarea"/g.test(s)&&(n.push({module:e,field:"fieldsJson",message:'"textarea" is deprecated \u2192 changed to "text"',autoFixed:!0}),s=s.replace(/"type"\s*:\s*"textarea"/g,'"type": "text"')),s}function Rc(t,e,n,s){if(!t)return t;let o=t,i=/@import\s+url\([^)]*(?:fonts\.googleapis|cdnjs|unpkg|jsdelivr)[^)]*\)\s*;?/gi;return i.test(o)&&(s.push({module:e,field:n,message:"CDN @import removed (external imports not allowed)",autoFixed:!0}),o=o.replace(i,"/* CDN import removed */")),o}function Oc(t,e,n,s){if(!t)return;let o=/\.([a-zA-Z][\w-]*)/g,i,a=0;for(;(i=o.exec(t))!==null;){let r=i[1];r.startsWith(n+"-")||r==="visible"||r==="active"||r==="scroll-animate"||r.startsWith("body-wrapper")||r.startsWith("dnd-")||r.startsWith("row-")||a++}a>3&&s.push({module:e,field:"moduleCss",message:`${a} CSS classes without "${n}-" prefix`,autoFixed:!1})}function jc(t,e,n){if(!t)return t;let s=t,o=/\{%[-~]?\s*(if|for|block|macro|endif|endfor|endblock|endmacro)\b[^%]*%\}/g,i=[],a;for(;(a=o.exec(s))!==null;){let c=a[1],d=!c.startsWith("end"),u=d?c:c.replace("end","");i.push({tag:c,isOpen:d,baseTag:u,start:a.index,end:a.index+a[0].length})}let r=[],l=[];for(let c=0;c<i.length;c++)if(i[c].isOpen)r.push(c);else{let d=-1;for(let u=r.length-1;u>=0;u--)if(i[r[u]].baseTag===i[c].baseTag){d=u;break}d!==-1?r.splice(d,1):l.push(c)}if(l.length>0){for(let c=l.length-1;c>=0;c--){let d=i[l[c]];s=s.slice(0,d.start)+`<!-- removed orphan {% ${d.tag} %} -->`+s.slice(d.end)}n.push({module:e,field:"moduleHtml",message:`Removed ${l.length} orphan closing tag${l.length===1?"":"s"} with no matching opener`,autoFixed:!0})}if(r.length>0){let c=r.map(u=>i[u].baseTag),d=c.reverse().map(u=>`{% end${u} %}`).join(`
1283
+ `);s=`${s}
1284
+ ${d}`,n.push({module:e,field:"moduleHtml",message:`Added ${c.length} missing closing tag${c.length===1?"":"s"}: ${c.map(u=>`{% end${u} %}`).join(", ")}`,autoFixed:!0})}return/\bnow\(\)/.test(s)&&(s=s.replace(/\bnow\(\)/g,"local_dt"),n.push({module:e,field:"moduleHtml",message:"Replaced now() with local_dt (now() is not valid HubL)",autoFixed:!0})),s}function Fc(t,e,n){let s=je(t);if(!s||typeof s!="object")return t;let o=s,i=!1;return o.host_template_types||(o.host_template_types=["PAGE"],i=!0),o.is_available_for_new_content===void 0&&(o.is_available_for_new_content=!0,i=!0),i?(n.push({module:e,field:"metaJson",message:"Added missing meta.json required fields",autoFixed:!0}),JSON.stringify(o,null,2)):t}import{execSync as Jc}from"child_process";async function rr(t,e,n,s,o,i,a,r){let l=Date.now(),c=i;if(Ut(n)){let O={"claude-code":"claude","gemini-cli":"gemini","codex-cli":"codex"}[n];if(O)try{Jc(`command -v ${O}`,{stdio:"ignore"})}catch{throw new Error(`CLI engine "${n}" requires "${O}" to be installed and on your PATH.`)}}let d=await Ki(t,e,n,s,o,a,r);if(d.intent==="question"&&d.answer){let H=Date.now()-l;return a({type:"pipeline_complete",modulesGenerated:0,modulesUnchanged:e.modules.length,durationMs:H}),{modules:[...e.modules],moduleOrder:e.moduleOrder,sharedCss:e.sharedCss,sharedJs:e.sharedJs,assistantMessage:d.answer,stats:{modulesGenerated:0,modulesUnchanged:e.modules.length,modulesFailed:0,durationMs:H}}}let u=null,p=e.sharedCss,g=e.sharedJs;(d.intent==="create"||d.designSystemChanges)&&(u=await Xi(t,d,e,n,s,o,a),p=u.designSystem.sharedCss||p,g=u.designSystem.sharedJs||g,a({type:"blueprint_ready",moduleOrder:u.moduleOrder,sharedCss:p,sharedJs:g}));let b=[];if(u)for(let H of u.modules)b.push({name:H.name,description:H.description,contentBrief:H.contentBrief,layoutNotes:H.layoutNotes});else{for(let H of d.newModules)b.push({name:H.name,description:H.description,contentBrief:"Generate appropriate content based on the user request",layoutNotes:"Use responsive layout matching the existing design system"});for(let H of d.affectedModules){let O=e.modules.find(te=>te.moduleName===H);O&&b.push({name:H,description:`Modify existing module: ${H}`,contentBrief:"Apply the user's requested changes",layoutNotes:"Preserve existing layout unless changes are requested",existingCode:O})}}let y=[],w=[];if(b.length>0){let H=await nr(t,b,p,e.themeName,n,s,o,c,a,d.guidesNeeded,e.brandAssets);for(let O of H)O.module?y.push(O.module):w.push(O.moduleName)}let I=null;if(y.length>0){I=ir(y,e.themeName,a),y=I.map(O=>O.module);let H=I.reduce((O,te)=>O+te.issues.length,0);if(H>0){let O=I.reduce((ie,Ks)=>ie+Ks.issues.filter(It=>It.autoFixed).length,0);M.info("pipeline",`Quality check: ${H} issues, ${O} auto-fixed`);let te=I.flatMap(ie=>ie.issues).map(ie=>`${ie.autoFixed?"\u2713":"\u26A0"} ${ie.module}: ${ie.message}`).join(`
1285
+ `);a({type:"agent_decision",step:"quality_check",decision:`${H} issues found, ${O} auto-fixed
1286
+ ${te}`})}else a({type:"agent_decision",step:"quality_check",decision:"All modules passed quality checks"})}let T=Dc(e,d,y,u,r),J=Hc(e,d,u,T),D=Date.now()-l,R=y.length,L=d.unchangedModules.length,Z=I?I.flatMap(H=>H.issues):[],G=Lc(d,R,L,w,D,u,Z);return w.length>0?a({type:"pipeline_partial",succeeded:y.map(H=>H.moduleName),failed:w,durationMs:D}):a({type:"pipeline_complete",modulesGenerated:R,modulesUnchanged:L,durationMs:D}),{modules:T,moduleOrder:J,sharedCss:p,sharedJs:g,assistantMessage:G,stats:{modulesGenerated:R,modulesUnchanged:L,modulesFailed:w.length,durationMs:D}}}function Dc(t,e,n,s,o){let i=[],a=new Set;for(let r of n)i.push(r),a.add(r.moduleName);for(let r of e.unchangedModules){if(a.has(r))continue;let l=t.modules.find(c=>c.moduleName===r);l&&(i.push(l),a.add(r))}if(e.reuseModules)for(let r of e.reuseModules){if(a.has(r.name))continue;let l=o.find(c=>c.name===r.name&&c.module);l&&l.module&&(i.push(l.module),a.add(r.name))}return i}function Hc(t,e,n,s){if(n?.moduleOrder?.length)return n.moduleOrder;if(e.intent==="create")return s.map(r=>r.moduleName);let o=[...t.moduleOrder],i=[...e.newModules.map(r=>({name:r.name,position:r.position})),...(e.reuseModules||[]).map(r=>({name:r.name,position:r.position}))].sort((r,l)=>r.position-l.position);for(let r of i){let l=Math.min(r.position,o.length);o.splice(l,0,r.name)}let a=new Set(s.map(r=>r.moduleName));return o.filter(r=>a.has(r))}function Lc(t,e,n,s,o,i,a){let r=Math.round(o/1e3),l=[];if(t.intent==="create")l.push(`Created ${e} module${e===1?"":"s"} in ${r}s.`);else if(t.intent==="modify"||t.intent==="style_change")l.push(`Updated ${e} module${e===1?"":"s"} in ${r}s.`),n>0&&l.push(`${n} module${n===1?"":"s"} unchanged.`);else if(t.intent==="add"){let u=t.newModules.map(p=>p.name).join(", ");l.push(`Added ${u} in ${r}s.`)}else t.intent==="remove"?l.push(`Removed modules in ${r}s.`):t.intent==="rearrange"&&l.push(`Rearranged modules in ${r}s.`);i?.narrative&&l.push(`
1287
+
1288
+ ${i.narrative}`),s.length>0&&l.push(`
1289
+
1290
+ **Failed:** ${s.join(", ")}. You can retry these individually.`);let c=a.filter(u=>!u.autoFixed),d=a.filter(u=>u.autoFixed);if(d.length>0||c.length>0){let u=[];d.length>0&&u.push(`**Auto-fixed:** ${d.map(p=>`${p.module}: ${p.message}`).join(", ")}`),c.length>0&&u.push(`**Warnings:** ${c.map(p=>`${p.module}: ${p.message}`).join(", ")}`),l.push(`
1291
+
1292
+ ${u.join(`
1293
+ `)}`)}return l.join("")}var Rs=null;function ar(t){Rs=t}var rt=null;function Wt(){return rt!==null}function xt(t){if(rt){let e=v();if(!e||e.id!==rt){M.warn("ai-handler","Session changed during generation \u2014 discarding AI output");return}}ze("assistant",t),_i(t,Rs||void 0),j()}async function Os(t,e,n,s){let o=v();if(!o)throw new Error("No active session");rt=o.id;let a=s?.length?Li(s):void 0;try{let r=E(),l=r.aiEngine||js();switch(l){case"anthropic-api":case"api":{let c=ge("anthropic-api",r);if(!c)throw new Error("Anthropic API key not configured. Open Settings to add one.");await Ri(t,c,o.themeName,r.anthropicApiModel||"claude-sonnet-4-6",e,n,xt,a);break}case"openai-api":{let c=ge("openai-api",r);if(!c)throw new Error("OpenAI API key not configured. Open Settings to add one.");await Oi(t,c,o.themeName,r.openaiApiModel||"gpt-4o",e,n,xt,a);break}case"gemini-api":{let c=ge("gemini-api",r);if(!c)throw new Error("Gemini API key not configured. Open Settings to add one.");await ji(t,c,o.themeName,e,n,xt,a);break}case"claude-code":await Fi(t,o.themeName,e,n,xt,a);break;case"gemini-cli":await ks("gemini",t,o.themeName,e,n,xt,a);break;case"codex-cli":await ks("codex",t,o.themeName,e,n,xt,a);break;default:throw new Error(`Unknown AI engine: ${l}. Open Settings to configure one.`)}}finally{rt=null,Rs=null}}function js(){let t=E();if(t.anthropicApiKey||process.env.ANTHROPIC_API_KEY)return"anthropic-api";if(t.openaiApiKey||process.env.OPENAI_API_KEY)return"openai-api";if(t.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY)return"gemini-api";try{return Ps("claude --version",{stdio:"pipe"}),"claude-code"}catch{}try{return Ps("gemini --version",{stdio:"pipe"}),"gemini-cli"}catch{}try{return Ps("codex --version",{stdio:"pipe"}),"codex-cli"}catch{}throw new Error("No AI engine available. Open Settings to configure one.")}function Gc(){let t=v(),e=Se(),n=e?[...e.modules]:[...t.modules],s=e?[...e.moduleOrder]:[...t.moduleOrder];return{modules:n,moduleOrder:s,sharedCss:e?.sharedCss||t.sharedCss,sharedJs:e?.sharedJs||t.sharedJs,messages:[...t.messages],themeName:t.themeName,themePath:t.themePath,brandAssets:t.brandAssets?{...t.brandAssets}:void 0}}function Uc(t){let e=t.aiEngine||js();if(!Fn(e))throw new Error("Agentic pipeline is not available for this engine.");if(Ut(e)){let o="";return e==="claude-code"&&(o=t.claudeCodeModel||""),{engine:e,apiKey:"",model:o}}let n=ge(e,t);if(!n)throw new Error(`API key not configured for ${e}. Open Settings to add one.`);let s;switch(e){case"anthropic-api":s=t.anthropicApiModel||"claude-sonnet-4-6";break;case"openai-api":s=t.openaiApiModel||"gpt-4o";break;case"gemini-api":s="gemini-2.5-flash";break;default:s=""}return{engine:e,apiKey:n,model:s}}async function lr(t,e,n){let s=v();if(!s)throw new Error("No active session");let o=s.id;rt=o;try{let i=E(),{engine:a,apiKey:r,model:l}=Uc(i),c=i.agenticConcurrency||20,d=Gc(),u=qe(),p=new Set(d.modules.map(y=>y.moduleName)),g=u.filter(y=>!p.has(y.module.moduleName)).map(y=>({name:y.module.moduleName,usedIn:y.usedIn})),h=await rr(t,d,a,r,l,c,e,g),b=v();if(!b||b.id!==o)throw M.warn("ai-handler","Session changed during agentic generation \u2014 discarding output"),new Error("Session changed during generation");return h}finally{rt=null}}function cr(t,e){Oe({modules:t.modules,sharedCss:t.sharedCss,sharedJs:t.sharedJs}),ht(t.moduleOrder),ze("assistant",t.assistantMessage,e),j()}function dr(){let t=E(),e=t.aiEngine||js();return Fn(e)?t.agenticMode===void 0?{useAgentic:!1,needsPrompt:!0}:{useAgentic:t.agenticMode,needsPrompt:!1}:{useAgentic:!1,needsPrompt:!1,reason:"Agentic pipeline is not available for this engine."}}ee();f();import{spawn as Fs}from"child_process";var Qe=new Map;function ur(t,e,n){t.stdout?.on("data",o=>{e.output+=o.toString()}),t.stderr?.on("data",o=>{e.output+=o.toString()}),t.on("close",o=>{e.status=o===0?"completed":"failed",e.exitCode=o,e.completedAt=Date.now()}),t.on("error",o=>{e.status="failed",e.output+=`
1294
+ Process error: ${o.message}`,e.completedAt=Date.now()}),setTimeout(()=>{e.status==="running"&&(t.kill(),e.status="failed",e.output+=`
1295
+ Process timed out`,e.completedAt=Date.now())},n||3e5)}function Bt(t,e,n,s){let o=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,i={id:o,command:`${t} ${e.join(" ")}`,description:n,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null};Qe.set(o,i);let a=Fs(t,e,{cwd:s?.cwd,stdio:[s?.stdin?"pipe":"ignore","pipe","pipe"],env:{...process.env,...s?.env},shell:process.platform==="win32"});return s?.stdin&&a.stdin&&(a.stdin.write(s.stdin),a.stdin.end()),ur(a,i,s?.timeout),o}function at(t,e,n){let s=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,o={id:s,command:t,description:e,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null};Qe.set(s,o);let i=t.split(" "),a=Fs(i[0],i.slice(1),{cwd:n?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...n?.env},shell:!0});return ur(a,o,n?.timeout),s}function Jn(t){return Qe.get(t)}function Wc(){let t=Date.now()-18e5;for(let[e,n]of Qe)n.completedAt&&n.completedAt<t&&Qe.delete(e)}setInterval(Wc,600*1e3);function Dn(t,e,n){let s=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,o={id:s,command:t,description:e,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null,listeners:new Set};Qe.set(s,o);let i=t.split(" "),a=Fs(i[0],i.slice(1),{cwd:n?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...n?.env},shell:!0}),r=c=>{for(let d of o.listeners)try{d(c)}catch{}};a.stdout?.on("data",c=>{let d=c.toString();o.output+=d,r(d)}),a.stderr?.on("data",c=>{let d=c.toString();o.output+=d,r(d)}),a.on("close",c=>{o.status=c===0?"completed":"failed",o.exitCode=c,o.completedAt=Date.now(),o.listeners.clear()}),a.on("error",c=>{o.status="failed",o.output+=`
1296
+ Process error: ${c.message}`,o.completedAt=Date.now(),o.listeners.clear()});let l=n?.timeout||3e5;return setTimeout(()=>{o.status==="running"&&(a.kill(),o.status="failed",o.output+=`
1297
+ Process timed out`,o.completedAt=Date.now(),o.listeners.clear())},l),s}function mr(t,e){let n=Qe.get(t);if(!n||!("listeners"in n))return;let s=n;if(s.output)try{e(s.output)}catch{}s.listeners.add(e)}function pr(t,e){let n=Qe.get(t);!n||!("listeners"in n)||n.listeners.delete(e)}X();f();import{existsSync as Ct,readdirSync as fr,rmSync as Bc}from"fs";import{join as At,basename as Kc}from"path";import{homedir as Vc}from"os";import{execFileSync as gr}from"child_process";ee();pn();tt();ee();X();var hr=process.platform==="win32"?{shell:!0}:{},$e=At(Vc(),"vibespot-themes"),Hn=null,Yc=5e3;function Ln(){if(Hn&&Date.now()-Hn.ts<Yc)return Hn.data;let t=[];if(Ct($e))try{for(let e of fr($e,{withFileTypes:!0}))if(e.isDirectory()){let n=At($e,e.name,"theme.json");if(Ct(n)){let s=0,o=At($e,e.name,"modules");if(Ct(o))try{s=fr(o,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}t.push({name:e.name,moduleCount:s})}}}catch{}return Hn={data:t,ts:Date.now()},t}function yr(t){let e=v(),n=on(),s=!1;try{gr("hs",["--version"],{encoding:"utf-8",stdio:"pipe",...hr}),s=!0}catch{}let o=bt().sort((a,r)=>r.updatedAt-a.updatedAt).slice(0,10),i=Ln();m(t,200,{hasActiveSession:!!e,activeSession:e?{id:e.id,themeName:e.themeName,moduleCount:e.modules.length}:null,hsInstalled:s,aiAvailable:n.availableEngines.length>0,availableEngines:n.availableEngines,activeEngine:n.activeEngine,sessions:o,localThemes:i})}function br(t,e){_(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=s.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,""),i=At($e,o);we($e),Ct(i)&&Bc(i,{recursive:!0,force:!0}),mn(i,o),Ft(i,o),j(),m(e,200,{ok:!0,themeName:o,themePath:i})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Sr(t,e){_(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=s.replace(/^\/+|\/+$/g,"");if(!o){m(e,400,{error:"Theme name is required"});return}let i=he(),a=E(),r=o.includes("/")||o.includes("@")?o.replace(/[@/]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""):o,l=At($e,r);we($e),a.hubspotUploadMode==="cli"||!i?(gr("hs",["cms","fetch",o,l],{encoding:"utf-8",stdio:"pipe",...hr}),Ft(l,r),Ht(l),j(),m(e,200,{ok:!0,themeName:r,themePath:l,moduleCount:v()?.modules.length||0})):Rt(i,o,l).then(()=>{Ft(l,r),Ht(l),j(),m(e,200,{ok:!0,themeName:r,themePath:l,moduleCount:v()?.modules.length||0})}).catch(c=>{m(e,500,{error:c instanceof Error?c.message:String(c)})})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function vr(t,e){_(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{path:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme path is required"});return}let o=s;if(Ct(o)||(o=At($e,s)),!Ct(o)){m(e,400,{error:`Theme folder not found: ${s}`});return}let i=Kc(o);Ft(o,i),Ht(o),j(),m(e,200,{ok:!0,themeName:i,themePath:o,moduleCount:v()?.modules.length||0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function wr(t,e){_(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{sessionId:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Session ID is required"});return}let o=_n(s);if(!o){m(e,404,{error:"Session not found"});return}m(e,200,{ok:!0,themeName:o.themeName,themePath:o.themePath,moduleCount:o.modules.length,messageCount:o.messages.length})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function xr(t,e){_(t,n=>{try{let{apiKey:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"API key is required"});return}Y({anthropicApiKey:s}),m(e,200,{ok:!0})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Cr(t){let e=he();if(!e){m(t,200,{themes:[],error:"No HubSpot account connected"});return}(async()=>{let n=await uo(e);if(n.length===0){m(t,200,{themes:[]});return}let s=[],o=n.map(async r=>{let l=r.path||r.name;try{let c=await ln(e,`${l}/theme.json`);c&&!c.folder&&s.push({name:r.name,path:l})}catch{}});await Promise.all(o),s.sort((r,l)=>r.name.localeCompare(l.name));let i=Ln(),a=new Set(i.map(r=>r.name));m(t,200,{themes:s.map(r=>({...r,existsLocally:a.has(r.name)}))})})().catch(n=>{m(t,200,{themes:[],error:n instanceof Error?n.message:String(n)})})}f();import{existsSync as zc,readFileSync as qc,appendFileSync as Xc}from"fs";import{join as Ar}from"path";import{homedir as Ir}from"os";ee();tt();X();var Kt={data:{},ts:0},Qc=600*1e3,kr={"claude-code":[{id:"sonnet",label:"Claude Sonnet (default)"},{id:"opus",label:"Claude Opus"},{id:"haiku",label:"Claude Haiku"}],"codex-cli":[{id:"o4-mini",label:"o4 Mini (default)"},{id:"o3",label:"o3"},{id:"gpt-4o",label:"GPT-4o"}]};async function Zc(t){let e=await fetch("https://api.anthropic.com/v1/models",{headers:{"x-api-key":t,"anthropic-version":"2023-06-01"}});return e.ok?(await e.json()).data.filter(s=>!s.id.startsWith("claude-3-")&&!s.id.startsWith("claude-2")).map(s=>({id:s.id,label:s.display_name})):[]}async function ed(t){let e=await fetch("https://api.openai.com/v1/models",{headers:{Authorization:`Bearer ${t}`}});if(!e.ok)return[];let n=await e.json(),s=/^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;return n.data.filter(o=>s.test(o.id)).sort((o,i)=>o.id.localeCompare(i.id)).map(o=>({id:o.id,label:o.id}))}async function td(t){let e=await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${t}`);return e.ok?(await e.json()).models.filter(s=>s.name.includes("gemini-2")).map(s=>({id:s.name.replace("models/",""),label:s.displayName})):[]}async function nd(){if(Date.now()-Kt.ts<Qc&&Object.keys(Kt.data).length>0)return Kt.data;let t=E(),e={...kr},n=[],s=ge("anthropic-api",t);s&&n.push(Zc(s).then(a=>{a.length&&(e["anthropic-api"]=a)}).catch(()=>{}));let o=ge("openai-api",t);o&&n.push(ed(o).then(a=>{a.length&&(e["openai-api"]=a)}).catch(()=>{}));let i=ge("gemini-api",t);return i&&n.push(td(i).then(a=>{a.length&&(e["gemini-api"]=a,e["gemini-cli"]=a)}).catch(()=>{})),await Promise.all(n),Kt.data=e,Kt.ts=Date.now(),e}function $r(t){let e=on(),n=E(),s={aiEngine:n.aiEngine||null,claudeCodeModel:n.claudeCodeModel||null,anthropicApiModel:n.anthropicApiModel||null,openaiApiModel:n.openaiApiModel||null,hubspotUploadMode:n.hubspotUploadMode||"api",hubspotAccounts:(n.hubspotAccounts||[]).map(r=>({portalId:r.portalId,portalName:r.portalName,dataCenter:r.dataCenter})),activeHubSpotAccount:n.activeHubSpotAccount||null,enabledCLITools:n.enabledCLITools||[],agenticMode:n.agenticMode,agenticConcurrency:n.agenticConcurrency},o=bt().length,i=Ln().length,a=ut();nd().then(r=>{m(t,200,{version:a,environment:e,config:s,models:r,sessionCount:o,localThemeCount:i})}).catch(()=>{m(t,200,{version:a,environment:e,config:s,models:kr,sessionCount:o,localThemeCount:i})})}function Tr(t,e){_(t,n=>{try{let{engine:s,model:o}=JSON.parse(n);if(!["claude-code","anthropic-api","openai-api","gemini-cli","gemini-api","codex-cli"].includes(s)){m(e,400,{error:`Invalid engine: ${s}`});return}let a={aiEngine:s};if(o)switch(s){case"claude-code":a.claudeCodeModel=o;break;case"anthropic-api":a.anthropicApiModel=o;break;case"openai-api":a.openaiApiModel=o;break}Y(a),m(e,200,{ok:!0,engine:s})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Er(t,e){_(t,n=>{try{let{provider:s,apiKey:o}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"provider is required"});return}if(!o){let l={};switch(s){case"anthropic":l.anthropicApiKey="";break;case"openai":l.openaiApiKey="";break;case"gemini":l.geminiApiKey="";break;default:m(e,400,{error:`Unknown provider: ${s}`});return}Y(l),m(e,200,{ok:!0,provider:s,deleted:!0});return}let i={};switch(s){case"anthropic":i.anthropicApiKey=o;break;case"openai":i.openaiApiKey=o;break;case"gemini":i.geminiApiKey=o;break;default:m(e,400,{error:`Unknown provider: ${s}`});return}Y(i);let a=null;if(!E().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[s];c&&(Y({aiEngine:c}),a=c)}m(e,200,{ok:!0,provider:s,autoSelectedEngine:a})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Mr(t,e){_(t,n=>{try{let{tool:s}=JSON.parse(n),o={hubspot:{cmd:"npm install -g @hubspot/cli",desc:"Installing HubSpot CLI"},claude:{cmd:"npm install -g @anthropic-ai/claude-code",desc:"Installing Claude Code"},gemini:{cmd:"npm install -g @google/gemini-cli",desc:"Installing Gemini CLI"},codex:{cmd:process.platform==="darwin"?"brew install --cask codex":"npm install -g @openai/codex",desc:"Installing OpenAI Codex"},gh:{cmd:process.platform==="darwin"?"brew install gh":"npm install -g @cli/gh",desc:"Installing GitHub CLI"}},i=o[s];if(!i){m(e,400,{error:`Unknown tool: ${s}. Valid: ${Object.keys(o).join(", ")}`});return}let a=at(i.cmd,i.desc,{timeout:12e4});m(e,200,{ok:!0,jobId:a})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Nr(t,e){_(t,n=>{try{let s=JSON.parse(n||"{}"),o=E(),i=o.hubspotUploadMode||"api";if(s.personalAccessKey)if(i==="api"){an(s.personalAccessKey).then(a=>{Qt(s.personalAccessKey,a.portalId,a.portalName,a.dataCenter),m(e,200,{ok:!0,portalName:a.portalName,portalId:a.portalId,dataCenter:a.dataCenter})}).catch(a=>{m(e,400,{error:a instanceof Error?a.message:String(a)})});return}else{if(!Me().found){m(e,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Bt("hs",["auth",`--pak=${s.personalAccessKey}`],"Authenticating with HubSpot",{timeout:3e4});m(e,200,{ok:!0,jobId:r});return}if(i==="api"){let a=o.hubspotAccounts||[];if(a.length>0&&!s.force){let r=a.find(l=>l.portalId===o.activeHubSpotAccount)||a[0];m(e,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}else{if(!Me().found){m(e,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Ne();if(r.authenticated&&!s.force){m(e,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}m(e,200,{needsKey:!0,instructions:"Create a personal access key in HubSpot",url:"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key",steps:["Click the link above to open HubSpot","Select your account","Create a Personal Access Key with CMS permissions","Copy the key and paste it below"]})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function _r(t,e){_(t,n=>{try{let s=JSON.parse(n||"{}");if(!Qn().found){m(e,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=Zn();if(i.authenticated&&!s.force){m(e,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(s.token){let r=Bt("gh",["auth","login","--with-token"],"Authenticating with GitHub",{timeout:3e4,stdin:s.token});m(e,200,{ok:!0,jobId:r});return}let a=at("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});m(e,200,{ok:!0,jobId:a,browserAuthRequired:!0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Pr(t,e){_(t,n=>{try{let{portalId:s,action:o}=JSON.parse(n);if((E().hubspotUploadMode||"api")==="api"){if(o==="remove"&&s){eo(s),m(e,200,{ok:!0});return}if(s){to(s),m(e,200,{ok:!0});return}}else{if(!Me().found){m(e,400,{error:"HubSpot CLI not installed"});return}let l=String(s).replace(/[^0-9]/g,"");if(!l){m(e,400,{error:"Invalid portalId"});return}if(o==="remove"){let c=Bt("hs",["accounts","remove",l],`Removing HubSpot account ${l}`,{timeout:15e3});m(e,200,{ok:!0,jobId:c});return}if(l){let c=Bt("hs",["accounts","use",l],`Switching to HubSpot account ${l}`,{timeout:15e3});m(e,200,{ok:!0,jobId:c});return}}m(e,400,{error:"portalId required"})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Rr(t){let e=at("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});m(t,200,{ok:!0,jobId:e})}function Or(t,e){_(t,n=>{try{let{cli:s,apiKey:o}=JSON.parse(n||"{}");switch(s){case"claude":{let i=at("CLAUDECODE= claude --print -p 'reply OK'","Authenticating Claude Code (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"If Claude Code opens a browser window, complete the sign-in there."});break}case"gemini":{let i=at("gemini -p 'reply OK'","Authenticating Gemini CLI (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"If Gemini opens a browser window, complete the sign-in there."});break}case"codex":{if(o&&o.trim()){let i=o.trim();if(process.env.OPENAI_API_KEY=i,Y({openaiApiKey:i}),process.platform!=="win32"){let a=/^[A-Za-z0-9_\-.:]+$/.test(i)?i:"";if(a){let r=`export OPENAI_API_KEY="${a}"`,l=process.env.SHELL?.includes("zsh")?Ar(Ir(),".zshrc"):Ar(Ir(),".bashrc");try{(zc(l)?qc(l,"utf-8"):"").includes("OPENAI_API_KEY")||Xc(l,`
742
1298
  # Added by vibeSpot
743
- ${a}
744
- `)}catch{}}d(t,200,{ok:!0,message:"API key saved"})}else{let i=Ce("codex login","Authenticating Codex CLI (check your browser if prompted)",{timeout:12e4});d(t,200,{ok:!0,jobId:i,hint:"Complete the sign-in in your browser."})}break}default:d(t,400,{error:`Unknown CLI: ${n}`})}}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Di(e,t){_(e,o=>{try{let{mode:n}=JSON.parse(o);if(n!=="api"&&n!=="cli"){d(t,400,{error:`Invalid mode: ${n}. Must be "api" or "cli".`});return}z({hubspotUploadMode:n}),d(t,200,{ok:!0,mode:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ji(e,t){_(e,o=>{try{let{toolId:n,enabled:s}=JSON.parse(o);if(!n||typeof s!="boolean"){d(t,400,{error:"toolId (string) and enabled (boolean) required"});return}ko(n,s),d(t,200,{ok:!0,toolId:n,enabled:s})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Fi(e,t){let o=e.replace("/api/settings/job/","");if(!o){d(t,400,{error:"Job ID required"});return}let n=vn(o);if(!n){d(t,404,{error:"Job not found"});return}d(t,200,{id:n.id,status:n.status,description:n.description,output:n.output,exitCode:n.exitCode,startedAt:n.startedAt,completedAt:n.completedAt})}h();import{existsSync as yl,rmSync as bl}from"fs";import{join as Sl}from"path";function Hi(e,t,o){if(e==="GET"){let n=$(),s=ut().sort((i,a)=>a.updatedAt-i.updatedAt);d(o,200,{activeTheme:n?{id:n.id,themeName:n.themeName}:null,sessions:s});return}if(e==="DELETE"){_(t,n=>{try{let{sessionId:s,deleteFiles:i}=JSON.parse(n);Fs(s,i),d(o,200,{ok:!0})}catch(s){d(o,500,{error:s instanceof Error?s.message:String(s)})}});return}d(o,405,{error:"Method not allowed"})}function Li(e,t){_(e,o=>{try{let{sessionId:n}=JSON.parse(o),s=bn(n);if(!s){d(t,404,{error:"Session not found"});return}d(t,200,{ok:!0,themeName:s.themeName,themePath:s.themePath})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Gi(e,t){_(e,o=>{try{let{themeName:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme name is required"});return}let s=Sl(Ae,n);if(!yl(s)){d(t,404,{error:"Theme not found on disk"});return}bl(s,{recursive:!0,force:!0}),d(t,200,{ok:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ui(e,t){_(e,o=>{try{let{sessionId:n,newName:s}=JSON.parse(o);if(!n||!s||typeof s!="string"){d(t,400,{error:"sessionId and newName are required"});return}let i=s.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-|-$/g,"").replace(/-{2,}/g,"-");if(!i){d(t,400,{error:"Invalid name"});return}let a=Hs(n,i);a.ok?d(t,200,{ok:!0,newName:i}):d(t,400,{error:a.error})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}h();import{existsSync as $n,readFileSync as Tl,rmSync as go}from"fs";import{join as Pe,basename as $l}from"path";import{execSync as kl}from"child_process";Z();Q();function Ki(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}let o=dt();d(e,200,{themeName:t.themeName,themePath:t.themePath,templates:t.templates.map(n=>({id:n.id,label:n.label,pageType:n.pageType,moduleCount:n.modules.length,messageCount:n.messages.length})),activeTemplateId:t.activeTemplateId,moduleLibrary:o.map(n=>({moduleName:n.module.moduleName,usedIn:n.usedIn})),brandAssets:{hasStyleguide:!!t.brandAssets?.styleguide,hasBrandvoice:!!t.brandAssets?.brandvoice,humanify:t.brandAssets?.humanify!==!1}})}function Bi(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}let o=t.themePath;if(!$n(o)){d(e,404,{error:"Theme directory not found"});return}let n=t.themeName||"theme",s=Pe(o,".."),i=$l(o);try{let a=`${n}.zip`,r=Pe(s,a);$n(r)&&go(r),kl(`zip -r "${a}" "${i}" -x "${i}/.git/*" "${i}/.vibespot/*" "${i}/node_modules/*"`,{cwd:s,timeout:3e4});let l=Tl(r);go(r),e.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${a}"`,"Content-Length":l.length}),e.end(l)}catch(a){V.error("download-zip","Failed to create zip archive",a),d(e,500,{error:"Failed to create zip archive"})}}function Yi(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){d(o,200,{templates:n.templates.map(s=>({id:s.id,label:s.label,pageType:s.pageType,moduleCount:s.modules.length})),activeTemplateId:n.activeTemplateId});return}if(e==="POST"){_(t,s=>{try{let{pageType:i,label:a}=JSON.parse(s);if(!i||!a){d(o,400,{error:"pageType and label are required"});return}if(!["landing_page","blog_post","website_page","module_only"].includes(i)){d(o,400,{error:`Invalid pageType: ${i}`});return}let l=Ns(i,a);j(),d(o,200,{ok:!0,template:{id:l.id,label:l.label,pageType:l.pageType}})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}if(e==="DELETE"){_(t,s=>{try{let{templateId:i}=JSON.parse(s);if(!i){d(o,400,{error:"templateId is required"});return}if(!Ps(i)){d(o,404,{error:"Template not found"});return}j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}d(o,405,{error:"Method not allowed"})}function Vi(e,t){_(e,o=>{try{let{templateId:n}=JSON.parse(o);if(!n){d(t,400,{error:"templateId is required"});return}if(!zn(n)){d(t,404,{error:"Template not found"});return}j();let i=$();d(t,200,{ok:!0,modules:be().map(a=>a.moduleName),messageCount:i?.messages.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function zi(e,t){_(e,o=>{try{let{templateId:n,newLabel:s}=JSON.parse(o);if(!n||!s||typeof s!="string"){d(t,400,{error:"templateId and newLabel are required"});return}if(!Rs(n,s.trim())){d(t,404,{error:"Template not found"});return}j(),d(t,200,{ok:!0,newLabel:s.trim()})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function qi(e,t){_(e,o=>{try{let{templateId:n,label:s}=JSON.parse(o);if(!n){d(t,400,{error:"templateId is required"});return}let i=_s(n,s);if(!i){d(t,404,{error:"Template not found"});return}j(),d(t,200,{ok:!0,template:{id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Xi(e){let t=dt();d(e,200,{modules:t.map(o=>({moduleName:o.module.moduleName,usedIn:o.usedIn,fieldsJson:o.module.fieldsJson}))})}function Qi(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}_(t,s=>{try{let{moduleName:i}=JSON.parse(s);if(!i){d(o,400,{error:"moduleName is required"});return}let r=dt().find(u=>u.module.moduleName===i);if(!r){d(o,404,{error:`Module "${i}" not found in library`});return}let l={...r.module};n.modules.find(u=>u.moduleName===l.moduleName)||(n.modules.push(l),n.moduleOrder.push(l.moduleName),n.updatedAt=Date.now()),j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}})}function Zi(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){d(o,200,{styleguide:n.brandAssets?.styleguide||null,brandvoice:n.brandAssets?.brandvoice||null});return}if(e==="POST"){_(t,s=>{try{let{type:i,content:a}=JSON.parse(s);if(!i){d(o,400,{error:"type is required"});return}if(n.brandAssets||(n.brandAssets={}),i==="humanify"){n.brandAssets.humanify=a==="on",n.updatedAt=Date.now(),j(),d(o,200,{ok:!0});return}if(!a){d(o,400,{error:"content is required"});return}if(i!=="styleguide"&&i!=="brandvoice"){d(o,400,{error:`Invalid type: ${i}. Must be "styleguide" or "brandvoice"`});return}n.brandAssets[i]=a,n.updatedAt=Date.now();let r=Pe(n.themePath,".vibespot");ge(r),M(Pe(r,`${i}.md`),a),j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}if(e==="DELETE"){_(t,s=>{try{let{type:i}=JSON.parse(s);if(i!=="styleguide"&&i!=="brandvoice"){d(o,400,{error:`Invalid type: ${i}`});return}n.brandAssets&&delete n.brandAssets[i],n.updatedAt=Date.now();let a=Pe(n.themePath,".vibespot",`${i}.md`);$n(a)&&go(a),j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}d(o,405,{error:"Method not allowed"})}function er(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}_(e,n=>{(async()=>{try{let{sourcePath:s}=n?JSON.parse(n):{},i=s||o.themePath,{extractDesignContext:a}=await Promise.resolve().then(()=>(fo(),po)),r=await a(i);o.brandAssets||(o.brandAssets={}),o.brandAssets.styleguide=r,o.updatedAt=Date.now();let l=Pe(o.themePath,".vibespot");ge(l),M(Pe(l,"styleguide.md"),r),j(),d(t,200,{ok:!0,styleguide:r})}catch(s){d(t,500,{error:s instanceof Error?s.message:String(s)})}})()})}function tr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}_(e,n=>{(async()=>{try{let{source:s,themeName:i,localPath:a}=JSON.parse(n),r;if(s==="hubspot"){if(!i){d(t,400,{error:"themeName is required for HubSpot import"});return}let p=ue();if(!p){d(t,400,{error:"No HubSpot account connected"});return}let f=i.replace(/^\/+|\/+$/g,"");if(!f){d(t,400,{error:"Invalid theme name"});return}let g=f.replace(/[@/]/g,"_").replace(/_+/g,"_"),{homedir:y}=await import("os"),S=Pe(y(),"vibespot-themes",".references",g);ge(S);let{fetchTheme:w}=await Promise.resolve().then(()=>(en(),Go));await w(p,f,S),r=S}else if(s==="local"){if(!a){d(t,400,{error:"localPath is required for local import"});return}if(!$n(a)){d(t,400,{error:`Path not found: ${a}`});return}r=a}else{d(t,400,{error:"source must be 'hubspot' or 'local'"});return}let{extractDesignContext:l}=await Promise.resolve().then(()=>(fo(),po)),c=await l(r);o.brandAssets||(o.brandAssets={}),o.brandAssets.styleguide=c,o.updatedAt=Date.now();let u=Pe(o.themePath,".vibespot");ge(u),M(Pe(u,"styleguide.md"),c),j(),d(t,200,{ok:!0,styleguide:c,source:r})}catch(s){d(t,500,{error:s instanceof Error?s.message:String(s)})}})()})}h();import{join as El}from"path";function nr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}d(t,200,{id:o.id,themeName:o.themeName,themePath:o.themePath,messageCount:o.messages.length,moduleCount:o.modules.length,moduleOrder:o.moduleOrder})}function or(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){let s=be();d(o,200,{modules:s.map(i=>({moduleName:i.moduleName,fieldsJson:i.fieldsJson,moduleHtml:i.moduleHtml,moduleCss:i.moduleCss,moduleJs:i.moduleJs||null})),sharedCss:n.sharedCss,sharedJs:n.sharedJs});return}if(e==="DELETE"){_(t,s=>{let{moduleName:i,deleteEntirely:a}=JSON.parse(s);a?js(i):Ds(i),j(),d(o,200,{ok:!0})});return}d(o,405,{error:"Method not allowed"})}function sr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}_(e,n=>{try{let s=JSON.parse(n);if(s.shared){if(s.shared==="css")o.sharedCss=s.content;else if(s.shared==="js")o.sharedJs=s.content;else{d(t,400,{error:"Invalid shared type"});return}let c=Fe();c&&(s.shared==="css"?c.sharedCss=s.content:c.sharedJs=s.content),o.updatedAt=Date.now(),j(),We(),d(t,200,{ok:!0});return}let{moduleName:i,fileType:a,content:r}=s;if(!i||!a){d(t,400,{error:"moduleName and fileType required"});return}let l=o.modules.find(c=>c.moduleName===i);if(!l){d(t,404,{error:`Module "${i}" not found`});return}switch(a){case"html":l.moduleHtml=r;break;case"css":l.moduleCss=r;break;case"js":l.moduleJs=r||void 0;break;case"fields":try{JSON.parse(r)}catch{d(t,400,{error:"Invalid JSON in fields.json"});return}l.fieldsJson=r;break;default:d(t,400,{error:`Invalid fileType: ${a}`});return}o.updatedAt=Date.now(),j(),We(),d(t,200,{ok:!0})}catch(s){d(t,400,{error:String(s)})}})}function ir(e,t){_(e,o=>{let{order:n}=JSON.parse(o);Array.isArray(n)?(Ms(n),j(),d(t,200,{ok:!0})):d(t,400,{error:"order must be an array"})})}async function rr(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}try{We();let o=mn(t.themePath),n=wn(`hs cms upload "${t.themePath}" "${t.themeName}"`,"Uploading to HubSpot",{cwd:El(t.themePath,".."),timeout:18e4});d(e,200,{ok:!0,jobId:n,fixes:o})}catch(o){d(e,500,{error:String(o)})}}function ar(e,t){_(e,o=>{try{let{moduleName:n,fieldPath:s,value:i}=JSON.parse(o);Js(n,s,i),j(),d(t,200,{ok:!0})}catch(n){d(t,400,{error:String(n)})}})}function lr(e,t){_(e,o=>{try{let{url:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"url is required"});return}let s=Ho(n),i=s.components.map(r=>`- ${r.name}: ${r.description}`).join(`
745
- `),a={sourceDir:s.sourceDir,componentCount:s.components.length,components:s.components.map(r=>({name:r.name,description:r.description})),hasTailwind:s.hasTailwind,cssVarCount:s.cssVarCount,fonts:s.fonts,interactions:s.interactions,conversionPrompt:`Import and convert the React landing page from ${n} to native HubSpot modules.
1299
+ ${r}
1300
+ `)}catch{}}}m(e,200,{ok:!0,message:"API key saved"})}else{let i=at("codex login","Authenticating Codex CLI (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"Complete the sign-in in your browser."})}break}default:m(e,400,{error:`Unknown CLI: ${s}`})}}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function jr(t,e){_(t,n=>{try{let{mode:s}=JSON.parse(n);if(s!=="api"&&s!=="cli"){m(e,400,{error:`Invalid mode: ${s}. Must be "api" or "cli".`});return}Y({hubspotUploadMode:s}),m(e,200,{ok:!0,mode:s})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Fr(t,e){_(t,n=>{try{let{toolId:s,enabled:o}=JSON.parse(n);if(!s||typeof o!="boolean"){m(e,400,{error:"toolId (string) and enabled (boolean) required"});return}no(s,o),m(e,200,{ok:!0,toolId:s,enabled:o})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Jr(t,e){_(t,n=>{try{let s=JSON.parse(n),o=["agenticMode","agenticConcurrency"],i={};for(let a of o)a in s&&(i[a]=s[a]);if(Object.keys(i).length===0){m(e,400,{error:"No valid settings fields provided"});return}Y(i),m(e,200,{ok:!0,updated:Object.keys(i)})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Dr(t,e){let n=t.replace("/api/settings/job/","");if(!n){m(e,400,{error:"Job ID required"});return}let s=Jn(n);if(!s){m(e,404,{error:"Job not found"});return}m(e,200,{id:s.id,status:s.status,description:s.description,output:s.output,exitCode:s.exitCode,startedAt:s.startedAt,completedAt:s.completedAt})}f();import{existsSync as sd,rmSync as od}from"fs";import{join as id}from"path";function Hr(t,e,n){if(t==="GET"){let s=v(),o=bt().sort((i,a)=>a.updatedAt-i.updatedAt);m(n,200,{activeTheme:s?{id:s.id,themeName:s.themeName}:null,sessions:o});return}if(t==="DELETE"){_(e,s=>{try{let{sessionId:o,deleteFiles:i}=JSON.parse(s);gi(o,i),m(n,200,{ok:!0})}catch(o){m(n,500,{error:o instanceof Error?o.message:String(o)})}});return}m(n,405,{error:"Method not allowed"})}function Lr(t,e){_(t,n=>{try{let{sessionId:s}=JSON.parse(n),o=_n(s);if(!o){m(e,404,{error:"Session not found"});return}m(e,200,{ok:!0,themeName:o.themeName,themePath:o.themePath})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Gr(t,e){_(t,n=>{try{let{themeName:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=id($e,s);if(!sd(o)){m(e,404,{error:"Theme not found on disk"});return}od(o,{recursive:!0,force:!0}),m(e,200,{ok:!0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Ur(t,e){_(t,n=>{try{let{sessionId:s,newName:o}=JSON.parse(n);if(!s||!o||typeof o!="string"){m(e,400,{error:"sessionId and newName are required"});return}let i=o.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-|-$/g,"").replace(/-{2,}/g,"-");if(!i){m(e,400,{error:"Invalid name"});return}let a=hi(s,i);a.ok?m(e,200,{ok:!0,newName:i}):m(e,400,{error:a.error})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}f();import{existsSync as Bn,readFileSync as md,rmSync as Gs}from"fs";import{join as Je,basename as pd}from"path";import{execFileSync as fd}from"child_process";ee();X();var gd=process.platform==="win32"?{shell:!0}:{};function Br(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}let n=qe();m(t,200,{themeName:e.themeName,themePath:e.themePath,templates:e.templates.map(s=>({id:s.id,label:s.label,pageType:s.pageType,moduleCount:s.modules.length,messageCount:s.messages.length})),activeTemplateId:e.activeTemplateId,moduleLibrary:n.map(s=>({moduleName:s.module.moduleName,usedIn:s.usedIn})),brandAssets:{hasStyleguide:!!e.brandAssets?.styleguide,hasBrandvoice:!!e.brandAssets?.brandvoice,humanify:e.brandAssets?.humanify!==!1}})}function Kr(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}let n=e.themePath;if(!Bn(n)){m(t,404,{error:"Theme directory not found"});return}let s=e.themeName||"theme",o=Je(n,".."),i=pd(n);try{let a=`${s}.zip`,r=Je(o,a);Bn(r)&&Gs(r),fd("zip",["-r",a,i,"-x",`${i}/.git/*`,`${i}/.vibespot/*`,`${i}/node_modules/*`],{cwd:o,timeout:3e4,...gd});let l=md(r);Gs(r),t.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${a}"`,"Content-Length":l.length}),t.end(l)}catch(a){M.error("download-zip","Failed to create zip archive",a),m(t,500,{error:"Failed to create zip archive"})}}function Vr(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){m(n,200,{templates:s.templates.map(o=>({id:o.id,label:o.label,pageType:o.pageType,moduleCount:o.modules.length})),activeTemplateId:s.activeTemplateId});return}if(t==="POST"){_(e,o=>{try{let{pageType:i,label:a}=JSON.parse(o);if(!i||!a){m(n,400,{error:"pageType and label are required"});return}if(!["landing_page","blog_post","website_page","module_only"].includes(i)){m(n,400,{error:`Invalid pageType: ${i}`});return}let l=di(i,a);j(),m(n,200,{ok:!0,template:{id:l.id,label:l.label,pageType:l.pageType}})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}if(t==="DELETE"){_(e,o=>{try{let{templateId:i}=JSON.parse(o);if(!i){m(n,400,{error:"templateId is required"});return}if(!pi(i)){m(n,404,{error:"Template not found"});return}j(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}m(n,405,{error:"Method not allowed"})}function Yr(t,e){_(t,n=>{try{let{templateId:s}=JSON.parse(n);if(!s){m(e,400,{error:"templateId is required"});return}if(!ls(s)){m(e,404,{error:"Template not found"});return}j();let i=v();m(e,200,{ok:!0,modules:ue().map(a=>a.moduleName),messageCount:i?.messages.length||0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function zr(t,e){_(t,n=>{try{let{templateId:s,newLabel:o}=JSON.parse(n);if(!s||!o||typeof o!="string"){m(e,400,{error:"templateId and newLabel are required"});return}if(!mi(s,o.trim())){m(e,404,{error:"Template not found"});return}j(),m(e,200,{ok:!0,newLabel:o.trim()})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function qr(t,e){_(t,n=>{try{let{templateId:s,label:o}=JSON.parse(n);if(!s){m(e,400,{error:"templateId is required"});return}let i=ui(s,o);if(!i){m(e,404,{error:"Template not found"});return}j(),m(e,200,{ok:!0,template:{id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Xr(t){let e=qe();m(t,200,{modules:e.map(n=>({moduleName:n.module.moduleName,usedIn:n.usedIn,fieldsJson:n.module.fieldsJson}))})}function Qr(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}_(e,o=>{try{let{moduleName:i}=JSON.parse(o);if(!i){m(n,400,{error:"moduleName is required"});return}let r=qe().find(d=>d.module.moduleName===i);if(!r){m(n,404,{error:`Module "${i}" not found in library`});return}let l={...r.module};s.modules.find(d=>d.moduleName===l.moduleName)||(s.modules.push(l),s.moduleOrder.push(l.moduleName),s.updatedAt=Date.now()),j(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}})}function Zr(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){m(n,200,{styleguide:s.brandAssets?.styleguide||null,brandvoice:s.brandAssets?.brandvoice||null});return}if(t==="POST"){_(e,o=>{try{let{type:i,content:a}=JSON.parse(o);if(!i){m(n,400,{error:"type is required"});return}if(s.brandAssets||(s.brandAssets={}),i==="humanify"){s.brandAssets.humanify=a==="on",s.updatedAt=Date.now(),j(),m(n,200,{ok:!0});return}if(!a){m(n,400,{error:"content is required"});return}if(i!=="styleguide"&&i!=="brandvoice"){m(n,400,{error:`Invalid type: ${i}. Must be "styleguide" or "brandvoice"`});return}s.brandAssets[i]=a,s.updatedAt=Date.now();let r=Je(s.themePath,".vibespot");we(r),F(Je(r,`${i}.md`),a),j(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}if(t==="DELETE"){_(e,o=>{try{let{type:i}=JSON.parse(o);if(i!=="styleguide"&&i!=="brandvoice"){m(n,400,{error:`Invalid type: ${i}`});return}s.brandAssets&&delete s.brandAssets[i],s.updatedAt=Date.now();let a=Je(s.themePath,".vibespot",`${i}.md`);Bn(a)&&Gs(a),j(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}m(n,405,{error:"Method not allowed"})}function ea(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}_(t,s=>{(async()=>{try{let{sourcePath:o}=s?JSON.parse(s):{},i=o||n.themePath,{extractDesignContext:a}=await Promise.resolve().then(()=>(Ls(),Hs)),r=await a(i);n.brandAssets||(n.brandAssets={}),n.brandAssets.styleguide=r,n.updatedAt=Date.now();let l=Je(n.themePath,".vibespot");we(l),F(Je(l,"styleguide.md"),r),j(),m(e,200,{ok:!0,styleguide:r})}catch(o){m(e,500,{error:o instanceof Error?o.message:String(o)})}})()})}function ta(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}_(t,s=>{(async()=>{try{let{source:o,themeName:i,localPath:a}=JSON.parse(s),r;if(o==="hubspot"){if(!i){m(e,400,{error:"themeName is required for HubSpot import"});return}let u=he();if(!u){m(e,400,{error:"No HubSpot account connected"});return}let p=i.replace(/^\/+|\/+$/g,"");if(!p){m(e,400,{error:"Invalid theme name"});return}let g=p.replace(/[@/]/g,"_").replace(/_+/g,"_"),{homedir:h}=await import("os"),b=Je(h(),"vibespot-themes",".references",g);we(b);let{fetchTheme:y}=await Promise.resolve().then(()=>(pn(),yo));await y(u,p,b),r=b}else if(o==="local"){if(!a){m(e,400,{error:"localPath is required for local import"});return}if(!Bn(a)){m(e,400,{error:`Path not found: ${a}`});return}r=a}else{m(e,400,{error:"source must be 'hubspot' or 'local'"});return}let{extractDesignContext:l}=await Promise.resolve().then(()=>(Ls(),Hs)),c=await l(r);n.brandAssets||(n.brandAssets={}),n.brandAssets.styleguide=c,n.updatedAt=Date.now();let d=Je(n.themePath,".vibespot");we(d),F(Je(d,"styleguide.md"),c),j(),m(e,200,{ok:!0,styleguide:c,source:r})}catch(o){m(e,500,{error:o instanceof Error?o.message:String(o)})}})()})}f();import{join as hd}from"path";function na(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}m(e,200,{id:n.id,themeName:n.themeName,themePath:n.themePath,messageCount:n.messages.length,moduleCount:n.modules.length,moduleOrder:n.moduleOrder})}function sa(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){let o=ue();m(n,200,{modules:o.map(i=>({moduleName:i.moduleName,fieldsJson:i.fieldsJson,moduleHtml:i.moduleHtml,moduleCss:i.moduleCss,moduleJs:i.moduleJs||null})),sharedCss:s.sharedCss,sharedJs:s.sharedJs});return}if(t==="DELETE"){$s(e,n,o=>{o.deleteEntirely?ii(o.moduleName):ri(o.moduleName),j(),m(n,200,{ok:!0})});return}m(n,405,{error:"Method not allowed"})}function oa(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}_(t,s=>{try{let o=JSON.parse(s);if(o.shared){if(o.shared==="css")n.sharedCss=o.content;else if(o.shared==="js")n.sharedJs=o.content;else{m(e,400,{error:"Invalid shared type"});return}let c=Se();c&&(o.shared==="css"?c.sharedCss=o.content:c.sharedJs=o.content),n.updatedAt=Date.now(),j(),Xe(),m(e,200,{ok:!0});return}let{moduleName:i,fileType:a,content:r}=o;if(!i||!a){m(e,400,{error:"moduleName and fileType required"});return}let l=n.modules.find(c=>c.moduleName===i);if(!l){m(e,404,{error:`Module "${i}" not found`});return}switch(a){case"html":l.moduleHtml=r;break;case"css":l.moduleCss=r;break;case"js":l.moduleJs=r||void 0;break;case"fields":try{JSON.parse(r)}catch{m(e,400,{error:"Invalid JSON in fields.json"});return}l.fieldsJson=r;break;default:m(e,400,{error:`Invalid fileType: ${a}`});return}n.updatedAt=Date.now(),j(),Xe(),m(e,200,{ok:!0})}catch(o){m(e,400,{error:String(o)})}})}function ia(t,e){$s(t,e,n=>{Array.isArray(n.order)?(ht(n.order),j(),m(e,200,{ok:!0})):m(e,400,{error:"order must be an array"})})}async function ra(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}try{Xe();let n=An(e.themePath),s=Dn(`hs cms upload "${e.themePath}" "${e.themeName}"`,"Uploading to HubSpot",{cwd:hd(e.themePath,".."),timeout:18e4});m(t,200,{ok:!0,jobId:s,fixes:n})}catch(n){m(t,500,{error:String(n)})}}function aa(t,e){_(t,n=>{try{let{moduleName:s,fieldPath:o,value:i}=JSON.parse(n);ai(s,o,i),j(),m(e,200,{ok:!0})}catch(s){m(e,400,{error:String(s)})}})}function la(t,e){_(t,n=>{try{let{url:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"url is required"});return}let o=go(s),i=o.components.map(r=>`- ${r.name}: ${r.description}`).join(`
1301
+ `),a={sourceDir:o.sourceDir,componentCount:o.components.length,components:o.components.map(r=>({name:r.name,description:r.description})),hasTailwind:o.hasTailwind,cssVarCount:o.cssVarCount,fonts:o.fonts,interactions:o.interactions,conversionPrompt:`Import and convert the React landing page from ${s} to native HubSpot modules.
746
1302
 
747
- Source analysis found ${s.components.length} components:
1303
+ Source analysis found ${o.components.length} components:
748
1304
  ${i}
749
1305
 
750
- Design system: ${s.hasTailwind?"Tailwind CSS":"Custom CSS"}, ${s.cssVarCount} CSS variables
751
- Fonts: ${s.fonts.length>0?s.fonts.join(", "):"System fonts"}
752
- Interactions: ${s.interactions.join(", ")}
1306
+ Design system: ${o.hasTailwind?"Tailwind CSS":"Custom CSS"}, ${o.cssVarCount} CSS variables
1307
+ Fonts: ${o.fonts.length>0?o.fonts.join(", "):"System fonts"}
1308
+ Interactions: ${o.interactions.join(", ")}
753
1309
 
754
- Read the React source files from ${s.sourceDir} and convert each component to a HubSpot module. Preserve the design, layout, colors, and content. Generate fields.json so marketers can edit all text, images, colors, and links in the HubSpot page editor.`};d(t,200,a)}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function cr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}if(!xe()){d(t,200,{available:!1,commits:[]});return}let s=new URL(e.url||"/","http://localhost").searchParams.get("templateId"),i=s?Is(o.themePath,s,50):As(o.themePath,50);d(t,200,{available:!0,commits:i,filtered:!!s})}function dr(e,t){_(e,o=>{try{let n=$();if(!n){d(t,404,{error:"No active session"});return}let{hash:s,templateId:i}=JSON.parse(o);if(!s||typeof s!="string"){d(t,400,{error:"Commit hash is required"});return}if(ze("assistant",`Rolled back to version ${s.slice(0,7)}.`),i){let a=n.templates.find(c=>c.id===i);if(!a){d(t,404,{error:"Template not found"});return}let r=a.moduleOrder.map(c=>`modules/${c}.module`);a.templateFile&&r.push(a.templateFile);let l=$s(n.themePath,i,s,r);if(!l.success){d(t,500,{error:l.error||"Rollback failed"});return}Gs()}else{let a=Ts(n.themePath,s);if(!a.success){d(t,500,{error:a.error||"Rollback failed"});return}Ls()}j(),d(t,200,{ok:!0,modules:be().map(a=>a.moduleName)})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}var pr={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".ico":"image/x-icon",".woff2":"font/woff2"};function fr(e){let{port:t,uiDir:o}=e,n=Nl((i,a)=>Pl(i,a,o)),s=new Rl({server:n});return s.on("connection",i=>Ml(i)),new Promise((i,a)=>{n.on("error",r=>{r.code==="EADDRINUSE"?n.listen(t+1,()=>{i({port:t+1,close:()=>{n.close(),s.close()}})}):a(r)}),n.listen(t,()=>{i({port:t,close:()=>{n.close(),s.close()}})})})}function Pl(e,t,o){let n=new URL(e.url||"/",`http://${e.headers.host}`),s=e.method||"GET";if(n.pathname.startsWith("/api/")){Ol(s,n.pathname,e,t);return}if(n.pathname==="/preview"){let i=Zs();t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(i);return}if(n.pathname==="/module-preview"){let i=n.searchParams.get("module")||"",a=ei(i);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(a||"<!-- module not found -->");return}if(n.pathname.startsWith("/theme-assets/")){jl(n.pathname.slice(14),t);return}Dl(n.pathname,o,e,t)}function Ol(e,t,o,n){if(n.setHeader("Access-Control-Allow-Origin","*"),n.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),n.setHeader("Access-Control-Allow-Headers","Content-Type"),e==="OPTIONS"){n.writeHead(204),n.end();return}switch(t){case"/api/session":nr(e,n);break;case"/api/modules":or(e,o,n);break;case"/api/modules/reorder":ir(o,n);break;case"/api/modules/code":sr(o,n);break;case"/api/upload":rr(n);break;case"/api/upload-files":e==="POST"?di(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/field":ar(o,n);break;case"/api/import":lr(o,n);break;case"/api/setup":bi(n);break;case"/api/setup/create":Si(o,n);break;case"/api/setup/fetch":vi(o,n);break;case"/api/setup/open":wi(o,n);break;case"/api/setup/resume":xi(o,n);break;case"/api/setup/apikey":Ci(o,n);break;case"/api/setup/remote-themes":e==="GET"?Ai(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/status":e==="GET"?ki(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/engine":e==="POST"?Ei(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/apikey":e==="POST"?Ni(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/install":e==="POST"?_i(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":e==="POST"?Ri(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":e==="POST"?Pi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":e==="POST"?Oi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":e==="POST"?Mi(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":e==="POST"?ji(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-mode":e==="POST"?Di(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-toggle":e==="POST"?Ji(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes":Hi(e,o,n);break;case"/api/themes/switch":e==="POST"?Li(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":e==="POST"?Gi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/rename":e==="POST"?Ui(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/history":e==="GET"?cr(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/rollback":e==="POST"?dr(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/dashboard":e==="GET"?Ki(n):d(n,405,{error:"Method not allowed"});break;case"/api/templates":Yi(e,o,n);break;case"/api/templates/activate":e==="POST"?Vi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/templates/rename":e==="POST"?zi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/templates/clone":e==="POST"?qi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/module-library":e==="GET"?Xi(n):d(n,405,{error:"Method not allowed"});break;case"/api/brand-assets":Zi(e,o,n);break;case"/api/brand-assets/extract":e==="POST"?er(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/brand-assets/import-reference":e==="POST"?tr(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/download-zip":e==="GET"?Bi(n):d(n,405,{error:"Method not allowed"});break;default:t.startsWith("/api/settings/job/")&&e==="GET"?Fi(t,n):t.match(/^\/api\/templates\/[^/]+\/add-module$/)&&e==="POST"?Qi(t,o,n):d(n,404,{error:"Not found"})}}function Ml(e){e.on("message",async o=>{let n;try{n=JSON.parse(o.toString())}catch{e.send(JSON.stringify({type:"error",message:"Invalid JSON"}));return}switch(n.type){case"chat":{let s=String(n.message||"");if(!s.trim())return;ze("user",s),j(),mi(a=>{e.send(JSON.stringify({type:"parse_warning",message:a}))});let i=Array.isArray(n.fileIds)?n.fileIds:void 0;try{await co(s,r=>{e.send(JSON.stringify({type:"stream",content:r}))},r=>{e.send(JSON.stringify({type:"stream_status",content:r}))},i);let a=$();if(a){We();let r=Fe(),l=null;if(r){let c=r.moduleOrder.map(u=>`modules/${u}.module`);r.templateFile&&c.push(r.templateFile),r.sharedCss&&c.push(`css/${a.themeName}-theme.css`),r.sharedJs&&c.push(`js/${a.themeName}-animations.js`),l=Cs(a.themePath,r.id,s,c)}else l=Kn(a.themePath,s);l&&e.send(JSON.stringify({type:"version_created",hash:l}))}e.send(JSON.stringify({type:"generation_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:be().map(r=>r.moduleName)}))}catch(a){e.send(JSON.stringify({type:"error",message:a instanceof Error?a.message:String(a)}))}break}case"start_upload":{let s=$();if(!s){e.send(JSON.stringify({type:"error",message:"No active session"}));break}try{We();let i=mn(s.themePath);if(i.length>0&&e.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i})),(N().hubspotUploadMode||"api")==="api"){let l=ue();if(!l){e.send(JSON.stringify({type:"upload_failed",output:"No HubSpot account configured. Open Settings \u2192 HubSpot to add one.",errors:[{file:"",message:"No HubSpot account configured",fixable:!1}]}));break}e.send(JSON.stringify({type:"upload_started",jobId:"api-upload"}));let c=await pn(l,s.themePath,s.themeName,{onFileStart:u=>{e.send(JSON.stringify({type:"upload_output",chunk:`Uploading ${u}
755
- `}))},onFileComplete:u=>{e.send(JSON.stringify({type:"upload_output",chunk:` \u2713 ${u}
756
- `}))},onFileError:(u,p)=>{e.send(JSON.stringify({type:"upload_output",chunk:` \u2717 ${u}: ${p.message}
757
- `}))},onProgress:(u,p)=>{e.send(JSON.stringify({type:"upload_progress",completed:u,total:p}))}});if(c.success){let u=Ke();e.send(JSON.stringify({type:"upload_complete",output:`Uploaded ${c.uploaded} files`,portalId:u?.portalId||"",dataCenter:u?.dataCenter||"na1",themeName:s.themeName}))}else{let u=dn(c.errors);e.send(JSON.stringify({type:"upload_failed",output:c.errors.map(p=>`${p.file}: ${p.message}`).join(`
758
- `),errors:u}))}}else{let l=wn(`hs cms upload "${s.themePath}" "${s.themeName}"`,"Uploading to HubSpot",{cwd:kn(s.themePath,".."),timeout:18e4});e.send(JSON.stringify({type:"upload_started",jobId:l}));let c=p=>{e.send(JSON.stringify({type:"upload_output",chunk:p}))};fi(l,c);let u=setInterval(()=>{let p=vn(l);if(!(!p||p.status==="running"))if(clearInterval(u),gi(l,c),p.status==="completed"){let f=ke(),g=f.portalId?wt(f.portalId):"na1";e.send(JSON.stringify({type:"upload_complete",output:p.output,portalId:f.portalId||"",dataCenter:g,themeName:s.themeName}))}else{let f=un(p.output);e.send(JSON.stringify({type:"upload_failed",output:p.output,errors:f,exitCode:p.exitCode}))}},500)}}catch(i){e.send(JSON.stringify({type:"error",message:i instanceof Error?i.message:String(i)}))}break}case"upload_fix_with_ai":{let s=String(n.errorContext||"");if(!s.trim()){e.send(JSON.stringify({type:"error",message:"No error context provided"}));break}let i=`The HubSpot upload ("hs cms upload") failed. Below is the upload log output containing the errors.
1310
+ Read the React source files from ${o.sourceDir} and convert each component to a HubSpot module. Preserve the design, layout, colors, and content. Generate fields.json so marketers can edit all text, images, colors, and links in the HubSpot page editor.`};m(e,200,a)}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function ca(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}if(!ke()){m(e,200,{available:!1,commits:[]});return}let o=new URL(t.url||"/","http://localhost").searchParams.get("templateId"),i=o?ti(n.themePath,o,50):ei(n.themePath,50);m(e,200,{available:!0,commits:i,filtered:!!o})}function da(t,e){_(t,n=>{try{let s=v();if(!s){m(e,404,{error:"No active session"});return}let{hash:o,templateId:i}=JSON.parse(n);if(!o||typeof o!="string"){m(e,400,{error:"Commit hash is required"});return}if(ze("assistant",`Rolled back to version ${o.slice(0,7)}.`),i){let a=s.templates.find(c=>c.id===i);if(!a){m(e,404,{error:"Template not found"});return}let r=a.moduleOrder.map(c=>`modules/${c}.module`);a.templateFile&&r.push(a.templateFile);let l=si(s.themePath,i,o,r);if(!l.success){m(e,500,{error:l.error||"Rollback failed"});return}vi()}else{let a=ni(s.themePath,o);if(!a.success){m(e,500,{error:a.error||"Rollback failed"});return}Si()}j(),m(e,200,{ok:!0,modules:ue().map(a=>a.moduleName)})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}var pa={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".ico":"image/x-icon",".woff2":"font/woff2"};function fa(t){let{port:e,uiDir:n}=t,s=yd((i,a)=>vd(i,a,n)),o=new Sd({server:s});return o.on("connection",i=>xd(i)),new Promise((i,a)=>{s.on("error",r=>{r.code==="EADDRINUSE"?s.listen(e+1,()=>{i({port:e+1,close:()=>{s.close(),o.close()}})}):a(r)}),s.listen(e,()=>{i({port:e,close:()=>{s.close(),o.close()}})})})}function vd(t,e,n){let s=new URL(t.url||"/",`http://${t.headers.host}`),o=t.method||"GET";if(e.setHeader("X-Content-Type-Options","nosniff"),e.setHeader("X-Frame-Options","DENY"),e.setHeader("X-XSS-Protection","1; mode=block"),e.setHeader("Referrer-Policy","strict-origin-when-cross-origin"),s.pathname.startsWith("/api/")){wd(o,s.pathname,t,e);return}if(s.pathname==="/preview"){let i=Mi();e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(i);return}if(s.pathname==="/module-preview"){let i=s.searchParams.get("module")||"",a=Ni(i);e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(a||"<!-- module not found -->");return}if(s.pathname.startsWith("/theme-assets/")){Cd(s.pathname.slice(14),e);return}Ad(s.pathname,n,t,e)}function wd(t,e,n,s){let o=n.headers.origin||"";if(/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(o)&&s.setHeader("Access-Control-Allow-Origin",o),s.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),s.setHeader("Access-Control-Allow-Headers","Content-Type"),t==="OPTIONS"){s.writeHead(204),s.end();return}switch(e){case"/api/session":na(t,s);break;case"/api/modules":sa(t,n,s);break;case"/api/modules/reorder":ia(n,s);break;case"/api/modules/code":oa(n,s);break;case"/api/upload":ra(s);break;case"/api/upload-files":t==="POST"?Hi(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/field":aa(n,s);break;case"/api/import":la(n,s);break;case"/api/setup":yr(s);break;case"/api/setup/create":br(n,s);break;case"/api/setup/fetch":Sr(n,s);break;case"/api/setup/open":vr(n,s);break;case"/api/setup/resume":wr(n,s);break;case"/api/setup/apikey":xr(n,s);break;case"/api/setup/remote-themes":t==="GET"?Cr(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/status":t==="GET"?$r(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/engine":t==="POST"?Tr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/apikey":t==="POST"?Er(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/install":t==="POST"?Mr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":t==="POST"?Nr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":t==="POST"?_r(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":t==="POST"?Pr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":t==="POST"?Rr(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":t==="POST"?Or(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-mode":t==="POST"?jr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/cli-toggle":t==="POST"?Fr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings":t==="POST"?Jr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/changelog":t==="GET"?m(s,200,{changelog:qs()}):m(s,405,{error:"Method not allowed"});break;case"/api/themes":Hr(t,n,s);break;case"/api/themes/switch":t==="POST"?Lr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":t==="POST"?Gr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/themes/rename":t==="POST"?Ur(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/history":t==="GET"?ca(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/rollback":t==="POST"?da(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/dashboard":t==="GET"?Br(s):m(s,405,{error:"Method not allowed"});break;case"/api/templates":Vr(t,n,s);break;case"/api/templates/activate":t==="POST"?Yr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/templates/rename":t==="POST"?zr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/templates/clone":t==="POST"?qr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/module-library":t==="GET"?Xr(s):m(s,405,{error:"Method not allowed"});break;case"/api/brand-assets":Zr(t,n,s);break;case"/api/brand-assets/extract":t==="POST"?ea(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/brand-assets/import-reference":t==="POST"?ta(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/download-zip":t==="GET"?Kr(s):m(s,405,{error:"Method not allowed"});break;default:e.startsWith("/api/settings/job/")&&t==="GET"?Dr(e,s):e.match(/^\/api\/templates\/[^/]+\/add-module$/)&&t==="POST"?Qr(e,n,s):m(s,404,{error:"Not found"})}}function xd(t){t.on("message",async n=>{let s;try{s=JSON.parse(n.toString())}catch{t.send(JSON.stringify({type:"error",message:"Invalid JSON"}));return}switch(s.type){case"chat":{let o=String(s.message||"");if(!o.trim())return;ze("user",o),j();let i=Array.isArray(s.fileIds)?s.fileIds:void 0,a=dr();a.needsPrompt&&t.send(JSON.stringify({type:"agentic_prompt"}));try{if(a.useAgentic){let l=[],c=[],d=await lr(o,u=>{if(u.type==="module_progress"&&u.moduleFiles){let{moduleFiles:p,...g}=u;t.send(JSON.stringify(g))}else t.send(JSON.stringify(u));if(u.type==="agent_step")l.push({step:u.step,label:u.label});else if(u.type==="agent_decision"){let p=l[l.length-1];p&&(p.decisions||(p.decisions=[]),p.decisions.push(u.decision))}else u.type==="design_system_ready"?Oe({sharedCss:u.sharedCss,sharedJs:u.sharedJs}):u.type==="blueprint_ready"?(Oe({sharedCss:u.sharedCss,sharedJs:u.sharedJs}),ht(u.moduleOrder),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(p=>p.moduleName)}))):u.type==="module_progress"&&u.status==="complete"&&u.moduleFiles?(Oe({modules:[{moduleName:u.module,fieldsJson:u.moduleFiles.fieldsJson,metaJson:u.moduleFiles.metaJson,moduleHtml:u.moduleFiles.moduleHtml,moduleCss:u.moduleFiles.moduleCss,moduleJs:u.moduleFiles.moduleJs}]}),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(p=>p.moduleName)})),c.push({name:u.module,status:"complete"})):u.type==="module_progress"&&u.status==="failed"&&c.push({name:u.module,status:"failed"})},i);cr(d,{steps:l,modules:c,stats:d.stats})}else ar(l=>{t.send(JSON.stringify({type:"parse_warning",message:l}))}),await Os(o,l=>{t.send(JSON.stringify({type:"stream",content:l}))},l=>{t.send(JSON.stringify({type:"stream_status",content:l}))},i);let r=v();if(r){Xe();let l=Se(),c=null;if(l){let d=l.moduleOrder.map(u=>`modules/${u}.module`);l.templateFile&&d.push(l.templateFile),l.sharedCss&&d.push(`css/${r.themeName}-theme.css`),l.sharedJs&&d.push(`js/${r.themeName}-animations.js`),c=Zo(r.themePath,l.id,o,d)}else c=rs(r.themePath,o);c&&t.send(JSON.stringify({type:"version_created",hash:c}))}t.send(JSON.stringify({type:"generation_complete"})),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(l=>l.moduleName)}))}catch(r){t.send(JSON.stringify({type:"error",message:r instanceof Error?r.message:String(r)}))}break}case"start_upload":{let o=v();if(!o){t.send(JSON.stringify({type:"error",message:"No active session"}));break}try{Xe();let i=An(o.themePath);if(i.length>0&&t.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i})),(E().hubspotUploadMode||"api")==="api"){let l=he();if(!l){t.send(JSON.stringify({type:"upload_failed",output:"No HubSpot account configured. Open Settings \u2192 HubSpot to add one.",errors:[{file:"",message:"No HubSpot account configured",fixable:!1}]}));break}t.send(JSON.stringify({type:"upload_started",jobId:"api-upload"}));let c=await In(l,o.themePath,o.themeName,{onFileStart:d=>{t.send(JSON.stringify({type:"upload_output",chunk:`Uploading ${d}
1311
+ `}))},onFileComplete:d=>{t.send(JSON.stringify({type:"upload_output",chunk:` \u2713 ${d}
1312
+ `}))},onFileError:(d,u)=>{t.send(JSON.stringify({type:"upload_output",chunk:` \u2717 ${d}: ${u.message}
1313
+ `}))},onProgress:(d,u)=>{t.send(JSON.stringify({type:"upload_progress",completed:d,total:u}))}});if(c.success){let d=Ze();t.send(JSON.stringify({type:"upload_complete",output:`Uploaded ${c.uploaded} files`,portalId:d?.portalId||"",dataCenter:d?.dataCenter||"na1",themeName:o.themeName}))}else{let d=xn(c.errors);t.send(JSON.stringify({type:"upload_failed",output:c.errors.map(u=>`${u.file}: ${u.message}`).join(`
1314
+ `),errors:d}))}}else{let l=Dn(`hs cms upload "${o.themePath}" "${o.themeName}"`,"Uploading to HubSpot",{cwd:Kn(o.themePath,".."),timeout:18e4});t.send(JSON.stringify({type:"upload_started",jobId:l}));let c=u=>{t.send(JSON.stringify({type:"upload_output",chunk:u}))};mr(l,c);let d=setInterval(()=>{let u=Jn(l);if(!(!u||u.status==="running"))if(clearInterval(d),pr(l,c),u.status==="completed"){let p=Ne(),g=p.portalId?Et(p.portalId):"na1";t.send(JSON.stringify({type:"upload_complete",output:u.output,portalId:p.portalId||"",dataCenter:g,themeName:o.themeName}))}else{let p=Cn(u.output);t.send(JSON.stringify({type:"upload_failed",output:u.output,errors:p,exitCode:u.exitCode}))}},500)}}catch(i){t.send(JSON.stringify({type:"error",message:i instanceof Error?i.message:String(i)}))}break}case"upload_fix_with_ai":{let o=String(s.errorContext||"");if(!o.trim()){t.send(JSON.stringify({type:"error",message:"No error context provided"}));break}let i=`The HubSpot upload ("hs cms upload") failed. Below is the upload log output containing the errors.
759
1315
 
760
1316
  IMPORTANT: Be verbose in your response. For each error:
761
1317
  1. State exactly which file has the problem and what the error is
@@ -768,9 +1324,9 @@ CRITICAL: After fixing the reported errors, scan ALL other module files in the t
768
1324
  After fixing all errors, summarize the changes you made.
769
1325
 
770
1326
  Upload log:
771
- ${s}`;ze("user",i),j(),e.send(JSON.stringify({type:"upload_fix_started"}));try{await co(i,r=>{e.send(JSON.stringify({type:"stream",content:r})),e.send(JSON.stringify({type:"upload_fix_stream",content:r}))});let a=$();if(a){We();let r=Kn(a.themePath,"AI fix: upload errors");r&&e.send(JSON.stringify({type:"version_created",hash:r}))}e.send(JSON.stringify({type:"upload_fix_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:be().map(r=>r.moduleName)}))}catch(a){e.send(JSON.stringify({type:"upload_failed",output:a instanceof Error?a.message:String(a),errors:[{file:"AI fix",message:a instanceof Error?a.message:String(a),fixable:!1}]}))}break}case"ping":e.send(JSON.stringify({type:"pong"}));break;default:e.send(JSON.stringify({type:"error",message:`Unknown type: ${n.type}`}))}});let t=$();if(t){let o=N(),n={"claude-code":"Claude Code","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-cli":"Gemini CLI","gemini-api":"Gemini API","codex-cli":"Codex CLI",api:"Anthropic API"},s=Fe();e.send(JSON.stringify({type:"init",sessionId:t.id,themeName:t.themeName,modules:be().map(i=>i.moduleName),messageCount:t.messages.length,messages:t.messages,gitAvailable:xe(),engine:o.aiEngine?n[o.aiEngine]||o.aiEngine:"",templateId:s?.id||null,pageType:s?.pageType||null,templates:(t.templates||[]).map(i=>({id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}))}))}else e.send(JSON.stringify({type:"needs_setup"}))}function jl(e,t){let o=$();if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("No session");return}let n=kn(o.themePath,"assets",e);if(!yo(n)){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Asset not found");return}let s=mr(n),i=pr[s]||"application/octet-stream",a=ho(n);t.writeHead(200,{"Content-Type":i,"Cache-Control":"no-cache"}),t.end(a)}var ur=new Map;function Dl(e,t,o,n){let i=kn(t,e==="/"?"/index.html":e);if(!yo(i)){let c=kn(t,"index.html");if(yo(c)){let u=ho(c);n.writeHead(200,{"Content-Type":"text/html","Cache-Control":"no-cache"}),n.end(u)}else n.writeHead(404,{"Content-Type":"text/plain"}),n.end("Not found");return}let a=mr(i),r=pr[a]||"application/octet-stream",l=a===".html";try{let c=ur.get(i);if(!c){let p=ho(i),f='"'+_l("md5").update(p).digest("hex").slice(0,16)+'"';c={buffer:p,etag:f,contentType:r},ur.set(i,c)}if(o.headers["if-none-match"]===c.etag){n.writeHead(304),n.end();return}n.writeHead(200,{"Content-Type":c.contentType,"Cache-Control":l?"no-cache":"public, max-age=3600",ETag:c.etag}),n.end(c.buffer)}catch{n.writeHead(500,{"Content-Type":"text/plain"}),n.end("Internal Server Error")}}var Fl=4200;async function gr(){let e=Nn.hex("#e8613a"),t=Nn.dim;console.log(""),console.log(e(" v vibeSpot")),console.log(t(` Starting...
772
- `));let o=Hl();o||(console.error(Nn.red(" Could not find UI assets. Is the package installed correctly?")),process.exit(1));try{let{port:n,close:s}=await fr({port:Fl,uiDir:o}),i=`http://localhost:${n}`;console.log(e(` v ${i}`)),console.log(t(` Press Ctrl+C to stop
773
- `));try{process.platform==="darwin"?bo(`open "${i}"`,{stdio:"ignore"}):process.platform==="win32"?bo(`cmd /c start "" "${i}"`,{stdio:"ignore"}):bo(`xdg-open "${i}"`,{stdio:"ignore"})}catch{}await new Promise(a=>{process.on("SIGINT",()=>{console.log(t(`
774
- Saving session...`)),j(),s(),console.log(t(` Goodbye!
775
- `)),a(),setTimeout(()=>process.exit(0),500)})})}catch(n){console.error(Nn.red(` Failed to start: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}function Hl(){let e=[En(import.meta.dirname,"../../ui"),En(import.meta.dirname,"../ui"),En(process.cwd(),"ui")];for(let t of e)if(Jl(En(t,"index.html")))return t;return null}Q();function hr(){let e=new Ll;return e.name("vibespot").description("AI-powered HubSpot CMS landing page builder").version(ot()).action(gr),e.command("wizard").description("Classic CLI wizard \u2014 step-by-step conversion flow").action(ys),e.command("init").description("Check and install required tools").action(bs),e.command("convert").description("Convert a React project to HubSpot modules").action(Ss),e.command("upload").description("Upload theme to HubSpot").action(vs),e.command("doctor").description("Diagnose environment issues").action(ws),e}var Gl=hr();Gl.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
1327
+ ${o}`;ze("user",i),j(),t.send(JSON.stringify({type:"upload_fix_started"}));try{await Os(i,r=>{t.send(JSON.stringify({type:"stream",content:r})),t.send(JSON.stringify({type:"upload_fix_stream",content:r}))});let a=v();if(a){Xe();let r=rs(a.themePath,"AI fix: upload errors");r&&t.send(JSON.stringify({type:"version_created",hash:r}))}t.send(JSON.stringify({type:"upload_fix_complete"})),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(r=>r.moduleName)}))}catch(a){t.send(JSON.stringify({type:"upload_failed",output:a instanceof Error?a.message:String(a),errors:[{file:"AI fix",message:a instanceof Error?a.message:String(a),fixable:!1}]}))}break}case"ping":t.send(JSON.stringify({type:"pong"}));break;default:t.send(JSON.stringify({type:"error",message:`Unknown type: ${s.type}`}))}});let e=v();if(e){let n=E(),s={"claude-code":"Claude Code","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-cli":"Gemini CLI","gemini-api":"Gemini API","codex-cli":"Codex CLI",api:"Anthropic API"},o=Se();t.send(JSON.stringify({type:"init",sessionId:e.id,themeName:e.themeName,modules:ue().map(i=>i.moduleName),messageCount:e.messages.length,messages:e.messages,gitAvailable:ke(),engine:n.aiEngine?s[n.aiEngine]||n.aiEngine:"",templateId:o?.id||null,pageType:o?.pageType||null,templates:(e.templates||[]).map(i=>({id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}))}))}else t.send(JSON.stringify({type:"needs_setup"}))}function Cd(t,e){let n=v();if(!n){e.writeHead(404,{"Content-Type":"text/plain"}),e.end("No session");return}let s=Kn(n.themePath,"assets",t);if(!Ws(s)){e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Asset not found");return}let o=ma(s),i=pa[o]||"application/octet-stream",a=Us(s);e.writeHead(200,{"Content-Type":i,"Cache-Control":"no-cache"}),e.end(a)}var ua=new Map;function Ad(t,e,n,s){let i=Kn(e,t==="/"?"/index.html":t);if(!Ws(i)){let c=Kn(e,"index.html");if(Ws(c)){let d=Us(c);s.writeHead(200,{"Content-Type":"text/html","Cache-Control":"no-cache"}),s.end(d)}else s.writeHead(404,{"Content-Type":"text/plain"}),s.end("Not found");return}let a=ma(i),r=pa[a]||"application/octet-stream",l=a===".html";try{let c=ua.get(i);if(!c){let u=Us(i),p='"'+bd("md5").update(u).digest("hex").slice(0,16)+'"';c={buffer:u,etag:p,contentType:r},ua.set(i,c)}if(n.headers["if-none-match"]===c.etag){s.writeHead(304),s.end();return}s.writeHead(200,{"Content-Type":c.contentType,"Cache-Control":l?"no-cache":"public, max-age=3600",ETag:c.etag}),s.end(c.buffer)}catch{s.writeHead(500,{"Content-Type":"text/plain"}),s.end("Internal Server Error")}}var kd=4200;async function ga(){let t=Yn.hex("#e8613a"),e=Yn.dim;console.log(""),console.log(t(" v vibeSpot")),console.log(e(` Starting...
1328
+ `));let n=$d();n||(console.error(Yn.red(" Could not find UI assets. Is the package installed correctly?")),process.exit(1));try{let{port:s,close:o}=await fa({port:kd,uiDir:n}),i=`http://localhost:${s}`;console.log(t(` v ${i}`)),console.log(e(` Press Ctrl+C to stop
1329
+ `));try{process.platform==="darwin"?Bs("open",[i],{stdio:"ignore"}):process.platform==="win32"?Bs("cmd",["/c","start","",i],{stdio:"ignore"}):Bs("xdg-open",[i],{stdio:"ignore"})}catch{}await new Promise(a=>{process.on("SIGINT",()=>{console.log(e(`
1330
+ Saving session...`)),j(),o(),console.log(e(` Goodbye!
1331
+ `)),a(),setTimeout(()=>process.exit(0),500)})})}catch(s){console.error(Yn.red(` Failed to start: ${s instanceof Error?s.message:String(s)}`)),process.exit(1)}}function $d(){let t=[Vn(import.meta.dirname,"../../ui"),Vn(import.meta.dirname,"../ui"),Vn(process.cwd(),"ui")];for(let e of t)if(Id(Vn(e,"index.html")))return e;return null}X();function ha(){let t=new Td;return t.name("vibespot").description("AI-powered HubSpot CMS landing page builder").version(ut()).action(ga),t.command("wizard").description("Classic CLI wizard \u2014 step-by-step conversion flow").action(Ko),t.command("init").description("Check and install required tools").action(Vo),t.command("convert").description("Convert a React project to HubSpot modules").action(Yo),t.command("upload").description("Upload theme to HubSpot").action(zo),t.command("doctor").description("Diagnose environment issues").action(qo),t}var Ed=ha();Ed.parseAsync(process.argv).catch(t=>{console.error(t),process.exit(1)});
776
1332
  //# sourceMappingURL=index.js.map