vibespot 0.7.1 → 0.9.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,34 +1,65 @@
1
- import{Command as Ur}from"commander";import Ge from"chalk";var ye={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},$n=!!process.env.NO_COLOR;function ke(e){return $n?Ge:Ge.hex(e)}var S={accent:ke(ye.accent),accentBright:ke(ye.accentBright),success:ke(ye.success),info:ke(ye.info),warn:ke(ye.warn),error:ke(ye.error),muted:ke(ye.muted),vibes:ke(ye.vibes),heading:$n?Ge.bold:Ge.bold.hex(ye.accent),command:ke(ye.accentBright),dim:Ge.dim,bold:Ge.bold};var Xs="0.7.1";function be(){let e=S.vibes,t=S.accent,o=S.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")} ${S.dim(`v${Xs}`)}`),console.log()}import{join as ft}from"path";import{homedir as gt}from"os";import{readFileSync as Pn,existsSync as ht,readdirSync as si}from"fs";import{execSync as En}from"child_process";function x(e,t={}){try{return{stdout:En(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 Tn(e,t={}){try{return En(e,{stdio:"inherit",timeout:3e5,...t}),!0}catch{return!1}}import{join as On}from"path";import{homedir as ni}from"os";import{readFileSync as Zs,writeFileSync as ei,mkdirSync as Nn,existsSync as _n}from"fs";import{dirname as ti,join as Bt}from"path";function b(e){return Zs(e,"utf-8")}function E(e,t){Nn(ti(e),{recursive:!0}),ei(e,t,"utf-8")}function g(e){return _n(e)}function $e(e){Nn(e,{recursive:!0})}function Rn(e){let t=[Bt(import.meta.dirname,"../../assets",e),Bt(import.meta.dirname,"../assets",e),Bt(process.cwd(),"assets",e)];for(let o of t)if(_n(o))return o;throw new Error(`Asset not found: ${e}`)}var oi=On(ni(),".vibespot"),Yt=On(oi,"config.json");function j(){if(!g(Yt))return{};try{let e=JSON.parse(b(Yt));return e.aiEngine==="api"&&(e.aiEngine="anthropic-api"),e}catch{return{}}}function je(e,t){let o=t||j();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 Vt(e){return e.length<=12?"***":e.slice(0,7)+"..."+e.slice(-4)}function ne(e){let o={...j(),...e};E(Yt,JSON.stringify(o,null,2))}var Me=process.platform==="win32"?"where":"which";function tt(){let e=x("node --version");return{name:"Node.js",found:e.success,version:e.stdout.replace(/^v/,""),path:x(`${Me} node`).stdout}}function nt(){let e=x("git --version");return{name:"Git",found:e.success,version:e.stdout.replace("git version ",""),path:x(`${Me} git`).stdout}}function Ee(){let e=x("hs --version");return{name:"HubSpot CLI",found:e.success,version:e.stdout,path:x(`${Me} hs`).stdout}}function ot(){let e=x("claude --version");if(!e.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=ft(gt(),".claude"),o=!1,n="Not signed in \u2014 run `claude` to authenticate";try{if(ht(t)){let s=si(t);(s.some(r=>r.includes("credentials")||r.includes("auth")||r.includes("token")||r===".credentials.json")||s.length>2)&&(o=!0,n="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:e.stdout,path:x(`${Me} claude`).stdout,authenticated:o,authDetail:n}}function yt(e){try{let t=ft(gt(),".hscli","config.yml");if(!ht(t))return"na1";let o=Pn(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 r=o.slice(s,s+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!r)return"na1";if(r[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function ve(){let e=x("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(`
2
- `);for(let r of i){let a=r.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(a&&!/Account ID/i.test(r)&&!/^-+$/.test(r.trim())&&!/^Name\s/i.test(r.trim())){let l=a[1].trim(),c=a[2].trim(),u=a[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 st(){let e=x("gemini --version");if(!e.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=ft(gt(),".config","gcloud","application_default_credentials.json"),o=ht(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:x(`${Me} gemini`).stdout,authenticated:s,authDetail:s?"Authenticated":"Run `gemini` to sign in with Google"}}function it(){let e=x("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=ft(gt(),".codex","auth.json");ht(i)&&(o=Pn(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:x(`${Me} codex`).stdout,authenticated:n,authDetail:s}}function zt(){let e=x("gh --version");return{name:"GitHub CLI",found:e.success,version:e.stdout.split(`
3
- `)[0]?.replace("gh version ","").split(" ")[0]||"",path:x(`${Me} gh`).stdout}}function qt(){let e=x("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 jn(){return!!process.env.ANTHROPIC_API_KEY}function bt(e){return parseInt(e.split(".")[0],10)>=18}function Mn(e){let t=parseInt(e.split(".")[0],10);return!isNaN(t)&&t>=8}function vt(){let e=j(),t=tt(),o=nt(),n=Ee(),s=n.found?ve():{authenticated:!1,portalName:"",portalId:"",accounts:[]},i=zt(),r=i.found?qt():{authenticated:!1,username:""},a=ot(),l=st(),c=it();function u(v,...N){if(v)return{configured:!0,masked:Vt(v),source:"config"};for(let K of N)if(process.env[K])return{configured:!0,masked:Vt(process.env[K]),source:"env"};return{configured:!1,masked:"",source:null}}let p=u(e.anthropicApiKey,"ANTHROPIC_API_KEY"),f=u(e.openaiApiKey,"OPENAI_API_KEY"),y=u(e.geminiApiKey,"GEMINI_API_KEY","GOOGLE_AI_API_KEY"),h=[];return a.found&&a.authenticated&&h.push("claude-code"),p.configured&&h.push("anthropic-api"),f.configured&&h.push("openai-api"),l.found&&l.authenticated&&h.push("gemini-cli"),y.configured&&h.push("gemini-api"),c.found&&c.authenticated&&h.push("codex-cli"),{tools:{node:t,git:o,hubspot:{...n,...s},github:{...i,...r},claudeCode:a,geminiCli:l,codexCli:c},apiKeys:{anthropic:p,openai:f,gemini:y},activeEngine:e.aiEngine||null,availableEngines:h}}import*as M from"@clack/prompts";function Qt(e){M.isCancel(e)&&(M.cancel(S.muted("Operation cancelled.")),process.exit(0))}async function Q(e){M.intro(S.heading(e))}async function X(e){M.outro(S.success(e))}async function ue(e,t){M.note(e,t?S.heading(t):void 0)}async function Se(e){let t=await M.text({message:S.accent(e.message),placeholder:e.placeholder,defaultValue:e.defaultValue,validate:e.validate});return Qt(t),t}async function B(e){let t=await M.confirm({message:S.accent(e.message),initialValue:e.initialValue??!0});return Qt(t),t}async function We(e){let t=await M.select({message:S.accent(e.message),options:e.options});return Qt(t),t}async function oe(){let e=M.spinner();return{start:t=>e.start(S.muted(t)),stop:t=>e.stop(S.success(t)),message:t=>e.message(S.muted(t))}}function G(e){M.log.info(e)}function k(e){M.log.success(S.success(e))}function J(e){M.log.warn(S.warn(e))}function T(e){M.log.error(S.error(e))}async function St(){await Q("Checking your environment");let e=tt();e.found||(T("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),bt(e.version)||(T(`Node.js ${e.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),k(`Node.js v${e.version}`);let t=nt();t.found||(T("Git not found. Install it from https://git-scm.com"),process.exit(1)),k(`Git ${t.version}`);let o=Ee();if(o.found)k(`HubSpot CLI v${o.version}`);else{J("HubSpot CLI not found"),await ue(`The HubSpot CLI is required to upload your theme.
4
- I'll install it for you now.`,"Missing dependency"),await B({message:"Install HubSpot CLI globally?"})||(T("HubSpot CLI is required. Install manually: npm install -g @hubspot/cli"),process.exit(1));let v=await oe();v.start("Installing HubSpot CLI..."),x("npm install -g @hubspot/cli").success||(v.stop("Failed to install HubSpot CLI"),T("Try running manually: npm install -g @hubspot/cli"),process.exit(1)),o=Ee(),v.stop(`HubSpot CLI v${o.version} installed`)}let n=ve();if(n.authenticated)k(`HubSpot portal${n.portalName?`: ${n.portalName}`:""} (ID: ${n.portalId})`);else{J("HubSpot not authenticated"),await ue(`You need to connect the CLI to your HubSpot account.
5
- This will open a browser window \u2014 log in and authorize.`,"Authentication required"),await B({message:"Run `hs init` now?"})||(T("HubSpot authentication is required. Run `hs init` manually."),process.exit(1));let v=await oe();v.start("Waiting for HubSpot authentication..."),Tn("hs init")||(v.stop("Authentication failed"),T("HubSpot authentication failed. Try running `hs init` manually."),process.exit(1)),n=ve(),v.stop(`Connected to portal${n.portalName?`: ${n.portalName}`:""} (ID: ${n.portalId})`)}let s=ot(),i=st(),r=it(),a=jn(),l=j(),c={"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=l.aiEngine,f=[];if(s.found&&f.push({value:"claude-code",label:"Claude Code",hint:p==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),i.found&&f.push({value:"gemini-cli",label:"Gemini CLI",hint:p==="gemini-cli"?"last used":"uses your existing Gemini setup"}),r.found&&f.push({value:"codex-cli",label:"OpenAI Codex",hint:p==="codex-cli"?"last used":"uses your existing OpenAI setup"}),a&&f.push({value:"api",label:"Anthropic API",hint:p==="api"?"last used":"uses your API key"}),p&&f.sort((h,v)=>h.value===p?-1:v.value===p?1:0),f.length===1)u=f[0].value,k(`AI engine: ${c[u]} (auto-detected)`);else if(f.length>1)u=await We({message:"Choose your AI engine:",options:f});else if(await ue(`You need an AI coding assistant to power the conversion.
1
+ import{Command as ll}from"commander";import Ke from"chalk";var ve={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},Zn=!!process.env.NO_COLOR;function Te(e){return Zn?Ke:Ke.hex(e)}var v={accent:Te(ve.accent),accentBright:Te(ve.accentBright),success:Te(ve.success),info:Te(ve.info),warn:Te(ve.warn),error:Te(ve.error),muted:Te(ve.muted),vibes:Te(ve.vibes),heading:Zn?Ke.bold:Ke.bold.hex(ve.accent),command:Te(ve.accentBright),dim:Ke.dim,bold:Ke.bold};var Ki="0.7.1";function we(){let e=v.vibes,t=v.accent,o=v.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")} ${v.dim(`v${Ki}`)}`),console.log()}import{join as kt}from"path";import{homedir as Et}from"os";import{readFileSync as co,existsSync as Nt,readdirSync as Xi}from"fs";import{execSync as eo}from"child_process";function x(e,t={}){try{return{stdout:eo(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 to(e,t={}){try{return eo(e,{stdio:"inherit",timeout:3e5,...t}),!0}catch{return!1}}import{join as io}from"path";import{homedir as zi}from"os";import{readFileSync as Bi,writeFileSync as Yi,mkdirSync as no,existsSync as oo}from"fs";import{dirname as Vi,join as fn}from"path";function b(e){return Bi(e,"utf-8")}function O(e,t){no(Vi(e),{recursive:!0}),Yi(e,t,"utf-8")}function h(e){return oo(e)}function ke(e){no(e,{recursive:!0})}function so(e){let t=[fn(import.meta.dirname,"../../assets",e),fn(import.meta.dirname,"../assets",e),fn(process.cwd(),"assets",e)];for(let o of t)if(oo(o))return o;throw new Error(`Asset not found: ${e}`)}var qi=io(zi(),".vibespot"),gn=io(qi,"config.json");function N(){if(!h(gn))return{};try{let e=JSON.parse(b(gn));return e.aiEngine==="api"&&(e.aiEngine="anthropic-api"),e}catch{return{}}}function Me(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 hn(e){return e.length<=12?"***":e.slice(0,7)+"..."+e.slice(-4)}function Y(e){let o={...N(),...e};O(gn,JSON.stringify(o,null,2))}function Fe(){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 $t(e,t,o,n){let i=N().hubspotAccounts||[],r=i.findIndex(l=>l.portalId===t),a={portalId:t,portalName:o,personalAccessKey:e,dataCenter:n,addedAt:new Date().toISOString()};r>=0?i[r]=a:i.push(a),Y({hubspotAccounts:i,activeHubSpotAccount:t})}function ro(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),Y(n)}function ao(e){Y({activeHubSpotAccount:e})}function fe(){return Fe()?.personalAccessKey||null}function Tt(e){return N().enabledCLITools?.includes(e)??!1}function lo(e,t){let o=N(),n=new Set(o.enabledCLITools||[]);t?n.add(e):n.delete(e),Y({enabledCLITools:[...n]})}var Je=process.platform==="win32"?"where":"which";function lt(){let e=x("node --version");return{name:"Node.js",found:e.success,version:e.stdout.replace(/^v/,""),path:x(`${Je} node`).stdout}}function ct(){let e=x("git --version");return{name:"Git",found:e.success,version:e.stdout.replace("git version ",""),path:x(`${Je} git`).stdout}}function xe(){let e=x("hs --version");return{name:"HubSpot CLI",found:e.success,version:e.stdout,path:x(`${Je} hs`).stdout}}function dt(){let e=x("claude --version");if(!e.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=kt(Et(),".claude"),o=!1,n="Not signed in \u2014 run `claude` to authenticate";try{if(Nt(t)){let s=Xi(t);(s.some(r=>r.includes("credentials")||r.includes("auth")||r.includes("token")||r===".credentials.json")||s.length>2)&&(o=!0,n="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:e.stdout,path:x(`${Je} claude`).stdout,authenticated:o,authDetail:n}}function ut(e){try{let t=kt(Et(),".hscli","config.yml");if(!Nt(t))return"na1";let o=co(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 r=o.slice(s,s+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!r)return"na1";if(r[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function Ce(){let e=x("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(`
2
+ `);for(let r of i){let a=r.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(a&&!/Account ID/i.test(r)&&!/^-+$/.test(r.trim())&&!/^Name\s/i.test(r.trim())){let l=a[1].trim(),c=a[2].trim(),u=a[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 mt(){let e=x("gemini --version");if(!e.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=kt(Et(),".config","gcloud","application_default_credentials.json"),o=Nt(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:x(`${Je} gemini`).stdout,authenticated:s,authDetail:s?"Authenticated":"Run `gemini` to sign in with Google"}}function pt(){let e=x("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=kt(Et(),".codex","auth.json");Nt(i)&&(o=co(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:x(`${Je} codex`).stdout,authenticated:n,authDetail:s}}function bn(){let e=x("gh --version");return{name:"GitHub CLI",found:e.success,version:e.stdout.split(`
3
+ `)[0]?.replace("gh version ","").split(" ")[0]||"",path:x(`${Je} gh`).stdout}}function Sn(){let e=x("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 uo(){return!!process.env.ANTHROPIC_API_KEY}function _t(e){return parseInt(e.split(".")[0],10)>=18}function mo(e){let t=parseInt(e.split(".")[0],10);return!isNaN(t)&&t>=8}function Qi(){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=Fe();return{authenticated:!!s,portalName:s?.portalName||"",portalId:s?.portalId||"",dataCenter:s?s.dataCenter:"na1",accounts:n,uploadMode:t}}var yn={name:"",found:!1,version:"",path:"",authenticated:!1,authDetail:"Disabled"};function Rt(){let e=N(),t=lt(),o=ct(),n=e.hubspotUploadMode||"api",s;if(n==="cli"){let C=xe(),T=C.found?Ce():{authenticated:!1,portalName:"",portalId:"",accounts:[]},k=T.portalId?ut(T.portalId):"na1";s={...C,...T,dataCenter:k,uploadMode:"cli"}}else s={name:"HubSpot API",found:!0,version:"v3",path:"",...Qi()};let i=bn(),r=i.found?Sn():{authenticated:!1,username:""},a=e.enabledCLITools||[],l=Tt("claude-code")?dt():{...yn,name:"Claude Code"},c=Tt("gemini-cli")?mt():{...yn,name:"Gemini CLI"},u=Tt("codex-cli")?pt():{...yn,name:"OpenAI Codex CLI"};function p(C,...T){if(C)return{configured:!0,masked:hn(C),source:"config"};for(let k of T)if(process.env[k])return{configured:!0,masked:hn(process.env[k]),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,...r},claudeCode:l,geminiCli:c,codexCli:u},apiKeys:{anthropic:f,openai:g,gemini:y},activeEngine:e.aiEngine||null,availableEngines:S,enabledCLITools:a}}import{readFileSync as Zi}from"fs";import{basename as er}from"path";var Ee="https://api.hubapi.com",tr=3,nr=1e3,or=300*1e3,po=new Map;async function fo(e){let t=po.get(e);if(t&&t.expiresAt-Date.now()>or)return t;let o=await fetch(`${Ee}/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 po.set(e,s),s}async function Be(e){let{accessToken:t}=await fo(e);return{Authorization:`Bearer ${t}`}}function Pt(e){return e.replace(/^\/+/,"").split("/").filter(Boolean).map(encodeURIComponent).join("/")}function sr(e){return e.startsWith("pat-eu1-")?"eu1":e.startsWith("pat-na1-")?"na1":e.startsWith("CiRldTE")?"eu1":"na1"}function ir(e){return new Promise(t=>setTimeout(t,e))}async function ft(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 r=i.errors[0];s=r.message||JSON.stringify(r)}}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 gt(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=nr*Math.pow(2,n);await ir(i);continue}return s}return fetch(e,t)}async function Ot(e){let t=await fo(e),o=`${Ee}/account-info/v3/details`,n=await gt(o,{headers:await Be(e)});if(!n.ok){let a=await ft(n);throw new Error(`Failed to get account info: ${a.message}`)}let s=await n.json(),i=String(s.portalId||t.hubId||""),r=t.hubName||s.uiDomain||i;return{portalId:i,portalName:r,dataCenter:sr(e)}}async function go(e,t,o){let n=Zi(o),s=er(o),i=new FormData,r=new Blob([n]);i.append("file",r,s);let a=`${Ee}/cms/v3/source-code/draft/content/${Pt(t)}`,l=await gt(a,{method:"PUT",headers:await Be(e),body:i});if(!l.ok){let c=await ft(l,t);return{success:!1,path:t,error:c}}return{success:!0,path:t}}async function vn(e,t){let o=`${Ee}/cms/v3/source-code/draft/content/${Pt(t)}`,n=await gt(o,{method:"DELETE",headers:await Be(e)});if(!n.ok&&n.status!==404){let s=await ft(n,t);throw new Error(`Failed to delete ${t}: ${s.message}`)}}async function ho(e,t){let o=`${Ee}/cms/v3/source-code/draft/content/${Pt(t)}`,n=await gt(o,{method:"GET",headers:await Be(e)});if(!n.ok){let i=await ft(n,t);throw new Error(`Failed to download ${t}: ${i.message}`)}let s=await n.arrayBuffer();return Buffer.from(s)}async function Mt(e,t){let o=`${Ee}/cms/v3/source-code/draft/metadata/${Pt(t)}`,n=await gt(o,{method:"GET",headers:await Be(e)});if(n.status===404)return null;if(!n.ok){let s=await ft(n,t);throw new Error(`Failed to get metadata for ${t}: ${s.message}`)}return await n.json()}async function yo(e){let t=await Be(e),o=[`${Ee}/cms/v3/source-code/draft/metadata`,`${Ee}/cms/v3/source-code/draft/metadata/`,`${Ee}/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(),r=i.children||i.objects||(Array.isArray(i)?i:null);if(r&&r.length>0)return r.filter(a=>a.folder)}}catch{}return[]}import*as G from"@clack/prompts";function wn(e){G.isCancel(e)&&(G.cancel(v.muted("Operation cancelled.")),process.exit(0))}async function ne(e){G.intro(v.heading(e))}async function oe(e){G.outro(v.success(e))}async function Ae(e,t){G.note(e,t?v.heading(t):void 0)}async function ge(e){let t=await G.text({message:v.accent(e.message),placeholder:e.placeholder,defaultValue:e.defaultValue,validate:e.validate});return wn(t),t}async function X(e){let t=await G.confirm({message:v.accent(e.message),initialValue:e.initialValue??!0});return wn(t),t}async function Ye(e){let t=await G.select({message:v.accent(e.message),options:e.options});return wn(t),t}async function se(){let e=G.spinner();return{start:t=>e.start(v.muted(t)),stop:t=>e.stop(v.success(t)),message:t=>e.message(v.muted(t))}}function K(e){G.log.info(e)}function _(e){G.log.success(v.success(e))}function U(e){G.log.warn(v.warn(e))}function M(e){G.log.error(v.error(e))}async function jt(){await ne("Checking your environment");let e=lt();e.found||(M("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),_t(e.version)||(M(`Node.js ${e.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),_(`Node.js v${e.version}`);let t=ct();t.found||(M("Git not found. Install it from https://git-scm.com"),process.exit(1)),_(`Git ${t.version}`);let o=N(),n=o.hubspotUploadMode!=="cli",s="",i="";if(n){let S=fe(),C=Fe();if(S)s=C?.portalId||"",i=C?.portalName||"",_(`HubSpot${i?`: ${i}`:""}${s?` (${s})`:""} \u2014 API mode`);else{U("No HubSpot account connected"),await Ae(`You need a Personal Access Key to deploy themes.
4
+ Create one at: https://app.hubspot.com/l/personal-access-key
5
+ Make sure the Content scope is enabled.`,"HubSpot connection required");let T=await ge({message:"Paste your Personal Access Key:",placeholder:"pat-na1-...",validate:E=>E.trim()?void 0:"Key is required"}),k=await se();k.start("Validating key...");try{let E=await Ot(T);$t(T,E.portalId,E.portalName,E.dataCenter),S=T,s=E.portalId,i=E.portalName,k.stop(`Connected to ${E.portalName} (${E.portalId})`)}catch(E){k.stop("Validation failed"),M(`Invalid key: ${E instanceof Error?E.message:String(E)}`),process.exit(1)}}}else{let S=xe();if(S.found)_(`HubSpot CLI v${S.version}`);else{U("HubSpot CLI not found"),await X({message:"Install HubSpot CLI globally?"})||(M("HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli"),process.exit(1));let k=await se();k.start("Installing HubSpot CLI..."),x("npm install -g @hubspot/cli").success||(k.stop("Failed"),M("Try: npm install -g @hubspot/cli"),process.exit(1)),S=xe(),k.stop(`HubSpot CLI v${S.version} installed`)}let C=Ce();if(C.authenticated)_(`HubSpot portal${C.portalName?`: ${C.portalName}`:""} (ID: ${C.portalId})`);else{U("HubSpot not authenticated"),await X({message:"Run `hs init` now?"})||(M("Run `hs init` manually."),process.exit(1));let k=await se();k.start("Waiting for HubSpot authentication..."),to("hs init")||(k.stop("Authentication failed"),process.exit(1)),C=Ce(),k.stop(`Connected to portal${C.portalName?`: ${C.portalName}`:""} (ID: ${C.portalId})`)}s=C.portalId,i=C.portalName}let r=dt(),a=mt(),l=pt(),c=uo(),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(r.found&&g.push({value:"claude-code",label:"Claude Code",hint:f==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),a.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,C)=>S.value===f?-1:C.value===f?1:0),g.length===1)p=g[0].value,_(`AI engine: ${u[p]} (auto-detected)`);else if(g.length>1)p=await Ye({message:"Choose your AI engine:",options:g});else if(await Ae(`You need an AI coding assistant to power the conversion.
6
6
 
7
- ${S.bold("Option 1:")} Install Claude Code ${S.muted("(recommended)")}
7
+ ${v.bold("Option 1:")} Install Claude Code ${v.muted("(recommended)")}
8
8
  https://claude.ai/code
9
9
 
10
- ${S.bold("Option 2:")} Install Gemini CLI
10
+ ${v.bold("Option 2:")} Install Gemini CLI
11
11
  https://github.com/google-gemini/gemini-cli
12
12
 
13
- ${S.bold("Option 3:")} Install OpenAI Codex
13
+ ${v.bold("Option 3:")} Install OpenAI Codex
14
14
  https://github.com/openai/codex
15
15
 
16
- ${S.bold("Option 4:")} Set an Anthropic API key
16
+ ${v.bold("Option 4:")} Set an Anthropic API key
17
17
  export ANTHROPIC_API_KEY=sk-ant-...
18
- (get one at https://console.anthropic.com)`,"AI engine required"),u=await We({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 h=await Se({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:v=>v.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=h,ne({anthropicApiKey:h})}let y;return u==="claude-code"&&(y=await We({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"}]})),ne({aiEngine:u}),await X("Environment ready!"),{aiEngine:u,model:y,portalId:n.portalId,portalName:n.portalName}}import{readdirSync as Xt,statSync as ii}from"fs";import{join as W,basename as Zt,extname as ri}from"path";function Jn(e){let t=[],o=[W(e,"src/components/landing"),W(e,"src/components/sections"),W(e,"src/components"),W(e,"src/pages"),W(e,"app/components"),W(e,"components")];for(let n of o)if(g(n))try{let s=Xt(n);for(let i of s){let r=W(n,i);if(!ii(r).isFile())continue;let l=ri(i);if(![".tsx",".jsx"].includes(l))continue;let c=Zt(i,l);if(c.startsWith("ui")||c==="index")continue;let u=b(r),p=ai(c,u);t.push({name:c,path:r,description:p})}}catch{}return t}function ai(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 Dn(e){let t=[W(e,"src/index.css"),W(e,"src/globals.css"),W(e,"src/app/globals.css"),W(e,"app/globals.css")],o=0,n=[];for(let s of t){if(!g(s))continue;let i=b(s),r=i.match(/--[\w-]+:/g);r&&(o+=r.length);let a=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(a)for(let c of a){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 Fn(e){let t=[],o=W(e,"src/hooks");if(g(o))try{let s=Xt(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=W(e,"src/components/landing");if(g(n))try{let s=Xt(n);for(let i of s){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let r=b(W(n,i));/carousel|embla|swiper/i.test(r)&&!t.includes("Carousel")&&t.push("Carousel"),/accordion|collapsible/i.test(r)&&!t.includes("Accordion")&&t.push("Accordion"),/typing|typewriter/i.test(r)&&!t.includes("Typing animation")&&t.push("Typing animation"),/parallax|requestAnimationFrame/i.test(r)&&!t.includes("Parallax")&&t.push("Parallax")}}catch{}return t.length===0&&t.push("Scroll animations"),t}function Ln(e){let t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let l=Zt(e.replace(/\.git$/,""))||"react-source";if(t=W(process.cwd(),"workspace",l),!g(t)){let c=x(`git clone --depth 1 "${e}" "${t}"`);if(!c.success)throw new Error(`Failed to clone ${e}: ${c.stderr}`)}}else if(t=e,!g(t))throw new Error(`Directory not found: ${t}`);let n=Jn(t),s=g(W(t,"tailwind.config.ts"))||g(W(t,"tailwind.config.js")),{varCount:i,fonts:r}=Dn(t),a=Fn(t);return{sourceDir:t,wasCloned:o,components:n,hasTailwind:s,cssVarCount:i,fonts:r,interactions:a}}async function wt(){await Q("Source Project");let e=await Se({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"}}),t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let h=Zt(e.replace(/\.git$/,""))||"react-source";if(t=W(process.cwd(),"workspace",h),g(t))k(`Using existing clone: ${S.dim(t)}`);else{let v=await oe();v.start("Cloning repository..."),x(`git clone --depth 1 "${e}" "${t}"`).success||(v.stop("Clone failed"),T(`Failed to clone ${e}. Check the URL and your access permissions.`),process.exit(1)),v.stop(`Cloned to ${S.dim(t)}`)}}else t=e,g(t)||(T(`Directory not found: ${t}`),process.exit(1)),k(`Using local source: ${S.dim(t)}`);let n=await oe();n.start("Analyzing project structure...");let s=Jn(t),i=g(W(t,"tailwind.config.ts"))||g(W(t,"tailwind.config.js")),{varCount:r,fonts:a}=Dn(t),l=Fn(t);n.stop(`Found ${s.length} landing page components`),s.length===0&&(J("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=s.map((h,v)=>` ${S.dim(`${v+1}.`)} ${S.bold(h.name)} ${S.muted(`\u2014 ${h.description}`)}`).join(`
19
- `),u=i?`Tailwind + custom CSS (${r} variables)`:`Custom CSS (${r} variables)`,p=a.length>0?a.join(", "):"System fonts",f=l.join(", ");return await ue(`${c}
18
+ (get one at https://console.anthropic.com)`,"AI engine required"),p=await Ye({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 ge({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:C=>C.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=S,Y({anthropicApiKey:S})}let y;return p==="claude-code"&&(y=await Ye({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:p}),await oe("Environment ready!"),{aiEngine:p,model:y,portalId:s,portalName:i}}import{readdirSync as xn,statSync as rr}from"fs";import{join as B,basename as Cn,extname as ar}from"path";function bo(e){let t=[],o=[B(e,"src/components/landing"),B(e,"src/components/sections"),B(e,"src/components"),B(e,"src/pages"),B(e,"app/components"),B(e,"components")];for(let n of o)if(h(n))try{let s=xn(n);for(let i of s){let r=B(n,i);if(!rr(r).isFile())continue;let l=ar(i);if(![".tsx",".jsx"].includes(l))continue;let c=Cn(i,l);if(c.startsWith("ui")||c==="index")continue;let u=b(r),p=lr(c,u);t.push({name:c,path:r,description:p})}}catch{}return t}function lr(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 So(e){let t=[B(e,"src/index.css"),B(e,"src/globals.css"),B(e,"src/app/globals.css"),B(e,"app/globals.css")],o=0,n=[];for(let s of t){if(!h(s))continue;let i=b(s),r=i.match(/--[\w-]+:/g);r&&(o+=r.length);let a=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(a)for(let c of a){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 vo(e){let t=[],o=B(e,"src/hooks");if(h(o))try{let s=xn(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=B(e,"src/components/landing");if(h(n))try{let s=xn(n);for(let i of s){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let r=b(B(n,i));/carousel|embla|swiper/i.test(r)&&!t.includes("Carousel")&&t.push("Carousel"),/accordion|collapsible/i.test(r)&&!t.includes("Accordion")&&t.push("Accordion"),/typing|typewriter/i.test(r)&&!t.includes("Typing animation")&&t.push("Typing animation"),/parallax|requestAnimationFrame/i.test(r)&&!t.includes("Parallax")&&t.push("Parallax")}}catch{}return t.length===0&&t.push("Scroll animations"),t}function wo(e){let t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let l=Cn(e.replace(/\.git$/,""))||"react-source";if(t=B(process.cwd(),"workspace",l),!h(t)){let c=x(`git clone --depth 1 "${e}" "${t}"`);if(!c.success)throw new Error(`Failed to clone ${e}: ${c.stderr}`)}}else if(t=e,!h(t))throw new Error(`Directory not found: ${t}`);let n=bo(t),s=h(B(t,"tailwind.config.ts"))||h(B(t,"tailwind.config.js")),{varCount:i,fonts:r}=So(t),a=vo(t);return{sourceDir:t,wasCloned:o,components:n,hasTailwind:s,cssVarCount:i,fonts:r,interactions:a}}async function Ft(){await ne("Source Project");let e=await ge({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=Cn(e.replace(/\.git$/,""))||"react-source";if(t=B(process.cwd(),"workspace",y),h(t))_(`Using existing clone: ${v.dim(t)}`);else{let S=await se();S.start("Cloning repository..."),x(`git clone --depth 1 "${e}" "${t}"`).success||(S.stop("Clone failed"),M(`Failed to clone ${e}. Check the URL and your access permissions.`),process.exit(1)),S.stop(`Cloned to ${v.dim(t)}`)}}else t=e,h(t)||(M(`Directory not found: ${t}`),process.exit(1)),_(`Using local source: ${v.dim(t)}`);let n=await se();n.start("Analyzing project structure...");let s=bo(t),i=h(B(t,"tailwind.config.ts"))||h(B(t,"tailwind.config.js")),{varCount:r,fonts:a}=So(t),l=vo(t);n.stop(`Found ${s.length} landing page components`),s.length===0&&(U("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=s.map((y,S)=>` ${v.dim(`${S+1}.`)} ${v.bold(y.name)} ${v.muted(`\u2014 ${y.description}`)}`).join(`
19
+ `),u=i?`Tailwind + custom CSS (${r} variables)`:`Custom CSS (${r} variables)`,p=a.length>0?a.join(", "):"System fonts",f=l.join(", ");return await Ae(`${c}
20
20
 
21
21
  CSS: ${u}
22
22
  JS: ${f}
23
- Font: ${p}`,`${s.length} components detected`),await B({message:"Does this look right?"})||(T("Please adjust your source directory and try again."),process.exit(0)),await X("Source analyzed!"),{sourceDir:t,wasCloned:o,components:s,hasTailwind:i,cssVarCount:r,fonts:a,interactions:l}}import{join as Ne}from"path";import{readdirSync as Hn,renameSync as li}from"fs";async function xt(){await Q("HubSpot Theme Setup");let e=await We({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=Ne(process.cwd(),"workspace");if($e(n),e==="fetch"){t=await Se({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:u=>u.trim()?void 0:"Theme name is required"}),o=Ne(n,t);let l=await oe();l.start("Fetching theme from HubSpot..."),x(`hs cms fetch "${t}" "${o}"`).success||(l.stop("Fetch failed"),T(`Could not fetch theme "${t}". Check the name in HubSpot Design Manager.`),T("Run `hs cms list /` to see available themes."),process.exit(1)),l.stop(`Theme fetched: ${S.dim(o)}`)}else{t=await Se({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),o=Ne(n,t);let l=await oe();l.start("Creating theme from boilerplate...");let c=new Set(Hn(process.cwd())),u=x(`hs cms theme create "${t}"`),p=Ne(process.cwd(),t);if(!g(p)){let h=Hn(process.cwd()).find(v=>!c.has(v)&&g(Ne(process.cwd(),v)));h&&(p=Ne(process.cwd(),h))}if(!u.success||!g(p)){l.stop("Creation failed");let y=u.stderr||u.stdout||"";T(`Could not create theme "${t}".`+(y?`
24
- ${y.slice(0,300)}`:"")+`
25
- Try running manually: hs cms theme create my-theme`),process.exit(1)}p!==o&&li(p,o),l.stop(`Theme created: ${S.dim(o)}`);let f=Ne(o,"theme.json");if(g(f))try{let y=JSON.parse(b(f));y.label=t,E(f,JSON.stringify(y,null,2)+`
26
- `),k(`Theme label set to "${t}"`)}catch{J("Could not update theme.json label \u2014 you can rename it manually in HubSpot.")}}await Q("Checking theme compatibility");let s=Ne(o,"templates/layouts/base.html");g(s)||(T(`base.html not found at ${s}. Your theme may have a different structure.`),process.exit(1)),k("base.html found");let i=b(s),r=!1;if(i.includes("template_css"))k("template_css support");else{J("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
23
+ Font: ${p}`,`${s.length} components detected`),await X({message:"Does this look right?"})||(M("Please adjust your source directory and try again."),process.exit(0)),await oe("Source analyzed!"),{sourceDir:t,wasCloned:o,components:s,hasTailwind:i,cssVarCount:r,fonts:a,interactions:l}}import{join as ht}from"path";import{mkdirSync as je,writeFileSync as Jt}from"fs";import{join as he}from"path";function Dt(e,t){je(e,{recursive:!0}),je(he(e,"templates"),{recursive:!0}),je(he(e,"modules"),{recursive:!0}),je(he(e,"css"),{recursive:!0}),je(he(e,"js"),{recursive:!0}),je(he(e,"images"),{recursive:!0}),je(he(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"}};Jt(he(e,"theme.json"),JSON.stringify(o,null,2)+`
24
+ `),Jt(he(e,"fields.json"),`[]
25
+ `);let n=`<!--
26
+ templateType: page
27
+ isAvailableForNewContent: true
28
+ label: ${t} Landing Page
29
+ screenshotPath: ../images/template-previews/home.png
30
+ -->
31
+ {% extends "./layouts/base.html" %}
32
+
33
+ {% block body %}
34
+ {% dnd_area "main_content"
35
+ label="Main Content",
36
+ class="body-container body-container--${t}"
37
+ %}
38
+ {% end_dnd_area %}
39
+ {% endblock body %}
40
+ `;Jt(he(e,"templates","home.html"),n);let s=`<!--
41
+ templateType: none
42
+ isAvailableForNewContent: false
43
+ label: Base Layout
44
+ -->
45
+ <!DOCTYPE html>
46
+ <html lang="{{ html_lang }}" {{ html_lang_dir }}>
47
+ <head>
48
+ <meta charset="utf-8">
49
+ <meta name="viewport" content="width=device-width, initial-scale=1">
50
+ {{ standard_header_includes }}
51
+ </head>
52
+ <body>
53
+ {% block body %}{% endblock body %}
54
+ {{ standard_footer_includes }}
55
+ </body>
56
+ </html>
57
+ `;je(he(e,"templates","layouts"),{recursive:!0}),Jt(he(e,"templates","layouts","base.html"),s)}import{mkdirSync as xo,writeFileSync as cr}from"fs";import{join as dr,dirname as ur}from"path";async function An(e,t){let o=await Mt(e,t);if(!o)return[];if(!o.folder)return[o.path||t];let n=[],s=o.children||[];for(let i of s){let r=typeof i=="string"?i:i.name;if(!r)continue;let a=`${t}/${r}`;if(typeof i=="string")n.push(...await An(e,a));else{let l=i;l.folder?n.push(...await An(e,l.path||a)):n.push(l.path||a)}}return n}async function mr(e,t,o){let n=0;async function s(){for(;n<e.length;){let r=n++;await o(e[r])}}let i=Array.from({length:Math.min(t,e.length)},()=>s());await Promise.all(i)}async function Ht(e,t,o,n={}){let s=n.concurrency??5,i=await An(e,t);if(i.length===0)throw new Error(`Theme "${t}" not found on HubSpot or is empty`);xo(o,{recursive:!0}),await mr(i,s,async r=>{let a=r.startsWith(t+"/")?r.slice(t.length+1):r,l=dr(o,a);xo(ur(l),{recursive:!0});let c=await ho(e,r);cr(l,c),n.onFile?.(a)})}async function Lt(){await ne("HubSpot Theme Setup");let e=await Ye({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=ht(process.cwd(),"workspace");if(ke(n),e==="fetch"){t=await ge({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:p=>p.trim()?void 0:"Theme name is required"}),o=ht(n,t);let l=await se();l.start("Fetching theme from HubSpot...");let c=N(),u=fe();if(c.hubspotUploadMode==="cli"||!u)x(`hs cms fetch "${t}" "${o}"`).success||(l.stop("Fetch failed"),M(`Could not fetch theme "${t}". Check the name in HubSpot Design Manager.`),process.exit(1));else try{await Ht(u,t,o)}catch(p){l.stop("Fetch failed"),M(`Could not fetch theme "${t}": ${p instanceof Error?p.message:String(p)}`),process.exit(1)}l.stop(`Theme fetched: ${v.dim(o)}`)}else{t=await ge({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),o=ht(n,t);let l=await se();l.start("Creating theme...");try{Dt(o,t)}catch(c){l.stop("Creation failed"),M(`Could not create theme "${t}": ${c instanceof Error?c.message:String(c)}`),process.exit(1)}l.stop(`Theme created: ${v.dim(o)}`)}await ne("Checking theme compatibility");let s=ht(o,"templates/layouts/base.html");h(s)||(M(`base.html not found at ${s}. Your theme may have a different structure.`),process.exit(1)),_("base.html found");let i=b(s),r=!1;if(i.includes("template_css"))_("template_css support");else{U("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
27
58
  `,i.indexOf("theme-overrides.css"))):i.lastIndexOf("require_css");if(l>0){let c=i.lastIndexOf(`
28
59
  `,l);i=i.slice(0,c)+`
29
60
  {% if template_css %}
30
61
  {{ require_css(get_asset_url(template_css)) }}
31
- {% endif %}`+i.slice(c),r=!0}}if(i.includes("template_js"))k("template_js support");else{J("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
62
+ {% endif %}`+i.slice(c),r=!0}}if(i.includes("template_js"))_("template_js support");else{U("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
32
63
  `,l),u=i.indexOf(`
33
64
  `,c+1),p=`
34
65
  {% if template_js %}
@@ -36,14 +67,14 @@ Try running manually: hs cms theme create my-theme`),process.exit(1)}p!==o&&li(p
36
67
  {% endif %}`,f=i.indexOf("}}",l)+2+i.slice(i.indexOf("}}",l)+2).indexOf(`
37
68
  `)+1;i=i.slice(0,i.indexOf(`
38
69
  `,i.indexOf("}}",l)+2))+p+i.slice(i.indexOf(`
39
- `,i.indexOf("}}",l)+2)),r=!0}}if(r){let l=await oe();l.start("Patching base.html..."),E(s,i),l.stop("base.html patched with template_css/template_js support")}let a=Ne(o,".hsignore");if(g(a)){let l=b(a);l.includes("docs/")||(E(a,l+`
70
+ `,i.indexOf("}}",l)+2)),r=!0}}if(r){let l=await se();l.start("Patching base.html..."),O(s,i),l.stop("base.html patched with template_css/template_js support")}let a=ht(o,".hsignore");if(h(a)){let l=b(a);l.includes("docs/")||(O(a,l+`
40
71
  docs/
41
- `),k("Added docs/ to .hsignore"))}else E(a,`docs/
72
+ `),_("Added docs/ to .hsignore"))}else O(a,`docs/
42
73
  *.md
43
74
  node_modules/
44
75
  .git
45
- `),k("Created .hsignore");return await X("Theme ready!"),{themePath:o,themeName:t}}import{join as le}from"path";import{readdirSync as rt,rmSync as eo}from"fs";import{spawn as ci}from"child_process";import{join as _,basename as di}from"path";import{readdirSync as we,statSync as Xn,writeFileSync as ui}from"fs";var Gn=new Map;function Ue(e){let t=Gn.get(e);if(t!==void 0)return t;try{t=b(Rn(e))}catch{t=""}return Gn.set(e,t),t}function se(){return Ue("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function Wn(){return Ue("design-guide.md")}function Un(){return Ue("content-guide.md")}function Ke(){return Ue("hubspot-rules.md")}function Kn(){return Ue("humanify-guide.md")}function Bn(e){let t=Ue("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(`
46
- ## `,s+n.length);return i>=0?t.slice(s,i).trim():t.slice(s).trim()}function Yn(e){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
76
+ `),_("Created .hsignore");return await oe("Theme ready!"),{themePath:o,themeName:t}}import{join as ue}from"path";import{readdirSync as yt,rmSync as Mo}from"fs";import{spawn as pr}from"child_process";import{join as j,basename as fr}from"path";import{readdirSync as Ie,statSync as Po,writeFileSync as gr}from"fs";var Co=new Map;function Ve(e){let t=Co.get(e);if(t!==void 0)return t;try{t=b(so(e))}catch{t=""}return Co.set(e,t),t}function ae(){return Ve("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function Ao(){return Ve("design-guide.md")}function Io(){return Ve("content-guide.md")}function ze(){return Ve("hubspot-rules.md")}function $o(){return Ve("humanify-guide.md")}function To(e){let t=Ve("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(`
77
+ ## `,s+n.length);return i>=0?t.slice(s,i).trim():t.slice(s).trim()}function ko(e){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
47
78
 
48
79
  ## Rules
49
80
  Follow the conversion guide below EXACTLY. Key rules:
@@ -60,10 +91,10 @@ Follow the conversion guide below EXACTLY. Key rules:
60
91
  - Convert React hooks to vanilla JS (no React, no npm packages)
61
92
 
62
93
  ## HubSpot CMS Rules
63
- ${Ke()}
94
+ ${ze()}
64
95
 
65
96
  ## Conversion Guide
66
- ${e}`}function Vn(e,t,o){return`Convert this React component to a HubSpot module named "${t}".
97
+ ${e}`}function Eo(e,t,o){return`Convert this React component to a HubSpot module named "${t}".
67
98
 
68
99
  Return a JSON object with these keys:
69
100
  - fieldsJson: complete fields.json content (as JSON string)
@@ -78,7 +109,7 @@ ${o}
78
109
  React component source:
79
110
  ${e}
80
111
 
81
- Return ONLY valid JSON, no markdown fences.`}function zn(e,t,o){return`Create a shared CSS file for a HubSpot CMS landing page.
112
+ Return ONLY valid JSON, no markdown fences.`}function No(e,t,o){return`Create a shared CSS file for a HubSpot CMS landing page.
82
113
 
83
114
  Extract the design system from the source CSS and Tailwind config below.
84
115
  Use the class prefix ".${o}-" for all custom classes.
@@ -102,7 +133,7 @@ ${e}
102
133
  Tailwind config:
103
134
  ${t}
104
135
 
105
- Return ONLY the CSS content, no markdown fences.`}function qn(e,t,o){return`Create a shared vanilla JS file for a HubSpot CMS landing page.
136
+ Return ONLY the CSS content, no markdown fences.`}function _o(e,t,o){return`Create a shared vanilla JS file for a HubSpot CMS landing page.
106
137
 
107
138
  Convert the React hooks and interactive components below to plain JavaScript.
108
139
  Use the class prefix "${o}-" to match the CSS.
@@ -120,7 +151,7 @@ ${e}
120
151
  Interactive component sources:
121
152
  ${t}
122
153
 
123
- Return ONLY the JavaScript content, no markdown fences.`}function Qn(e,t,o){return`Create a HubSpot page template that assembles these modules:
154
+ Return ONLY the JavaScript content, no markdown fences.`}function Ro(e,t,o){return`Create a HubSpot page template that assembles these modules:
124
155
 
125
156
  ${e.map((n,s)=>`${s+1}. ${n}.module`).join(`
126
157
  `)}
@@ -135,11 +166,11 @@ Template requirements:
135
166
  - Each module in its own dnd_section with padding zeroed and full_width=true
136
167
  - dnd_area label: "${t} Landing Page"
137
168
 
138
- Return ONLY the template HTML content, no markdown fences.`}var mi=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"]),Ct=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||se();this.reported.clear(),this.moduleCount=0,this.expectedModules=0;let r=this.countSourceComponents(o),a=this.listModules(n),l=this.listDir(_(n,"css")),c=this.listDir(_(n,"js")),u=this.listDir(_(n,"templates")),p=this.buildFullPrompt(o,n,i);s("convert",`Starting Claude Code (${r} source components found)...`);let f="",y="",h=setInterval(()=>{this.reportProgress(n,a,l,c,u,s)},3e3);try{await new Promise((F,H)=>{let z={...process.env};delete z.CLAUDECODE;let q=["--print","--max-turns","50","--allowedTools","Read,Glob,Grep,Write,Edit,Bash"];this.model&&q.push("--model",this.model);let O=ci("claude",q,{cwd:n,stdio:["pipe","pipe","pipe"],env:z,shell:!0});O.stdout.on("data",L=>{f+=L.toString()}),O.stderr.on("data",L=>{y+=L.toString()}),O.on("error",L=>H(new Error(`Claude Code failed to start: ${L.message}`))),O.on("close",L=>{L!==0?H(new Error(`Claude Code exited with code ${L}.
139
- `+(y?`Stderr: ${y.slice(0,500)}
140
- `:"")+(f?`Output: ${f.slice(0,500)}`:"No output"))):F()}),O.stdin.on("error",()=>{}),O.stdin.write(p),O.stdin.end(),setTimeout(()=>{O.kill(),H(new Error("Claude Code timed out after 30 minutes"))},18e5)})}finally{clearInterval(h)}let v=_(n,"..","vibespot-conversion.log");try{let H=["=== vibeSpot Conversion Log ===",`Timestamp: ${new Date().toISOString()}`,`Source: ${o}`,`Theme: ${n}`,`Model: ${this.model||"default"}`,"","=== PROMPT SENT ===",p.slice(0,500)+`
141
- ... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",f||"(empty)","","=== CLAUDE CODE STDERR ===",y||"(empty)",""].join(`
142
- `);ui(v,H,"utf-8"),s("status",`Log written to ${di(v)}`)}catch{}s("scan","Scanning generated files...");let N=this.scanGeneratedFiles(n);if(N.modules.filter(F=>!a.has(F.moduleName+".module")).length===0){let F=f.slice(0,1500)||"(no output)",H=y.slice(0,500);throw new Error(`Claude Code did not create any new module files.
169
+ Return ONLY the template HTML content, no markdown fences.`}var hr=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"]),Gt=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||ae();this.reported.clear(),this.moduleCount=0,this.expectedModules=0;let r=this.countSourceComponents(o),a=this.listModules(n),l=this.listDir(j(n,"css")),c=this.listDir(j(n,"js")),u=this.listDir(j(n,"templates")),p=this.buildFullPrompt(o,n,i);s("convert",`Starting Claude Code (${r} source components found)...`);let f="",g="",y=setInterval(()=>{this.reportProgress(n,a,l,c,u,s)},3e3);try{await new Promise((k,E)=>{let q={...process.env};delete q.CLAUDECODE;let H=["--print","--max-turns","50","--allowedTools","Read,Glob,Grep,Write,Edit,Bash"];this.model&&H.push("--model",this.model);let P=pr("claude",H,{cwd:n,stdio:["pipe","pipe","pipe"],env:q,shell:!0});P.stdout.on("data",L=>{f+=L.toString()}),P.stderr.on("data",L=>{g+=L.toString()}),P.on("error",L=>E(new Error(`Claude Code failed to start: ${L.message}`))),P.on("close",L=>{L!==0?E(new Error(`Claude Code exited with code ${L}.
170
+ `+(g?`Stderr: ${g.slice(0,500)}
171
+ `:"")+(f?`Output: ${f.slice(0,500)}`:"No output"))):k()}),P.stdin.on("error",()=>{}),P.stdin.write(p),P.stdin.end(),setTimeout(()=>{P.kill(),E(new Error("Claude Code timed out after 30 minutes"))},18e5)})}finally{clearInterval(y)}let S=j(n,"..","vibespot-conversion.log");try{let E=["=== vibeSpot Conversion Log ===",`Timestamp: ${new Date().toISOString()}`,`Source: ${o}`,`Theme: ${n}`,`Model: ${this.model||"default"}`,"","=== PROMPT SENT ===",p.slice(0,500)+`
172
+ ... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",f||"(empty)","","=== CLAUDE CODE STDERR ===",g||"(empty)",""].join(`
173
+ `);gr(S,E,"utf-8"),s("status",`Log written to ${fr(S)}`)}catch{}s("scan","Scanning generated files...");let C=this.scanGeneratedFiles(n);if(C.modules.filter(k=>!a.has(k.moduleName+".module")).length===0){let k=f.slice(0,1500)||"(no output)",E=g.slice(0,500);throw new Error(`Claude Code did not create any new module files.
143
174
 
144
175
  This usually means the model described the conversion instead of using Write tool to create files.
145
176
 
@@ -150,12 +181,12 @@ Possible causes:
150
181
 
151
182
  Source: ${t.sourceDir}
152
183
  Theme: ${n}
153
- `+(H?`
184
+ `+(E?`
154
185
  Stderr:
155
- ${H}
186
+ ${E}
156
187
  `:"")+`
157
188
  Claude output:
158
- ${F}`)}return N}reportProgress(t,o,n,s,i,r){let a=0,l=this.listDir(_(t,"css"));for(let f of l){if(n.has(f)||!f.endsWith(".css"))continue;let y=`css:${f}`;this.reported.has(y)||(this.reported.add(y),r("created",`Shared CSS (${f})`),a++)}let c=this.listDir(_(t,"js"));for(let f of c){if(s.has(f)||!f.endsWith(".js"))continue;let y=`js:${f}`;this.reported.has(y)||(this.reported.add(y),r("created",`Shared JS (${f})`),a++)}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 y=`module:${f}`;if(!this.reported.has(y)){this.reported.add(y),this.moduleCount++;let h=this.expectedModules>0?`[${this.moduleCount}/${this.expectedModules}]`:`[${this.moduleCount}]`;r("created",`Module ${h}: ${f.replace(".module","")}`),a++}}let p=this.listDir(_(t,"templates"));for(let f of p){if(i.has(f)||!f.endsWith(".html"))continue;let y=`template:${f}`;this.reported.has(y)||(this.reported.add(y),r("created",`Page template (${f})`),a++)}if(a===0)if(this.moduleCount>0){let f=this.expectedModules>0?`/${this.expectedModules}`:"";r("status",`${this.moduleCount}${f} modules created, conversion continuing...`)}else this.reported.size>0?r("status","Shared assets created, building modules..."):r("status","Claude Code is analyzing source files...")}buildFullPrompt(t,o,n){return`You are converting a React landing page to native HubSpot CMS modules.
189
+ ${k}`)}return C}reportProgress(t,o,n,s,i,r){let a=0,l=this.listDir(j(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),r("created",`Shared CSS (${f})`),a++)}let c=this.listDir(j(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),r("created",`Shared JS (${f})`),a++)}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}]`;r("created",`Module ${y}: ${f.replace(".module","")}`),a++}}let p=this.listDir(j(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),r("created",`Page template (${f})`),a++)}if(a===0)if(this.moduleCount>0){let f=this.expectedModules>0?`/${this.expectedModules}`:"";r("status",`${this.moduleCount}${f} modules created, conversion continuing...`)}else this.reported.size>0?r("status","Shared assets created, building modules..."):r("status","Claude Code is analyzing source files...")}buildFullPrompt(t,o,n){return`You are converting a React landing page to native HubSpot CMS modules.
159
190
 
160
191
  SOURCE DIRECTORY: ${t}
161
192
  THEME DIRECTORY: ${o}
@@ -198,16 +229,16 @@ CSS QUALITY: The converted page must visually match the original React page. Eve
198
229
  Do NOT run hs upload \u2014 I will handle that separately.
199
230
 
200
231
  HUBSPOT CMS RULES:
201
- ${Ke()}
232
+ ${ze()}
202
233
 
203
234
  CONVERSION GUIDE:
204
- ${n}`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=_(t,"css");if(g(n)){for(let a of we(n))if(a.endsWith(".css")&&a!=="theme-overrides.css"&&a!=="main.css"&&a!=="style.css"){o.sharedCss=b(_(n,a));break}}let s=_(t,"js");if(g(s)){for(let a of we(s))if(a.endsWith(".js")&&a!=="main.js"){o.sharedJs=b(_(s,a));break}}let i=_(t,"templates");if(g(i)){for(let a of we(i))if(a.startsWith("lp-")&&a.endsWith(".html")){o.template=b(_(i,a));break}if(!o.template){for(let a of we(i))if(a.endsWith(".html")&&!mi.has(a)&&!a.startsWith("system")){let l=b(_(i,a));if(l.includes("dnd_area")){o.template=l;break}}}if(!o.template){for(let a of we(i))if(a.endsWith(".html")&&!a.startsWith("system")&&a!=="base.html"){let l=b(_(i,a));if(l.includes("dnd_area")){o.template=l;break}}}}let r=_(t,"modules");if(g(r))for(let a of we(r)){if(!a.endsWith(".module"))continue;let l=_(r,a);if(!Xn(l).isDirectory())continue;let c={moduleName:a.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=_(l,"fields.json");g(u)&&(c.fieldsJson=b(u));let p=_(l,"meta.json");g(p)&&(c.metaJson=b(p));let f=_(l,"module.html");g(f)&&(c.moduleHtml=b(f));let y=_(l,"module.css");g(y)&&(c.moduleCss=b(y));let h=_(l,"module.js");g(h)&&(c.moduleJs=b(h)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}listModules(t){let o=_(t,"modules");return g(o)?new Set(we(o).filter(n=>n.endsWith(".module"))):new Set}listDir(t){return g(t)?new Set(we(t)):new Set}detectExpectedModules(t,o){let n=_(t,"templates");if(!g(n))return 0;for(let s of we(n))if(!o.has(s)&&!(!s.endsWith(".html")||s==="base.html"||s.startsWith("system")))try{let i=b(_(n,s));if(i.includes("dnd_area")){let r=i.match(/dnd_module/g);return r?r.length:0}}catch{}return 0}countSourceComponents(t){let o=_(t,"src");return g(o)?this.countComponentsRecursive(o):0}countComponentsRecursive(t){let o=0;for(let n of we(t)){let s=_(t,n);try{Xn(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}};import pi from"@anthropic-ai/sdk";import{join as D,basename as fi}from"path";import{readdirSync as Zn}from"fs";var At=class{client;model="claude-sonnet-4-6";constructor(t){this.client=new pi({apiKey:t||process.env.ANTHROPIC_API_KEY})}async convert(t){let{sourceDir:o,themePath:n,conversionGuide:s,onProgress:i}=t,r=Yn(s),a=fi(o)||"page",l=a.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(r,zn(c,u,l)),f=D(n,"css",`${l}-theme.css`);E(f,p),i("css-done",`Created css/${l}-theme.css`),i("js","Creating shared JavaScript...");let y=this.findAndReadHooks(o),h=this.findInteractiveComponents(o),v=await this.complete(r,qn(y,h,l)),N=D(n,"js",`${l}-animations.js`);E(N,v),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let K=this.findComponents(o),F=[];for(let O=0;O<K.length;O++){let L=K[O],Ae=L.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${Ae}.module (${O+1}/${K.length})...`);let Pe=b(L.path),pt=await this.complete(r,Vn(Pe,Ae,`See css/${l}-theme.css`));try{let de=JSON.parse(pt),Ie={moduleName:Ae,fieldsJson:typeof de.fieldsJson=="string"?de.fieldsJson:JSON.stringify(de.fieldsJson,null,2),metaJson:typeof de.metaJson=="string"?de.metaJson:JSON.stringify(de.metaJson,null,2),moduleHtml:de.moduleHtml||"",moduleCss:de.moduleCss||"",moduleJs:de.moduleJs||void 0},he=D(n,"modules",`${Ae}.module`);$e(he),E(D(he,"fields.json"),Ie.fieldsJson),E(D(he,"meta.json"),Ie.metaJson),E(D(he,"module.html"),Ie.moduleHtml),E(D(he,"module.css"),Ie.moduleCss),Ie.moduleJs&&E(D(he,"module.js"),Ie.moduleJs),F.push(Ie),i("module-done",`${Ae}.module (${this.countFiles(Ie)} files)`)}catch{i("module-error",`Failed to parse ${Ae} \u2014 skipping`)}}i("template","Creating page template...");let H=F.map(O=>O.moduleName),z=await this.complete(r,Qn(H,a,l)),q=D(n,"templates",`lp-${l}.html`);return E(q,z),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:p,sharedJs:v,template:z,modules:F}}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=[D(t,"src/index.css"),D(t,"src/globals.css"),D(t,"src/app/globals.css"),D(t,"app/globals.css")];for(let n of o)if(g(n))return b(n);return""}findAndReadTailwind(t){let o=[D(t,"tailwind.config.ts"),D(t,"tailwind.config.js"),D(t,"tailwind.config.mjs")];for(let n of o)if(g(n))return b(n);return""}findAndReadHooks(t){let o=D(t,"src/hooks");if(!g(o))return"";try{return Zn(o).filter(n=>n.endsWith(".ts")||n.endsWith(".tsx")).map(n=>`// ${n}
205
- ${b(D(o,n))}`).join(`
235
+ ${n}`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=j(t,"css");if(h(n)){for(let a of Ie(n))if(a.endsWith(".css")&&a!=="theme-overrides.css"&&a!=="main.css"&&a!=="style.css"){o.sharedCss=b(j(n,a));break}}let s=j(t,"js");if(h(s)){for(let a of Ie(s))if(a.endsWith(".js")&&a!=="main.js"){o.sharedJs=b(j(s,a));break}}let i=j(t,"templates");if(h(i)){for(let a of Ie(i))if(a.startsWith("lp-")&&a.endsWith(".html")){o.template=b(j(i,a));break}if(!o.template){for(let a of Ie(i))if(a.endsWith(".html")&&!hr.has(a)&&!a.startsWith("system")){let l=b(j(i,a));if(l.includes("dnd_area")){o.template=l;break}}}if(!o.template){for(let a of Ie(i))if(a.endsWith(".html")&&!a.startsWith("system")&&a!=="base.html"){let l=b(j(i,a));if(l.includes("dnd_area")){o.template=l;break}}}}let r=j(t,"modules");if(h(r))for(let a of Ie(r)){if(!a.endsWith(".module"))continue;let l=j(r,a);if(!Po(l).isDirectory())continue;let c={moduleName:a.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=j(l,"fields.json");h(u)&&(c.fieldsJson=b(u));let p=j(l,"meta.json");h(p)&&(c.metaJson=b(p));let f=j(l,"module.html");h(f)&&(c.moduleHtml=b(f));let g=j(l,"module.css");h(g)&&(c.moduleCss=b(g));let y=j(l,"module.js");h(y)&&(c.moduleJs=b(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}listModules(t){let o=j(t,"modules");return h(o)?new Set(Ie(o).filter(n=>n.endsWith(".module"))):new Set}listDir(t){return h(t)?new Set(Ie(t)):new Set}detectExpectedModules(t,o){let n=j(t,"templates");if(!h(n))return 0;for(let s of Ie(n))if(!o.has(s)&&!(!s.endsWith(".html")||s==="base.html"||s.startsWith("system")))try{let i=b(j(n,s));if(i.includes("dnd_area")){let r=i.match(/dnd_module/g);return r?r.length:0}}catch{}return 0}countSourceComponents(t){let o=j(t,"src");return h(o)?this.countComponentsRecursive(o):0}countComponentsRecursive(t){let o=0;for(let n of Ie(t)){let s=j(t,n);try{Po(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}};import yr from"@anthropic-ai/sdk";import{join as W,basename as br}from"path";import{readdirSync as Oo}from"fs";var Ut=class{client;model="claude-sonnet-4-6";constructor(t){this.client=new yr({apiKey:t||process.env.ANTHROPIC_API_KEY})}async convert(t){let{sourceDir:o,themePath:n,conversionGuide:s,onProgress:i}=t,r=ko(s),a=br(o)||"page",l=a.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(r,No(c,u,l)),f=W(n,"css",`${l}-theme.css`);O(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(r,_o(g,y,l)),C=W(n,"js",`${l}-animations.js`);O(C,S),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let T=this.findComponents(o),k=[];for(let P=0;P<T.length;P++){let L=T[P],ee=L.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${ee}.module (${P+1}/${T.length})...`);let J=b(L.path),It=await this.complete(r,Eo(J,ee,`See css/${l}-theme.css`));try{let te=JSON.parse(It),pe={moduleName:ee,fieldsJson:typeof te.fieldsJson=="string"?te.fieldsJson:JSON.stringify(te.fieldsJson,null,2),metaJson:typeof te.metaJson=="string"?te.metaJson:JSON.stringify(te.metaJson,null,2),moduleHtml:te.moduleHtml||"",moduleCss:te.moduleCss||"",moduleJs:te.moduleJs||void 0},Oe=W(n,"modules",`${ee}.module`);ke(Oe),O(W(Oe,"fields.json"),pe.fieldsJson),O(W(Oe,"meta.json"),pe.metaJson),O(W(Oe,"module.html"),pe.moduleHtml),O(W(Oe,"module.css"),pe.moduleCss),pe.moduleJs&&O(W(Oe,"module.js"),pe.moduleJs),k.push(pe),i("module-done",`${ee}.module (${this.countFiles(pe)} files)`)}catch{i("module-error",`Failed to parse ${ee} \u2014 skipping`)}}i("template","Creating page template...");let E=k.map(P=>P.moduleName),q=await this.complete(r,Ro(E,a,l)),H=W(n,"templates",`lp-${l}.html`);return O(H,q),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:p,sharedJs:S,template:q,modules:k}}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=[W(t,"src/index.css"),W(t,"src/globals.css"),W(t,"src/app/globals.css"),W(t,"app/globals.css")];for(let n of o)if(h(n))return b(n);return""}findAndReadTailwind(t){let o=[W(t,"tailwind.config.ts"),W(t,"tailwind.config.js"),W(t,"tailwind.config.mjs")];for(let n of o)if(h(n))return b(n);return""}findAndReadHooks(t){let o=W(t,"src/hooks");if(!h(o))return"";try{return Oo(o).filter(n=>n.endsWith(".ts")||n.endsWith(".tsx")).map(n=>`// ${n}
236
+ ${b(W(o,n))}`).join(`
206
237
 
207
238
  `)}catch{return""}}findInteractiveComponents(t){let o=this.findComponents(t),n=[];for(let s of o){let i=b(s.path);/carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(i)&&n.push(`// ${s.name}
208
239
  ${i}`)}return n.join(`
209
240
 
210
- `)}findComponents(t){let o=[D(t,"src/components/landing"),D(t,"src/components/sections"),D(t,"src/components")];for(let n of o)if(g(n))try{return Zn(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:D(n,s)}))}catch{continue}return[]}countFiles(t){let o=3;return t.moduleCss&&o++,t.moduleJs&&o++,o}};import{spawn as gi}from"child_process";import{join as ie}from"path";import{readdirSync as It,statSync as hi}from"fs";var kt=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||se(),r=this.buildFullPrompt(o,n,i);return s("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((a,l)=>{let c=gi("gemini",["-p",r],{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}`)):a()}),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}.
241
+ `)}findComponents(t){let o=[W(t,"src/components/landing"),W(t,"src/components/sections"),W(t,"src/components")];for(let n of o)if(h(n))try{return Oo(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:W(n,s)}))}catch{continue}return[]}countFiles(t){let o=3;return t.moduleCss&&o++,t.moduleJs&&o++,o}};import{spawn as Sr}from"child_process";import{join as le}from"path";import{readdirSync as Wt,statSync as vr}from"fs";var Kt=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||ae(),r=this.buildFullPrompt(o,n,i);return s("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((a,l)=>{let c=Sr("gemini",["-p",r],{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}`)):a()}),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}.
211
242
 
212
243
  INSTRUCTIONS:
213
244
  1. Analyze all .tsx/.jsx components in the React source
@@ -222,7 +253,7 @@ CONVERSION GUIDE:
222
253
  ${n}
223
254
 
224
255
  Do NOT run hs upload \u2014 I will handle that separately.
225
- Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=ie(t,"css");if(g(n)){for(let a of It(n))if((a.includes("theme")||a.includes("page"))&&a.endsWith(".css")&&a!=="theme-overrides.css"&&a!=="main.css"&&a!=="style.css"){o.sharedCss=b(ie(n,a));break}}let s=ie(t,"js");if(g(s)){for(let a of It(s))if((a.includes("animation")||a.includes("page"))&&a.endsWith(".js")&&a!=="main.js"){o.sharedJs=b(ie(s,a));break}}let i=ie(t,"templates");if(g(i)){for(let a of It(i))if(a.endsWith(".html")&&!a.startsWith("system")&&a!=="base.html"){let l=b(ie(i,a));if(l.includes("dnd_area")){o.template=l;break}}}let r=ie(t,"modules");if(g(r))for(let a of It(r)){if(!a.endsWith(".module"))continue;let l=ie(r,a);if(!hi(l).isDirectory())continue;let c={moduleName:a.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=ie(l,"fields.json");g(u)&&(c.fieldsJson=b(u));let p=ie(l,"meta.json");g(p)&&(c.metaJson=b(p));let f=ie(l,"module.html");g(f)&&(c.moduleHtml=b(f));let y=ie(l,"module.css");g(y)&&(c.moduleCss=b(y));let h=ie(l,"module.js");g(h)&&(c.moduleJs=b(h)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};import{spawn as yi}from"child_process";import{join as re}from"path";import{readdirSync as $t,statSync as bi}from"fs";var Et=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||se(),r=this.buildFullPrompt(o,n,i);return s("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((a,l)=>{let c=yi("codex",["exec","--full-auto",r],{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}`)):a()}),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}.
256
+ Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=le(t,"css");if(h(n)){for(let a of Wt(n))if((a.includes("theme")||a.includes("page"))&&a.endsWith(".css")&&a!=="theme-overrides.css"&&a!=="main.css"&&a!=="style.css"){o.sharedCss=b(le(n,a));break}}let s=le(t,"js");if(h(s)){for(let a of Wt(s))if((a.includes("animation")||a.includes("page"))&&a.endsWith(".js")&&a!=="main.js"){o.sharedJs=b(le(s,a));break}}let i=le(t,"templates");if(h(i)){for(let a of Wt(i))if(a.endsWith(".html")&&!a.startsWith("system")&&a!=="base.html"){let l=b(le(i,a));if(l.includes("dnd_area")){o.template=l;break}}}let r=le(t,"modules");if(h(r))for(let a of Wt(r)){if(!a.endsWith(".module"))continue;let l=le(r,a);if(!vr(l).isDirectory())continue;let c={moduleName:a.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=le(l,"fields.json");h(u)&&(c.fieldsJson=b(u));let p=le(l,"meta.json");h(p)&&(c.metaJson=b(p));let f=le(l,"module.html");h(f)&&(c.moduleHtml=b(f));let g=le(l,"module.css");h(g)&&(c.moduleCss=b(g));let y=le(l,"module.js");h(y)&&(c.moduleJs=b(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};import{spawn as wr}from"child_process";import{join as ce}from"path";import{readdirSync as Bt,statSync as xr}from"fs";var Yt=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||ae(),r=this.buildFullPrompt(o,n,i);return s("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((a,l)=>{let c=wr("codex",["exec","--full-auto",r],{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}`)):a()}),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}.
226
257
 
227
258
  INSTRUCTIONS:
228
259
  1. Analyze all .tsx/.jsx components in the React source
@@ -237,15 +268,15 @@ CONVERSION GUIDE:
237
268
  ${n}
238
269
 
239
270
  Do NOT run hs upload \u2014 I will handle that separately.
240
- Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=re(t,"css");if(g(n)){for(let a of $t(n))if((a.includes("theme")||a.includes("page"))&&a.endsWith(".css")&&a!=="theme-overrides.css"&&a!=="main.css"&&a!=="style.css"){o.sharedCss=b(re(n,a));break}}let s=re(t,"js");if(g(s)){for(let a of $t(s))if((a.includes("animation")||a.includes("page"))&&a.endsWith(".js")&&a!=="main.js"){o.sharedJs=b(re(s,a));break}}let i=re(t,"templates");if(g(i)){for(let a of $t(i))if(a.endsWith(".html")&&!a.startsWith("system")&&a!=="base.html"){let l=b(re(i,a));if(l.includes("dnd_area")){o.template=l;break}}}let r=re(t,"modules");if(g(r))for(let a of $t(r)){if(!a.endsWith(".module"))continue;let l=re(r,a);if(!bi(l).isDirectory())continue;let c={moduleName:a.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=re(l,"fields.json");g(u)&&(c.fieldsJson=b(u));let p=re(l,"meta.json");g(p)&&(c.metaJson=b(p));let f=re(l,"module.html");g(f)&&(c.moduleHtml=b(f));let y=re(l,"module.css");g(y)&&(c.moduleCss=b(y));let h=re(l,"module.js");g(h)&&(c.moduleJs=b(h)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};function vi(e,t){switch(e){case"claude-code":return new Ct(t);case"gemini-cli":return new kt;case"codex-cli":return new Et;case"api":return new At}}async function Tt(e){await Q("Converting React to HubSpot Modules"),await ue(`AI will now analyze your React code and create
241
- HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let t=vi(e.aiEngine,e.model),o=se(),n=await oe();n.start("Starting AI conversion...");let s=Date.now(),i=await t.convert({sourceDir:e.sourceDir,themePath:e.themePath,conversionGuide:o,onProgress:(h,v)=>{h==="created"?k(v):n.message(v)}}),r=((Date.now()-s)/1e3).toFixed(0);n.stop(`AI conversion complete (${r}s)`);let a=Si(e.themePath);for(let h of a)k(`Auto-fixed: ${h}`);let l=wi(e.themePath,i),c=[];for(let h of l){let v=h.passed?"\u2705":"\u274C",N=h.passed?"":h.critical?" (CRITICAL)":" (cosmetic)";c.push(`${v} ${h.label}${N}`)}let u=l.filter(h=>h.passed).length;c.push(`
242
- ${u}/${l.length} checks passed`),await ue(c.join(`
243
- `),"Conversion Checklist");let p=l.filter(h=>!h.passed&&h.critical),f=l.filter(h=>!h.passed&&!h.critical);if(p.length>0){if(T(`${p.length} critical issue(s) \u2014 upload will likely fail:
244
- `+p.map(v=>` - ${v.label}`).join(`
245
- `)),!await B({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else f.length>0&&J(`${f.length} non-critical issue(s) \u2014 page will work but may look incomplete:
246
- `+f.map(h=>` - ${h.label}`).join(`
247
- `));let y=le(e.themePath,"..","vibespot-conversion.log");return g(y)&&(await B({message:"Keep conversion log file for debugging?",initialValue:!1})?k(`Log saved: ${y}`):eo(y)),await X("Files ready for upload!"),i}function Si(e){let t=[];xi(e),Ci(e);let o=le(e,"modules");if(g(o))for(let s of rt(o)){if(!s.endsWith(".module"))continue;let i=le(o,s,"fields.json");if(!g(i))continue;let r=s.replace(".module",""),a=b(i),l=!1;a.includes('"textarea"')&&(a=a.replace(/"textarea"/g,'"text"'),l=!0,t.push(`${r}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(a)&&(a=a.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,t.push(`${r}: reserved field name "name" \u2192 "item_name"`));try{let u=JSON.parse(a),p=!1;to(u)&&(p=!0,t.push(`${r}: fixed choice field format`)),no(u)&&(p=!0,t.push(`${r}: fixed link field default value`)),p&&(a=JSON.stringify(u,null,2)+`
248
- `,l=!0)}catch{t.push(`${r}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&E(i,a);let c=le(o,s,"module.html");if(g(c)){let u=b(c);u.includes("now()")&&(u=u.replace(/now\(\)/g,"local_dt"),E(c,u),t.push(`${r}: now() \u2192 local_dt`))}}let n=le(e,"templates");if(g(n))for(let s of rt(n)){if(!s.endsWith(".html"))continue;let i=le(n,s),r=b(i);(r.includes("hubdb_table")||r.includes("hubdb_table_rows"))&&(eo(i),t.push(`Removed ${s} (HubDB requires CMS Hub Pro/Enterprise)`))}return t}function to(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 r=i.charAt(0).toUpperCase()+i.slice(1);return[i,r]}return i}),t=!0),Array.isArray(n.children)&&to(n.children)&&(t=!0)}return t}function no(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 r=typeof s=="string"?s:"";n.default={url:{href:r,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&no(n.children)&&(t=!0)}return t}function wi(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 r=t.modules.filter(p=>!p.moduleCss).map(p=>p.moduleName),a=r.length===0;o.push({label:a?"module.css created for each module":`module.css missing for: ${r.join(", ")}`,passed:n>0&&a,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=le(e,"templates"),u=!1;if(g(c))for(let p of rt(c)){if(!p.endsWith(".html")||p==="base.html"||p.startsWith("system"))continue;let f=b(le(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 xi(e){let t=le(e,"templates");if(g(t))for(let o of rt(t)){if(!o.endsWith(".html")||o==="base.html"||o.startsWith("system"))continue;let n=le(t,o),s=b(n);if(!s.includes("dnd_area")&&!s.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(s),r=/isAvailableForNewContent\s*:\s*true/i.test(s);if(i&&r)continue;let a=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+=`
271
+ Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=ce(t,"css");if(h(n)){for(let a of Bt(n))if((a.includes("theme")||a.includes("page"))&&a.endsWith(".css")&&a!=="theme-overrides.css"&&a!=="main.css"&&a!=="style.css"){o.sharedCss=b(ce(n,a));break}}let s=ce(t,"js");if(h(s)){for(let a of Bt(s))if((a.includes("animation")||a.includes("page"))&&a.endsWith(".js")&&a!=="main.js"){o.sharedJs=b(ce(s,a));break}}let i=ce(t,"templates");if(h(i)){for(let a of Bt(i))if(a.endsWith(".html")&&!a.startsWith("system")&&a!=="base.html"){let l=b(ce(i,a));if(l.includes("dnd_area")){o.template=l;break}}}let r=ce(t,"modules");if(h(r))for(let a of Bt(r)){if(!a.endsWith(".module"))continue;let l=ce(r,a);if(!xr(l).isDirectory())continue;let c={moduleName:a.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=ce(l,"fields.json");h(u)&&(c.fieldsJson=b(u));let p=ce(l,"meta.json");h(p)&&(c.metaJson=b(p));let f=ce(l,"module.html");h(f)&&(c.moduleHtml=b(f));let g=ce(l,"module.css");h(g)&&(c.moduleCss=b(g));let y=ce(l,"module.js");h(y)&&(c.moduleJs=b(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};function Cr(e,t){switch(e){case"claude-code":return new Gt(t);case"gemini-cli":return new Kt;case"codex-cli":return new Yt;case"api":return new Ut}}async function Vt(e){await ne("Converting React to HubSpot Modules"),await Ae(`AI will now analyze your React code and create
272
+ HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let t=Cr(e.aiEngine,e.model),o=ae(),n=await se();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"?_(S):n.message(S)}}),r=((Date.now()-s)/1e3).toFixed(0);n.stop(`AI conversion complete (${r}s)`);let a=Ar(e.themePath);for(let y of a)_(`Auto-fixed: ${y}`);let l=Ir(e.themePath,i),c=[];for(let y of l){let S=y.passed?"\u2705":"\u274C",C=y.passed?"":y.critical?" (CRITICAL)":" (cosmetic)";c.push(`${S} ${y.label}${C}`)}let u=l.filter(y=>y.passed).length;c.push(`
273
+ ${u}/${l.length} checks passed`),await Ae(c.join(`
274
+ `),"Conversion Checklist");let p=l.filter(y=>!y.passed&&y.critical),f=l.filter(y=>!y.passed&&!y.critical);if(p.length>0){if(M(`${p.length} critical issue(s) \u2014 upload will likely fail:
275
+ `+p.map(S=>` - ${S.label}`).join(`
276
+ `)),!await X({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else f.length>0&&U(`${f.length} non-critical issue(s) \u2014 page will work but may look incomplete:
277
+ `+f.map(y=>` - ${y.label}`).join(`
278
+ `));let g=ue(e.themePath,"..","vibespot-conversion.log");return h(g)&&(await X({message:"Keep conversion log file for debugging?",initialValue:!1})?_(`Log saved: ${g}`):Mo(g)),await oe("Files ready for upload!"),i}function Ar(e){let t=[];$r(e),Tr(e);let o=ue(e,"modules");if(h(o))for(let s of yt(o)){if(!s.endsWith(".module"))continue;let i=ue(o,s,"fields.json");if(!h(i))continue;let r=s.replace(".module",""),a=b(i),l=!1;a.includes('"textarea"')&&(a=a.replace(/"textarea"/g,'"text"'),l=!0,t.push(`${r}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(a)&&(a=a.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,t.push(`${r}: reserved field name "name" \u2192 "item_name"`));try{let u=JSON.parse(a),p=!1;jo(u)&&(p=!0,t.push(`${r}: fixed choice field format`)),Fo(u)&&(p=!0,t.push(`${r}: fixed link field default value`)),p&&(a=JSON.stringify(u,null,2)+`
279
+ `,l=!0)}catch{t.push(`${r}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&O(i,a);let c=ue(o,s,"module.html");if(h(c)){let u=b(c);u.includes("now()")&&(u=u.replace(/now\(\)/g,"local_dt"),O(c,u),t.push(`${r}: now() \u2192 local_dt`))}}let n=ue(e,"templates");if(h(n))for(let s of yt(n)){if(!s.endsWith(".html"))continue;let i=ue(n,s),r=b(i);(r.includes("hubdb_table")||r.includes("hubdb_table_rows"))&&(Mo(i),t.push(`Removed ${s} (HubDB requires CMS Hub Pro/Enterprise)`))}return t}function jo(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 r=i.charAt(0).toUpperCase()+i.slice(1);return[i,r]}return i}),t=!0),Array.isArray(n.children)&&jo(n.children)&&(t=!0)}return t}function Fo(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 r=typeof s=="string"?s:"";n.default={url:{href:r,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&Fo(n.children)&&(t=!0)}return t}function Ir(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 r=t.modules.filter(p=>!p.moduleCss).map(p=>p.moduleName),a=r.length===0;o.push({label:a?"module.css created for each module":`module.css missing for: ${r.join(", ")}`,passed:n>0&&a,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=ue(e,"templates"),u=!1;if(h(c))for(let p of yt(c)){if(!p.endsWith(".html")||p==="base.html"||p.startsWith("system"))continue;let f=b(ue(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 $r(e){let t=ue(e,"templates");if(h(t))for(let o of yt(t)){if(!o.endsWith(".html")||o==="base.html"||o.startsWith("system"))continue;let n=ue(t,o),s=b(n);if(!s.includes("dnd_area")&&!s.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(s),r=/isAvailableForNewContent\s*:\s*true/i.test(s);if(i&&r)continue;let a=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+=`
249
280
  templateType: page`),r||(c+=`
250
281
  isAvailableForNewContent: true`),/label\s*:/i.test(c)||(c+=`
251
282
  label: ${a}`),s=c+s.slice(l)}else s=`<!--
@@ -253,40 +284,39 @@ ${u}/${l.length} checks passed`),await ue(c.join(`
253
284
  isAvailableForNewContent: true
254
285
  label: ${a}
255
286
  -->
256
- `+s;E(n,s),k(`Template "${o}" \u2014 annotations verified`)}}function Ci(e){let t=le(e,"modules");if(g(t))for(let o of rt(t)){if(!o.endsWith(".module"))continue;let n=le(t,o,"meta.json");if(g(n))try{let s=JSON.parse(b(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&&E(n,JSON.stringify(s,null,2)+`
257
- `)}catch{}}}import{join as po,basename as Ei}from"path";import{join as Y}from"path";import{readdirSync as _e,rmSync as Ai}from"fs";function Nt(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 _t(e){let t=[];return so(e)&&t.push("textarea \u2192 text"),io(e)&&t.push("name \u2192 item_name"),ro(e)&&t.push("now() \u2192 local_dt"),ao(e)&&t.push("Removed HubDB templates"),lo(e)&&t.push("Fixed link field defaults"),co(e)&&t.push("Fixed rgba/invalid color values \u2192 hex"),Ii(e)&&t.push("Stripped CDN @import statements"),t}function oo(e,t){return t.message.includes("textarea")?so(e):t.message.includes("reserved field name")?io(e):t.message.includes("now()")?ro(e):t.message.includes("HubDB")?ao(e):t.message.includes("invalid default value")||t.message.includes("deserialization")?lo(e):t.message.includes("invalid format")&&t.message.includes("color")?co(e):!1}function so(e){let t=!1,o=Y(e,"modules");if(!g(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Y(o,n,"fields.json");if(!g(s))continue;let i=b(s);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),E(s,i),t=!0)}return t}function io(e){let t=!1,o=Y(e,"modules");if(!g(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Y(o,n,"fields.json");if(!g(s))continue;let i=b(s);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),E(s,i),t=!0)}return t}function ro(e){let t=!1,o=Y(e,"modules");if(!g(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Y(o,n,"module.html");if(!g(s))continue;let i=b(s);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),E(s,i),t=!0)}return t}function ao(e){let t=!1,o=Y(e,"templates");if(!g(o))return!1;for(let n of _e(o)){if(!n.endsWith(".html"))continue;let s=Y(o,n),i=b(s);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(Ai(s),t=!0)}return t}function lo(e){let t=!1,o=Y(e,"modules");if(!g(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Y(o,n,"fields.json");if(g(s))try{let i=JSON.parse(b(s));mo(i)&&(E(s,JSON.stringify(i,null,2)+`
258
- `),t=!0)}catch{}}return t}function Ii(e){let t=!1,o=Y(e,"css");if(g(o))for(let s of _e(o)){if(!s.endsWith(".css"))continue;let i=Y(o,s),r=b(i),a=r.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");a!==r&&(E(i,a),t=!0)}let n=Y(e,"modules");if(g(n))for(let s of _e(n)){if(!s.endsWith(".module"))continue;let i=Y(n,s,"module.css");if(!g(i))continue;let r=b(i),a=r.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");a!==r&&(E(i,a),t=!0)}if(g(n))for(let s of _e(n)){if(!s.endsWith(".module"))continue;let i=Y(n,s,"module.html");if(!g(i))continue;let r=b(i),a=r.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");a!==r&&(E(i,a),t=!0)}return t}function co(e){let t=!1,o=Y(e,"modules");if(!g(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Y(o,n,"fields.json");if(g(s))try{let i=JSON.parse(b(s));uo(i)&&(E(s,JSON.stringify(i,null,2)+`
259
- `),t=!0)}catch{}}return t}function uo(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"&&!ki(i)){let r=$i(i);r&&(s.color=r.hex,r.opacity!==void 0&&(s.opacity=r.opacity),t=!0)}}Array.isArray(n.children)&&uo(n.children)&&(t=!0)}return t}function ki(e){return/^#[0-9a-fA-F]{6}$/.test(e)}function $i(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])),r=Math.min(255,parseInt(o[2])),a=Math.min(255,parseInt(o[3])),l=`#${i.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}${a.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 mo(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 r=typeof s=="string"?s:"";n.default={url:{href:r,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&mo(n.children)&&(t=!0)}return t}function Ti(e){return(e.match(/^Uploaded file /gm)||[]).length}async function Be(e){await Q("Uploading to HubSpot");let t=Ei(e)||e,o=await oe(),n=3;for(let s=1;s<=n;s++){o.start(s===1?"Uploading theme...":`Retrying upload (attempt ${s}/${n})...`);let i=x(`hs cms upload "${e}" "${t}"`,{cwd:po(e,"..")}),r=[i.stdout,i.stderr].filter(Boolean).join(`
260
- `),a=Ti(r);if(i.success)return o.stop(`All files uploaded! (${a} files)`),await X("Upload complete!"),!0;let l=Nt(r);if(a>0?o.stop(`${a} files uploaded, but some errors occurred`):o.stop("Upload failed"),l.length===0){if(T(`Upload error:
261
- ${r.slice(0,500)}`),a>0&&(J(`Most files uploaded successfully. The theme may already be usable in HubSpot.
262
- You can check your HubSpot Design Manager to verify.`),await B({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(s<n){if(!await B({message:"Try uploading again?"}))break;continue}break}let c=!1;for(let u of l)u.fixable?oo(e,u)?(k(`Auto-fixed: ${u.message}`),c=!0):J(`Could not auto-fix: ${u.message}`):T(u.message);if(!(c&&s<n)){if(a>0&&(J(`${a} files uploaded successfully despite errors.
263
- The theme may work \u2014 check HubSpot Design Manager.`),await B({message:"Continue anyway?",initialValue:!0})))return!0;c||(o.start("Cleaning up stuck modules..."),x(`hs cms delete "${t}/modules"`,{cwd:po(e,"..")}),o.stop("Cleaned up modules, retrying..."))}}return T("Upload failed after multiple attempts. Try running `hs cms upload` manually to see detailed errors."),!1}import{execSync as en}from"child_process";import{rmSync as Ni}from"fs";import{basename as fo}from"path";async function go(e){let{portalId:t,sourceDir:o,themePath:n,wasCloned:s}=e;await Q("You're all set!");let r=yt(t)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await ue(`Your React page has been converted and uploaded to HubSpot.
287
+ `+s;O(n,s),_(`Template "${o}" \u2014 annotations verified`)}}function Tr(e){let t=ue(e,"modules");if(h(t))for(let o of yt(t)){if(!o.endsWith(".module"))continue;let n=ue(t,o,"meta.json");if(h(n))try{let s=JSON.parse(b(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&&O(n,JSON.stringify(s,null,2)+`
288
+ `)}catch{}}}import{join as Vo,basename as Fr}from"path";import{join as Q}from"path";import{readdirSync as _e,rmSync as kr}from"fs";function zt(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 qt(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 Xt(e){let t=[];return Do(e)&&t.push("textarea \u2192 text"),Ho(e)&&t.push("name \u2192 item_name"),Lo(e)&&t.push("now() \u2192 local_dt"),Go(e)&&t.push("Removed HubDB templates"),Uo(e)&&t.push("Fixed link field defaults"),Wo(e)&&t.push("Fixed rgba/invalid color values \u2192 hex"),Er(e)&&t.push("Stripped CDN @import statements"),t}function Jo(e,t){return t.message.includes("textarea")?Do(e):t.message.includes("reserved field name")?Ho(e):t.message.includes("now()")?Lo(e):t.message.includes("HubDB")?Go(e):t.message.includes("invalid default value")||t.message.includes("deserialization")?Uo(e):t.message.includes("invalid format")&&t.message.includes("color")?Wo(e):!1}function Do(e){let t=!1,o=Q(e,"modules");if(!h(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Q(o,n,"fields.json");if(!h(s))continue;let i=b(s);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),O(s,i),t=!0)}return t}function Ho(e){let t=!1,o=Q(e,"modules");if(!h(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Q(o,n,"fields.json");if(!h(s))continue;let i=b(s);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),O(s,i),t=!0)}return t}function Lo(e){let t=!1,o=Q(e,"modules");if(!h(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Q(o,n,"module.html");if(!h(s))continue;let i=b(s);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),O(s,i),t=!0)}return t}function Go(e){let t=!1,o=Q(e,"templates");if(!h(o))return!1;for(let n of _e(o)){if(!n.endsWith(".html"))continue;let s=Q(o,n),i=b(s);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(kr(s),t=!0)}return t}function Uo(e){let t=!1,o=Q(e,"modules");if(!h(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Q(o,n,"fields.json");if(h(s))try{let i=JSON.parse(b(s));Bo(i)&&(O(s,JSON.stringify(i,null,2)+`
289
+ `),t=!0)}catch{}}return t}function Er(e){let t=!1,o=Q(e,"css");if(h(o))for(let s of _e(o)){if(!s.endsWith(".css"))continue;let i=Q(o,s),r=b(i),a=r.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");a!==r&&(O(i,a),t=!0)}let n=Q(e,"modules");if(h(n))for(let s of _e(n)){if(!s.endsWith(".module"))continue;let i=Q(n,s,"module.css");if(!h(i))continue;let r=b(i),a=r.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");a!==r&&(O(i,a),t=!0)}if(h(n))for(let s of _e(n)){if(!s.endsWith(".module"))continue;let i=Q(n,s,"module.html");if(!h(i))continue;let r=b(i),a=r.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");a!==r&&(O(i,a),t=!0)}return t}function Wo(e){let t=!1,o=Q(e,"modules");if(!h(o))return!1;for(let n of _e(o)){if(!n.endsWith(".module"))continue;let s=Q(o,n,"fields.json");if(h(s))try{let i=JSON.parse(b(s));Ko(i)&&(O(s,JSON.stringify(i,null,2)+`
290
+ `),t=!0)}catch{}}return t}function Ko(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"&&!Nr(i)){let r=_r(i);r&&(s.color=r.hex,r.opacity!==void 0&&(s.opacity=r.opacity),t=!0)}}Array.isArray(n.children)&&Ko(n.children)&&(t=!0)}return t}function Nr(e){return/^#[0-9a-fA-F]{6}$/.test(e)}function _r(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])),r=Math.min(255,parseInt(o[2])),a=Math.min(255,parseInt(o[3])),l=`#${i.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}${a.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 Bo(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 r=typeof s=="string"?s:"";n.default={url:{href:r,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&Bo(n.children)&&(t=!0)}return t}import{readdirSync as Rr}from"fs";import{join as Pr,relative as Or}from"path";var Mr=new Set([".git","node_modules",".vibespot",".DS_Store"]);function Yo(e){let t=[];for(let o of Rr(e,{withFileTypes:!0})){if(Mr.has(o.name)||o.name.startsWith(".")&&o.name!==".gitkeep")continue;let n=Pr(e,o.name);o.isDirectory()?t.push(...Yo(n)):o.isFile()&&t.push(n)}return t}async function jr(e,t,o){let n=0;async function s(){for(;n<e.length;){let r=n++;await o(e[r])}}let i=Array.from({length:Math.min(t,e.length)},()=>s());await Promise.all(i)}async function Qt(e,t,o,n={}){let s=n.concurrency??5,i=Yo(t),r=i.length,a=0,l=0,c=[];return await jr(i,s,async u=>{let p=Or(t,u).replace(/\\/g,"/"),f=`${o}/${p}`;n.onFileStart?.(p);let g=await go(e,f,u);if(g.success)a++,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?.(a+l,r)}),{success:l===0,uploaded:a,failed:l,total:r,errors:c}}function Jr(e){return(e.match(/^Uploaded file /gm)||[]).length}async function qe(e){await ne("Uploading to HubSpot");let t=Fr(e)||e,o=N(),n=fe(),s=o.hubspotUploadMode!=="cli"&&!!n,i=await se(),r=3;for(let a=1;a<=r;a++){i.start(a===1?"Uploading theme...":`Retrying upload (attempt ${a}/${r})...`);let l=[],c=0,u=!1;if(s){let f=await Qt(n,e,t,{onFileComplete:()=>{c++}});u=f.success,u?c=f.uploaded:l=zt(f.errors)}else{let f=x(`hs cms upload "${e}" "${t}"`,{cwd:Vo(e,"..")}),g=[f.stdout,f.stderr].filter(Boolean).join(`
291
+ `);c=Jr(g),u=f.success,u||(l=qt(g))}if(u)return i.stop(`All files uploaded! (${c} files)`),await oe("Upload complete!"),!0;if(c>0?i.stop(`${c} files uploaded, but some errors occurred`):i.stop("Upload failed"),l.length===0){if(M("Upload failed with unknown error."),c>0&&(U(`Most files uploaded successfully. The theme may already be usable in HubSpot.
292
+ You can check your HubSpot Design Manager to verify.`),await X({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(a<r){if(!await X({message:"Try uploading again?"}))break;continue}break}let p=!1;for(let f of l)f.fixable?Jo(e,f)?(_(`Auto-fixed: ${f.message}`),p=!0):U(`Could not auto-fix: ${f.message}`):M(f.message);if(!(p&&a<r)){if(c>0&&(U(`${c} files uploaded successfully despite errors.
293
+ The theme may work \u2014 check HubSpot Design Manager.`),await X({message:"Continue anyway?",initialValue:!0})))return!0;if(!p){if(i.start("Cleaning up stuck modules..."),s)try{await vn(n,`${t}/modules`)}catch{}else x(`hs cms delete "${t}/modules"`,{cwd:Vo(e,"..")});i.stop("Cleaned up modules, retrying...")}}}return M("Upload failed after multiple attempts."),!1}import{execSync as In}from"child_process";import{rmSync as Dr}from"fs";import{basename as zo}from"path";async function qo(e){let{portalId:t,sourceDir:o,themePath:n,wasCloned:s}=e;await ne("You're all set!");let r=ut(t)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await Ae(`Your React page has been converted and uploaded to HubSpot.
264
294
  The theme and modules are now in your account, but you still
265
- need to ${S.bold("create a new landing page")} that uses them.
295
+ need to ${v.bold("create a new landing page")} that uses them.
266
296
 
267
297
  Next steps:
268
298
 
269
- ${S.bold("1.")} Go to HubSpot ${S.muted("\u2192")} Content ${S.muted("\u2192")} Landing Pages ${S.muted("\u2192")} Create
270
- ${S.bold("2.")} Choose your uploaded theme from the theme picker
271
- ${S.bold("3.")} Select the landing page template that was just created
272
- ${S.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
273
- ${S.bold("5.")} Click each section to edit text, images, and colors
274
- ${S.bold("6.")} Upload images via File Manager ${S.muted("(Settings \u2192 Files)")}
275
- ${S.bold("7.")} Preview and publish!`,"What's next"),await B({message:"Open HubSpot Landing Pages in your browser?"})){let c=t?`https://${r}/page-ui/${t}/management/pages/landing`:`https://${r}`;try{let u=process.platform;u==="darwin"?en(`open "${c}"`):u==="win32"?en(`cmd /c start "${c}"`):en(`xdg-open "${c}"`),k("Opening HubSpot Landing Pages...")}catch{G(`Open this URL in your browser: ${S.info(c)}`)}}let l=[];if(s&&g(o)&&l.push({path:o,label:`Cloned source (${fo(o)})`}),g(n)&&l.push({path:n,label:`Theme directory (${fo(n)})`}),l.length>0&&await B({message:"Clean up local working directories?"}))for(let u of l)try{Ni(u.path,{recursive:!0,force:!0}),k(`Removed ${u.label}`)}catch{J(`Could not remove ${u.label} \u2014 delete manually if needed.`)}await X(`Thanks for using hub${S.vibes("Vibes")}! ${S.vibes("~")}`)}async function ho(){be();let e=await St(),t=await wt();ne({lastSourcePath:t.sourceDir});let o=await xt();ne({lastThemePath:o.themePath}),await Tt({aiEngine:e.aiEngine,model:e.model,sourceDir:t.sourceDir,themePath:o.themePath}),await Be(o.themePath),await go({portalId:e.portalId,sourceDir:t.sourceDir,themePath:o.themePath,wasCloned:t.wasCloned})}async function yo(){be(),await St()}async function bo(){be();let e=j();e.aiEngine||(T("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let t=await wt(),o=await xt();await Tt({aiEngine:e.aiEngine,sourceDir:t.sourceDir,themePath:o.themePath})}async function vo(){be();let e=j();if(e.lastThemePath)if(await B({message:`Upload from ${e.lastThemePath}?`}))await Be(e.lastThemePath);else{let o=await Se({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await Be(o)}else{let t=await Se({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:o=>o.trim()?void 0:"Path is required"});await Be(t)}}async function So(){be(),await Q("Environment Diagnostics");let e=0,t=tt();t.found?bt(t.version)?k(`Node.js v${t.version}`):(J(`Node.js v${t.version} \u2014 too old (need 18+)`),G(" Update at https://nodejs.org"),e++):(T("Node.js \u2014 not installed"),G(" Install from https://nodejs.org"),e++);let o=nt();o.found?k(`Git ${o.version}`):(T("Git \u2014 not installed"),G(" Install from https://git-scm.com"),e++);let n=Ee();if(!n.found)J("HubSpot CLI \u2014 not installed (only needed for deployment)"),G(" Install: npm install -g @hubspot/cli");else if(!Mn(n.version))J(`HubSpot CLI v${n.version} \u2014 too old (need v8+)`),G(" Update: npm install -g @hubspot/cli@latest"),e++;else{k(`HubSpot CLI v${n.version}`);let f=ve();f.authenticated?k(`HubSpot portal${f.portalName?`: ${f.portalName}`:""} (ID: ${f.portalId})`):(J("HubSpot \u2014 not authenticated"),G(" Run: hs init"))}let s=ot();s.found?k(`Claude Code ${s.version} at ${s.path}`):G(S.muted("Claude Code \u2014 not installed"));let i=st();i.found?k(`Gemini CLI ${i.version} at ${i.path}`):G(S.muted("Gemini CLI \u2014 not installed"));let r=it();r.found?k(`OpenAI Codex ${r.version} at ${r.path}`):G(S.muted("OpenAI Codex \u2014 not installed"));let a=j(),l=!!(a.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(a.openaiApiKey||process.env.OPENAI_API_KEY),u=!!(a.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?k("Anthropic API key configured"):G(S.muted("Anthropic API key \u2014 not set")),c?k("OpenAI API key configured"):G(S.muted("OpenAI API key \u2014 not set")),u?k("Google AI API key configured"):G(S.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"};a.aiEngine&&k(`AI engine: ${p[a.aiEngine]||a.aiEngine}`),a.lastThemePath&&G(S.muted(`Last theme: ${a.lastThemePath}`)),!s.found&&!i.found&&!r.found&&!l&&!c&&!u&&(J("No AI engine available"),G(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),G(" Or install: Claude Code \u2014 https://claude.ai/code"),G(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),G(" Codex CLI \u2014 https://github.com/openai/codex"),e++),console.log(),e===0?await X("Everything looks good!"):await X(S.warn(`${e} issue${e>1?"s":""} found \u2014 see above`))}import{join as Ut}from"path";import{existsSync as Hr}from"fs";import{execSync as kn}from"child_process";import Kt from"chalk";import{createServer as Rr}from"http";import{readFileSync as Bs,existsSync as Ys}from"fs";import{join as In,extname as Or}from"path";import{createHash as Pr}from"crypto";import{WebSocketServer as jr}from"ws";import{readFileSync as ae,readdirSync as Ve,existsSync as R,writeFileSync as V,mkdirSync as Oe,rmSync as on,renameSync as sn}from"fs";import{join as w,dirname as Pi}from"path";import{homedir as ji}from"os";import{existsSync as Re,writeFileSync as _i,mkdirSync as Ri}from"fs";import{join as xe}from"path";var Rt=null;function me(){return Rt!==null||(Rt=x("git --version").success),Rt}function tn(e){if(!me())return!1;if(Re(xe(e,".git")))return wo(e),!0;let t=x("git init",{cwd:e});return t.success?(Oi(e),wo(e),x("git add -A",{cwd:e}),x('git commit -m "Initial theme"',{cwd:e}),!0):(console.warn(`[project-git] git init failed in ${e}: ${t.stderr}`),!1)}function wo(e){let t=xe(e,".vibespot");Re(t)||Ri(t,{recursive:!0})}function Oi(e){let t=xe(e,".gitignore");_i(t,[".vibespot/","node_modules/",""].join(`
276
- `),"utf-8")}function nn(e,t){if(!me()||!Re(xe(e,".git"))||(x("git add -A",{cwd:e}),x("git diff --cached --quiet",{cwd:e}).success))return null;let n=t.length>72?t.slice(0,69)+"...":t,s=x(`git commit -m "${n.replace(/"/g,'\\"')}"`,{cwd:e});if(!s.success)return console.warn(`[project-git] commit failed: ${s.stderr}`),null;let i=x("git rev-parse --short HEAD",{cwd:e});return i.success?i.stdout:null}function xo(e,t,o,n){if(!me()||!Re(xe(e,".git")))return null;for(let p of n){let f=xe(e,p);Re(f)&&x(`git add "${p}"`,{cwd:e})}if(x("git diff --cached --quiet",{cwd:e}).success)return null;let i=`[${t}] `,r=72-i.length,a=o.length>r?o.slice(0,r-3)+"...":o,l=i+a,c=x(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:e});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let u=x("git rev-parse --short HEAD",{cwd:e});return u.success?u.stdout:null}function Co(e,t=50){if(!me())return[];if(!Re(xe(e,".git")))return[];let o=x(`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(`
277
- `)){let i=s.split("|");if(i.length<4)continue;let r=parseInt(i[3],10)*1e3;n.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:r,date:new Date(r).toISOString()})}return n}function Ao(e,t,o=50){if(!me())return[];if(!Re(xe(e,".git")))return[];let n=t.replace(/[[\]\\]/g,"\\$&"),s=x(`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 r of s.stdout.split(`
278
- `)){let a=r.split("|");if(a.length<4)continue;let l=parseInt(a[3],10)*1e3;i.push({hash:a[0],fullHash:a[1],message:a[2],timestamp:l,date:new Date(l).toISOString()})}return i}function Io(e,t){if(!me())return{success:!1,error:"Git not available"};if(!Re(xe(e,".git")))return{success:!1,error:"Not a git repo"};let o=x(`git cat-file -t ${t}`,{cwd:e});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${t} not found`};let n=x(`git log --format="%s" -1 ${t}`,{cwd:e}),s=n.success?n.stdout:t,i=x(`git checkout ${t} -- .`,{cwd:e});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let r=`Rollback to: ${s}`.slice(0,72);return x(`git commit -m "${r.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}function ko(e,t,o,n){if(!me())return{success:!1,error:"Git not available"};if(!Re(xe(e,".git")))return{success:!1,error:"Not a git repo"};let s=x(`git cat-file -t ${o}`,{cwd:e});if(!s.success||s.stdout.trim()!=="commit")return{success:!1,error:`Commit ${o} not found`};let i=x(`git log --format="%s" -1 ${o}`,{cwd:e}),r=i.success?i.stdout:o,a=0;for(let u of n)x(`git checkout ${o} -- "${u}"`,{cwd:e}).success&&a++;if(a===0)return{success:!1,error:"No files could be restored from that commit"};x("git add -A",{cwd:e});let c=`${`[${t}] `}Rollback to: ${r}`.slice(0,72);return x(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}var U=w(ji(),".vibespot","sessions"),rn=w(U,"_index.json"),Ye=null;function Ot(){if(Ye)return Ye;try{return R(rn)?(Ye=JSON.parse(ae(rn,"utf-8")),Ye):an()}catch{return an()}}function Pt(e){Ye=e;try{Oe(U,{recursive:!0}),V(rn,JSON.stringify(e),"utf-8")}catch{}}function an(){if(!R(U))return[];let e=[];for(let t of Ve(U).filter(o=>o.endsWith(".json")&&o!=="_index.json"))try{let o=JSON.parse(ae(w(U,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 Ye=e,Pt(e),e}function Mi(e){let t=Ot(),o=e.templates||[],n={id:e.id,themeName:e.themeName,updatedAt:e.updatedAt,moduleCount:o.reduce((i,r)=>i+(r.modules?.length||0),0),templateCount:o.length},s=t.findIndex(i=>i.id===e.id);s>=0?t[s]=n:t.push(n),Pt(t)}function Ji(e){let t=Ot().filter(o=>o.id!==e);Pt(t)}function Di(e){let t=Ot().filter(o=>o.themeName!==e);Pt(t)}var m=null;function jt(e,t){let o={id:Yi(),themePath:e,themeName:t,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return m=o,tn(e),o}function Eo(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 Je(){return!m||!m.activeTemplateId||!m.templates?.length?null:m.templates.find(e=>e.id===m.activeTemplateId)||null}function ln(e){if(!m)return!1;let t=m.templates.find(o=>o.id===e);return t?(m.activeTemplateId=e,cn(t),m.updatedAt=Date.now(),!0):!1}function To(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,cn(i),m.updatedAt=Date.now(),i}function No(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 _o(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?ln(m.templates[0].id):(m.activeTemplateId="",m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",m.messages=[])),m.updatedAt=Date.now(),!0)}function ze(){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 cn(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 De(){if(!m)return;let e=Je();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 I(){return m}function Fe(e,t){m&&(m.messages.push({role:e,content:t,timestamp:Date.now()}),m.updatedAt=Date.now(),De(),Fi())}function Mt(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(),De()}}function Ro(e){m&&(m.moduleOrder=e,m.updatedAt=Date.now(),De())}function Oo(e){m&&(m.modules=m.modules.filter(t=>t.moduleName!==e),m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),De())}function Po(e){m&&(m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),De())}function jo(e,t,o){if(!m)return;let n=m.modules.find(s=>s.moduleName===e);if(n)try{let s=JSON.parse(n.fieldsJson);Lo(s,t,o),n.fieldsJson=JSON.stringify(s,null,2),m.updatedAt=Date.now(),De()}catch{}}function ce(){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 Jt(e){if(!m)return;let t=Li(e);t.length>0&&m.messages.length===0&&(m.messages=t),tn(e);let o=w(e,"modules");if(!R(o))return;let n=Ve(o,{withFileTypes:!0});for(let l of n){if(!l.isDirectory()||!l.name.endsWith(".module"))continue;let c=w(o,l.name),u=l.name.replace(/\.module$/,""),p={moduleName:u,fieldsJson:Z(w(c,"fields.json")),metaJson:Z(w(c,"meta.json")),moduleHtml:Z(w(c,"module.html")),moduleCss:Z(w(c,"module.css")),moduleJs:Z(w(c,"module.js"))||void 0};p.fieldsJson&&p.moduleHtml&&(m.modules.push(p),m.moduleOrder.push(u))}let s=w(e,"css"),i=w(e,"js");if(R(s)){let l=Ve(s).filter(c=>c.endsWith("-theme.css")||c.endsWith("-theme.css"));l.length>0&&(m.sharedCss=Z(w(s,l[0])))}if(R(i)){let l=Ve(i).filter(c=>c.endsWith("-animations.js"));l.length>0&&(m.sharedJs=Z(w(i,l[0])))}let r=w(e,".vibespot","styleguide.md"),a=w(e,".vibespot","brandvoice.md");(R(r)||R(a))&&(m.brandAssets||(m.brandAssets={}),R(r)&&(m.brandAssets.styleguide=Z(r)),R(a)&&(m.brandAssets.brandvoice=Z(a))),m.templates||(m.templates=[]),m.activeTemplateId||(m.activeTemplateId=""),Eo(m)}function P(){if(!m)return;Oe(U,{recursive:!0});let e=w(U,`${m.id}.json`);V(e,JSON.stringify(m,null,2),"utf-8"),Mi(m)}function Dt(e){let t=w(U,e+".json");if(!R(t))return null;try{let o=JSON.parse(ae(t,"utf-8"));return o.templates||(o.templates=[]),o.activeTemplateId||(o.activeTemplateId=""),Eo(o),m=o,o}catch{return null}}function Ft(){return R(U)?Ot():[]}function Mo(e,t=!1){let o=w(U,e+".json"),n="";if(t)try{let s=JSON.parse(ae(o,"utf-8"));n=s.themeName||"",s.themePath&&R(s.themePath)&&on(s.themePath,{recursive:!0,force:!0})}catch{}else try{n=JSON.parse(ae(o,"utf-8")).themeName||""}catch{}try{R(o)&&on(o)}catch{}if(n&&R(U)){for(let s of Ve(U).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(ae(w(U,s),"utf-8")).themeName===n&&on(w(U,s))}catch{}Di(n)}else Ji(e);m?.id===e&&(m=null)}function Jo(e,t){let o=w(U,e+".json");if(!R(o))return{ok:!1,error:"Session not found"};let n;try{n=JSON.parse(ae(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,r=w(Pi(i),t);if(R(i)){if(R(r))return{ok:!1,error:"A project with that name already exists"};try{sn(i,r)}catch(f){return{ok:!1,error:`Failed to rename folder: ${f instanceof Error?f.message:String(f)}`}}let a=w(r,"css",`${s}-theme.css`),l=w(r,"css",`${t}-theme.css`);if(R(a))try{sn(a,l)}catch{}let c=w(r,"js",`${s}-animations.js`),u=w(r,"js",`${t}-animations.js`);if(R(c))try{sn(c,u)}catch{}let p=w(r,"theme.json");if(R(p))try{let f=JSON.parse(ae(p,"utf-8"));f.label=t,f.name=t,V(p,JSON.stringify(f,null,2),"utf-8")}catch{}}if(R(U))for(let a of Ve(U).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(ae(w(U,a),"utf-8"));l.themeName===s&&(l.themeName=t,l.themePath=r,l.updatedAt=Date.now(),V(w(U,a),JSON.stringify(l,null,2),"utf-8"))}catch{}return m&&m.themeName===s&&(m.themeName=t,m.themePath=r,m.updatedAt=Date.now()),an(),{ok:!0}}function qe(){if(!m)return;let e=m.themePath,t=new Map;if(m.templates.length>0)for(let n of m.templates)for(let s of n.modules)t.set(s.moduleName,s);for(let n of m.modules)t.set(n.moduleName,n);let o=w(e,"modules");Oe(o,{recursive:!0});for(let n of t.values())Oe(w(o,`${n.moduleName}.module`),{recursive:!0});for(let n of t.values()){let s=w(o,`${n.moduleName}.module`);V(w(s,"fields.json"),n.fieldsJson,"utf-8"),V(w(s,"meta.json"),n.metaJson,"utf-8"),V(w(s,"module.html"),n.moduleHtml,"utf-8"),V(w(s,"module.css"),n.moduleCss,"utf-8"),n.moduleJs&&V(w(s,"module.js"),n.moduleJs,"utf-8")}if(m.sharedCss){let n=w(e,"css");Oe(n,{recursive:!0}),V(w(n,`${m.themeName}-theme.css`),m.sharedCss,"utf-8")}if(m.sharedJs){let n=w(e,"js");Oe(n,{recursive:!0}),V(w(n,`${m.themeName}-animations.js`),m.sharedJs,"utf-8")}if(m.templates.length>0){let n=w(e,"templates");Oe(n,{recursive:!0});for(let s of m.templates){if(s.pageType==="module_only"||s.modules.length===0)continue;let i=s.template||Wi(s),r=$o(i,s.label,s.pageType);V(w(n,`${s.id}.html`),r,"utf-8"),s.pageType==="blog_post"&&Ui(n,s)}}else if(m.modules.length>0){let n=m.template||Bi(),s=w(e,"templates");Oe(s,{recursive:!0});let i=$o(n,`${m.themeName} Landing Page`);V(w(s,`lp-${m.themeName}.html`),i,"utf-8")}Hi(),Gi()}function Fi(){if(m)try{let e=w(m.themePath,".vibespot");Oe(e,{recursive:!0});let t={sessionId:m.id,themeName:m.themeName,messages:m.messages,updatedAt:Date.now()};V(w(e,"chat.json"),JSON.stringify(t,null,2),"utf-8")}catch{}}function Li(e){let t=w(e,".vibespot","chat.json");if(!R(t))return[];try{let o=JSON.parse(ae(t,"utf-8"));return Array.isArray(o.messages)?o.messages:[]}catch{return[]}}function Do(){m&&(m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",Jt(m.themePath),m.updatedAt=Date.now(),De())}function Fo(){if(!m)return;let e=Je();if(!e)return;let t=m.themePath,o=w(t,"modules");e.modules=[];for(let n of e.moduleOrder){let s=w(o,`${n}.module`);if(!R(s))continue;let i={moduleName:n,fieldsJson:Z(w(s,"fields.json")),metaJson:Z(w(s,"meta.json")),moduleHtml:Z(w(s,"module.html")),moduleCss:Z(w(s,"module.css")),moduleJs:Z(w(s,"module.js"))||void 0};i.fieldsJson&&i.moduleHtml&&e.modules.push(i)}if(e.templateFile){let n=w(t,e.templateFile);R(n)&&(e.template=Z(n))}cn(e),m.updatedAt=Date.now()}function Hi(){if(!m)return;let e=w(m.themePath,"templates","layouts","base.html");if(R(e))try{let t=ae(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+`
299
+ ${v.bold("1.")} Go to HubSpot ${v.muted("\u2192")} Content ${v.muted("\u2192")} Landing Pages ${v.muted("\u2192")} Create
300
+ ${v.bold("2.")} Choose your uploaded theme from the theme picker
301
+ ${v.bold("3.")} Select the landing page template that was just created
302
+ ${v.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
303
+ ${v.bold("5.")} Click each section to edit text, images, and colors
304
+ ${v.bold("6.")} Upload images via File Manager ${v.muted("(Settings \u2192 Files)")}
305
+ ${v.bold("7.")} Preview and publish!`,"What's next"),await X({message:"Open HubSpot Landing Pages in your browser?"})){let c=t?`https://${r}/page-ui/${t}/management/pages/landing`:`https://${r}`;try{let u=process.platform;u==="darwin"?In(`open "${c}"`):u==="win32"?In(`cmd /c start "${c}"`):In(`xdg-open "${c}"`),_("Opening HubSpot Landing Pages...")}catch{K(`Open this URL in your browser: ${v.info(c)}`)}}let l=[];if(s&&h(o)&&l.push({path:o,label:`Cloned source (${zo(o)})`}),h(n)&&l.push({path:n,label:`Theme directory (${zo(n)})`}),l.length>0&&await X({message:"Clean up local working directories?"}))for(let u of l)try{Dr(u.path,{recursive:!0,force:!0}),_(`Removed ${u.label}`)}catch{U(`Could not remove ${u.label} \u2014 delete manually if needed.`)}await oe(`Thanks for using hub${v.vibes("Vibes")}! ${v.vibes("~")}`)}async function Xo(){we();let e=await jt(),t=await Ft();Y({lastSourcePath:t.sourceDir});let o=await Lt();Y({lastThemePath:o.themePath}),await Vt({aiEngine:e.aiEngine,model:e.model,sourceDir:t.sourceDir,themePath:o.themePath}),await qe(o.themePath),await qo({portalId:e.portalId,sourceDir:t.sourceDir,themePath:o.themePath,wasCloned:t.wasCloned})}async function Qo(){we(),await jt()}async function Zo(){we();let e=N();e.aiEngine||(M("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let t=await Ft(),o=await Lt();await Vt({aiEngine:e.aiEngine,sourceDir:t.sourceDir,themePath:o.themePath})}async function es(){we();let e=N();if(e.lastThemePath)if(await X({message:`Upload from ${e.lastThemePath}?`}))await qe(e.lastThemePath);else{let o=await ge({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await qe(o)}else{let t=await ge({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:o=>o.trim()?void 0:"Path is required"});await qe(t)}}async function ts(){we(),await ne("Environment Diagnostics");let e=0,t=lt();t.found?_t(t.version)?_(`Node.js v${t.version}`):(U(`Node.js v${t.version} \u2014 too old (need 18+)`),K(" Update at https://nodejs.org"),e++):(M("Node.js \u2014 not installed"),K(" Install from https://nodejs.org"),e++);let o=ct();o.found?_(`Git ${o.version}`):(M("Git \u2014 not installed"),K(" Install from https://git-scm.com"),e++);let n=xe();if(!n.found)U("HubSpot CLI \u2014 not installed (only needed for deployment)"),K(" Install: npm install -g @hubspot/cli");else if(!mo(n.version))U(`HubSpot CLI v${n.version} \u2014 too old (need v8+)`),K(" Update: npm install -g @hubspot/cli@latest"),e++;else{_(`HubSpot CLI v${n.version}`);let f=Ce();f.authenticated?_(`HubSpot portal${f.portalName?`: ${f.portalName}`:""} (ID: ${f.portalId})`):(U("HubSpot \u2014 not authenticated"),K(" Run: hs init"))}let s=dt();s.found?_(`Claude Code ${s.version} at ${s.path}`):K(v.muted("Claude Code \u2014 not installed"));let i=mt();i.found?_(`Gemini CLI ${i.version} at ${i.path}`):K(v.muted("Gemini CLI \u2014 not installed"));let r=pt();r.found?_(`OpenAI Codex ${r.version} at ${r.path}`):K(v.muted("OpenAI Codex \u2014 not installed"));let a=N(),l=!!(a.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(a.openaiApiKey||process.env.OPENAI_API_KEY),u=!!(a.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?_("Anthropic API key configured"):K(v.muted("Anthropic API key \u2014 not set")),c?_("OpenAI API key configured"):K(v.muted("OpenAI API key \u2014 not set")),u?_("Google AI API key configured"):K(v.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"};a.aiEngine&&_(`AI engine: ${p[a.aiEngine]||a.aiEngine}`),a.lastThemePath&&K(v.muted(`Last theme: ${a.lastThemePath}`)),!s.found&&!i.found&&!r.found&&!l&&!c&&!u&&(U("No AI engine available"),K(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),K(" Or install: Claude Code \u2014 https://claude.ai/code"),K(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),K(" Codex CLI \u2014 https://github.com/openai/codex"),e++),console.log(),e===0?await oe("Everything looks good!"):await oe(v.warn(`${e} issue${e>1?"s":""} found \u2014 see above`))}import{join as un}from"path";import{existsSync as il}from"fs";import{execSync as Qn}from"child_process";import mn from"chalk";import{createServer as Xa}from"http";import{readFileSync as qn,existsSync as Xn}from"fs";import{join as dn,extname as Hi}from"path";import{createHash as Qa}from"crypto";import{WebSocketServer as Za}from"ws";import{readFileSync as de,readdirSync as Qe,existsSync as D,writeFileSync as Z,mkdirSync as Pe,rmSync as kn,renameSync as En}from"fs";import{join as w,dirname as Ur}from"path";import{homedir as Wr}from"os";import{existsSync as Re,writeFileSync as Hr,mkdirSync as Lr}from"fs";import{join as $e}from"path";var Zt=null;function ye(){return Zt!==null||(Zt=x("git --version").success),Zt}function $n(e){if(!ye())return!1;if(Re($e(e,".git")))return ns(e),!0;let t=x("git init",{cwd:e});return t.success?(Gr(e),ns(e),x("git add -A",{cwd:e}),x('git commit -m "Initial theme"',{cwd:e}),!0):(console.warn(`[project-git] git init failed in ${e}: ${t.stderr}`),!1)}function ns(e){let t=$e(e,".vibespot");Re(t)||Lr(t,{recursive:!0})}function Gr(e){let t=$e(e,".gitignore");Hr(t,[".vibespot/","node_modules/",""].join(`
306
+ `),"utf-8")}function Tn(e,t){if(!ye()||!Re($e(e,".git"))||(x("git add -A",{cwd:e}),x("git diff --cached --quiet",{cwd:e}).success))return null;let n=t.length>72?t.slice(0,69)+"...":t,s=x(`git commit -m "${n.replace(/"/g,'\\"')}"`,{cwd:e});if(!s.success)return console.warn(`[project-git] commit failed: ${s.stderr}`),null;let i=x("git rev-parse --short HEAD",{cwd:e});return i.success?i.stdout:null}function os(e,t,o,n){if(!ye()||!Re($e(e,".git")))return null;for(let p of n){let f=$e(e,p);Re(f)&&x(`git add "${p}"`,{cwd:e})}if(x("git diff --cached --quiet",{cwd:e}).success)return null;let i=`[${t}] `,r=72-i.length,a=o.length>r?o.slice(0,r-3)+"...":o,l=i+a,c=x(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:e});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let u=x("git rev-parse --short HEAD",{cwd:e});return u.success?u.stdout:null}function ss(e,t=50){if(!ye())return[];if(!Re($e(e,".git")))return[];let o=x(`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(`
307
+ `)){let i=s.split("|");if(i.length<4)continue;let r=parseInt(i[3],10)*1e3;n.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:r,date:new Date(r).toISOString()})}return n}function is(e,t,o=50){if(!ye())return[];if(!Re($e(e,".git")))return[];let n=t.replace(/[[\]\\]/g,"\\$&"),s=x(`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 r of s.stdout.split(`
308
+ `)){let a=r.split("|");if(a.length<4)continue;let l=parseInt(a[3],10)*1e3;i.push({hash:a[0],fullHash:a[1],message:a[2],timestamp:l,date:new Date(l).toISOString()})}return i}function rs(e,t){if(!ye())return{success:!1,error:"Git not available"};if(!Re($e(e,".git")))return{success:!1,error:"Not a git repo"};let o=x(`git cat-file -t ${t}`,{cwd:e});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${t} not found`};let n=x(`git log --format="%s" -1 ${t}`,{cwd:e}),s=n.success?n.stdout:t,i=x(`git checkout ${t} -- .`,{cwd:e});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let r=`Rollback to: ${s}`.slice(0,72);return x(`git commit -m "${r.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}function as(e,t,o,n){if(!ye())return{success:!1,error:"Git not available"};if(!Re($e(e,".git")))return{success:!1,error:"Not a git repo"};let s=x(`git cat-file -t ${o}`,{cwd:e});if(!s.success||s.stdout.trim()!=="commit")return{success:!1,error:`Commit ${o} not found`};let i=x(`git log --format="%s" -1 ${o}`,{cwd:e}),r=i.success?i.stdout:o,a=0;for(let u of n)x(`git checkout ${o} -- "${u}"`,{cwd:e}).success&&a++;if(a===0)return{success:!1,error:"No files could be restored from that commit"};x("git add -A",{cwd:e});let c=`${`[${t}] `}Rollback to: ${r}`.slice(0,72);return x(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}var V=w(Wr(),".vibespot","sessions"),Nn=w(V,"_index.json"),Xe=null;function en(){if(Xe)return Xe;try{return D(Nn)?(Xe=JSON.parse(de(Nn,"utf-8")),Xe):_n()}catch{return _n()}}function tn(e){Xe=e;try{Pe(V,{recursive:!0}),Z(Nn,JSON.stringify(e),"utf-8")}catch{}}function _n(){if(!D(V))return[];let e=[];for(let t of Qe(V).filter(o=>o.endsWith(".json")&&o!=="_index.json"))try{let o=JSON.parse(de(w(V,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 Xe=e,tn(e),e}function Kr(e){let t=en(),o=e.templates||[],n={id:e.id,themeName:e.themeName,updatedAt:e.updatedAt,moduleCount:o.reduce((i,r)=>i+(r.modules?.length||0),0),templateCount:o.length},s=t.findIndex(i=>i.id===e.id);s>=0?t[s]=n:t.push(n),tn(t)}function Br(e){let t=en().filter(o=>o.id!==e);tn(t)}function Yr(e){let t=en().filter(o=>o.themeName!==e);tn(t)}var m=null;function bt(e,t){let o={id:na(),themePath:e,themeName:t,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return m=o,$n(e),o}function cs(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 De(){return!m||!m.activeTemplateId||!m.templates?.length?null:m.templates.find(e=>e.id===m.activeTemplateId)||null}function Rn(e){if(!m)return!1;let t=m.templates.find(o=>o.id===e);return t?(m.activeTemplateId=e,Pn(t),m.updatedAt=Date.now(),!0):!1}function ds(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,Pn(i),m.updatedAt=Date.now(),i}function us(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 ms(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?Rn(m.templates[0].id):(m.activeTemplateId="",m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",m.messages=[])),m.updatedAt=Date.now(),!0)}function Ze(){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 Pn(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 He(){if(!m)return;let e=De();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 Le(e,t){m&&(m.messages.push({role:e,content:t,timestamp:Date.now()}),m.updatedAt=Date.now(),He(),Vr())}function ps(e){m&&(m.assets||(m.assets=[]),m.assets.push(e),m.updatedAt=Date.now(),F())}function nn(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(),He()}}function fs(e){m&&(m.moduleOrder=e,m.updatedAt=Date.now(),He())}function gs(e){m&&(m.modules=m.modules.filter(t=>t.moduleName!==e),m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),He())}function hs(e){m&&(m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),He())}function ys(e,t,o){if(!m)return;let n=m.modules.find(s=>s.moduleName===e);if(n)try{let s=JSON.parse(n.fieldsJson);xs(s,t,o),n.fieldsJson=JSON.stringify(s,null,2),m.updatedAt=Date.now(),He()}catch{}}function me(){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 St(e){if(!m)return;let t=zr(e);t.length>0&&m.messages.length===0&&(m.messages=t),$n(e);let o=w(e,"modules");if(!D(o))return;let n=Qe(o,{withFileTypes:!0});for(let l of n){if(!l.isDirectory()||!l.name.endsWith(".module"))continue;let c=w(o,l.name),u=l.name.replace(/\.module$/,""),p={moduleName:u,fieldsJson:ie(w(c,"fields.json")),metaJson:ie(w(c,"meta.json")),moduleHtml:ie(w(c,"module.html")),moduleCss:ie(w(c,"module.css")),moduleJs:ie(w(c,"module.js"))||void 0};p.fieldsJson&&p.moduleHtml&&(m.modules.push(p),m.moduleOrder.push(u))}let s=w(e,"css"),i=w(e,"js");if(D(s)){let l=Qe(s).filter(c=>c.endsWith("-theme.css")||c.endsWith("-theme.css"));l.length>0&&(m.sharedCss=ie(w(s,l[0])))}if(D(i)){let l=Qe(i).filter(c=>c.endsWith("-animations.js"));l.length>0&&(m.sharedJs=ie(w(i,l[0])))}let r=w(e,".vibespot","styleguide.md"),a=w(e,".vibespot","brandvoice.md");(D(r)||D(a))&&(m.brandAssets||(m.brandAssets={}),D(r)&&(m.brandAssets.styleguide=ie(r)),D(a)&&(m.brandAssets.brandvoice=ie(a))),m.templates||(m.templates=[]),m.activeTemplateId||(m.activeTemplateId=""),cs(m)}function F(){if(!m)return;Pe(V,{recursive:!0});let e=w(V,`${m.id}.json`);Z(e,JSON.stringify(m,null,2),"utf-8"),Kr(m)}function on(e){let t=w(V,e+".json");if(!D(t))return null;try{let o=JSON.parse(de(t,"utf-8"));return o.templates||(o.templates=[]),o.activeTemplateId||(o.activeTemplateId=""),cs(o),m=o,o}catch{return null}}function et(){return D(V)?en():[]}function bs(e,t=!1){let o=w(V,e+".json"),n="";if(t)try{let s=JSON.parse(de(o,"utf-8"));n=s.themeName||"",s.themePath&&D(s.themePath)&&kn(s.themePath,{recursive:!0,force:!0})}catch{}else try{n=JSON.parse(de(o,"utf-8")).themeName||""}catch{}try{D(o)&&kn(o)}catch{}if(n&&D(V)){for(let s of Qe(V).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(de(w(V,s),"utf-8")).themeName===n&&kn(w(V,s))}catch{}Yr(n)}else Br(e);m?.id===e&&(m=null)}function Ss(e,t){let o=w(V,e+".json");if(!D(o))return{ok:!1,error:"Session not found"};let n;try{n=JSON.parse(de(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,r=w(Ur(i),t);if(D(i)){if(D(r))return{ok:!1,error:"A project with that name already exists"};try{En(i,r)}catch(f){return{ok:!1,error:`Failed to rename folder: ${f instanceof Error?f.message:String(f)}`}}let a=w(r,"css",`${s}-theme.css`),l=w(r,"css",`${t}-theme.css`);if(D(a))try{En(a,l)}catch{}let c=w(r,"js",`${s}-animations.js`),u=w(r,"js",`${t}-animations.js`);if(D(c))try{En(c,u)}catch{}let p=w(r,"theme.json");if(D(p))try{let f=JSON.parse(de(p,"utf-8"));f.label=t,f.name=t,Z(p,JSON.stringify(f,null,2),"utf-8")}catch{}}if(D(V))for(let a of Qe(V).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(de(w(V,a),"utf-8"));l.themeName===s&&(l.themeName=t,l.themePath=r,l.updatedAt=Date.now(),Z(w(V,a),JSON.stringify(l,null,2),"utf-8"))}catch{}return m&&m.themeName===s&&(m.themeName=t,m.themePath=r,m.updatedAt=Date.now()),_n(),{ok:!0}}function tt(){if(!m)return;let e=m.themePath,t=new Map;if(m.templates.length>0)for(let n of m.templates)for(let s of n.modules)t.set(s.moduleName,s);for(let n of m.modules)t.set(n.moduleName,n);let o=w(e,"modules");Pe(o,{recursive:!0});for(let n of t.values())Pe(w(o,`${n.moduleName}.module`),{recursive:!0});for(let n of t.values()){let s=w(o,`${n.moduleName}.module`);Z(w(s,"fields.json"),n.fieldsJson,"utf-8"),Z(w(s,"meta.json"),n.metaJson,"utf-8"),Z(w(s,"module.html"),n.moduleHtml,"utf-8"),Z(w(s,"module.css"),n.moduleCss,"utf-8"),n.moduleJs&&Z(w(s,"module.js"),n.moduleJs,"utf-8")}if(m.sharedCss){let n=w(e,"css");Pe(n,{recursive:!0}),Z(w(n,`${m.themeName}-theme.css`),m.sharedCss,"utf-8")}if(m.sharedJs){let n=w(e,"js");Pe(n,{recursive:!0}),Z(w(n,`${m.themeName}-animations.js`),m.sharedJs,"utf-8")}if(m.templates.length>0){let n=w(e,"templates");Pe(n,{recursive:!0});for(let s of m.templates){if(s.pageType==="module_only"||s.modules.length===0)continue;let i=s.template||Qr(s),r=ls(i,s.label,s.pageType);Z(w(n,`${s.id}.html`),r,"utf-8"),s.pageType==="blog_post"&&Zr(n,s)}}else if(m.modules.length>0){let n=m.template||ta(),s=w(e,"templates");Pe(s,{recursive:!0});let i=ls(n,`${m.themeName} Landing Page`);Z(w(s,`lp-${m.themeName}.html`),i,"utf-8")}qr(),Xr()}function Vr(){if(m)try{let e=w(m.themePath,".vibespot");Pe(e,{recursive:!0});let t={sessionId:m.id,themeName:m.themeName,messages:m.messages,updatedAt:Date.now()};Z(w(e,"chat.json"),JSON.stringify(t,null,2),"utf-8")}catch{}}function zr(e){let t=w(e,".vibespot","chat.json");if(!D(t))return[];try{let o=JSON.parse(de(t,"utf-8"));return Array.isArray(o.messages)?o.messages:[]}catch{return[]}}function vs(){m&&(m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",St(m.themePath),m.updatedAt=Date.now(),He())}function ws(){if(!m)return;let e=De();if(!e)return;let t=m.themePath,o=w(t,"modules");e.modules=[];for(let n of e.moduleOrder){let s=w(o,`${n}.module`);if(!D(s))continue;let i={moduleName:n,fieldsJson:ie(w(s,"fields.json")),metaJson:ie(w(s,"meta.json")),moduleHtml:ie(w(s,"module.html")),moduleCss:ie(w(s,"module.css")),moduleJs:ie(w(s,"module.js"))||void 0};i.fieldsJson&&i.moduleHtml&&e.modules.push(i)}if(e.templateFile){let n=w(t,e.templateFile);D(n)&&(e.template=ie(n))}Pn(e),m.updatedAt=Date.now()}function qr(){if(!m)return;let e=w(m.themePath,"templates","layouts","base.html");if(D(e))try{let t=de(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+`
279
309
  {% if template_js %}
280
310
  {{ require_js(get_asset_url(template_js)) }}
281
311
  {% endif %}`):t=t.replace("{{ standard_footer_includes }}",`{% if template_js %}
282
312
  {{ require_js(get_asset_url(template_js)) }}
283
313
  {% endif %}
284
- {{ standard_footer_includes }}`),V(e,t,"utf-8")}catch{}}function Gi(){if(!m)return;let e=w(m.themePath,"theme.json");if(R(e))try{let t=JSON.parse(ae(e,"utf-8"));t.label=m.themeName,t.name=m.themeName,V(e,JSON.stringify(t,null,2),"utf-8")}catch{}}function $o(e,t,o="landing_page"){return e.includes("templateType")?e:`<!--
314
+ {{ standard_footer_includes }}`),Z(e,t,"utf-8")}catch{}}function Xr(){if(!m)return;let e=w(m.themePath,"theme.json");if(D(e))try{let t=JSON.parse(de(e,"utf-8"));t.label=m.themeName,t.name=m.themeName,Z(e,JSON.stringify(t,null,2),"utf-8")}catch{}}function ls(e,t,o="landing_page"){return e.includes("templateType")?e:`<!--
285
315
  templateType: ${o==="blog_post"?"blog_post":"page"}
286
316
  isAvailableForNewContent: true
287
317
  label: "${t}"
288
318
  -->
289
- `+e}function Wi(e){if(e.modules.length===0)return"";let t=m.themeName,n=Ki(e).map(i=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
319
+ `+e}function Qr(e){if(e.modules.length===0)return"";let t=m.themeName,n=ea(e).map(i=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
290
320
  {% dnd_module path="../modules/${i.moduleName}.module" %}
291
321
  {% end_dnd_module %}
292
322
  {% end_dnd_section %}`).join(`
@@ -317,7 +347,7 @@ ${n}
317
347
 
318
348
  {% block footer %}
319
349
  {% endblock footer %}
320
- `}function Ui(e,t){let o=`<!--
350
+ `}function Zr(e,t){let o=`<!--
321
351
  templateType: blog_listing
322
352
  isAvailableForNewContent: true
323
353
  label: "${t.label} - Listing"
@@ -342,7 +372,7 @@ ${n}
342
372
  {% endif %}
343
373
  </div>
344
374
  {% endblock body %}
345
- `;V(w(e,`${t.id}-listing.html`),o,"utf-8")}function Ki(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 Bi(){if(!m||m.modules.length===0)return"";let e=m.themeName,o=ce().map(n=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
375
+ `;Z(w(e,`${t.id}-listing.html`),o,"utf-8")}function ea(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 ta(){if(!m||m.modules.length===0)return"";let e=m.themeName,o=me().map(n=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
346
376
  {% dnd_module path="../modules/${n.moduleName}.module" %}
347
377
  {% end_dnd_module %}
348
378
  {% end_dnd_section %}`).join(`
@@ -373,7 +403,7 @@ ${o}
373
403
 
374
404
  {% block footer %}
375
405
  {% endblock footer %}
376
- `}function Yi(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function Z(e){try{return ae(e,"utf-8")}catch{return""}}function Lo(e,t,o){let n=t.split("."),s=n[0],i=e.find(r=>r.name===s);i&&(n.length===1?i.default=o:i.children&&Lo(i.children,n.slice(1).join("."),o))}function Lt(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]=Lt(o.children):t[o.name]=o.default??"";return t}function un(e,t){let o=e;return o=or(o),o=Go(o,t),o=Wo(o,t),o=Uo(o,t),o=ir(o),o}function mn(e){let t=[e.sharedCss||"",...e.moduleCssArray].filter(Boolean).map(s=>`<style>${s}</style>`).join(`
406
+ `}function na(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function ie(e){try{return de(e,"utf-8")}catch{return""}}function xs(e,t,o){let n=t.split("."),s=n[0],i=e.find(r=>r.name===s);i&&(n.length===1?i.default=o:i.children&&xs(i.children,n.slice(1).join("."),o))}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 Mn(e,t){let o=e;return o=ua(o),o=$s(o,t),o=Ts(o,t),o=ks(o,t),o=pa(o),o}function jn(e){let t=[e.sharedCss||"",...e.moduleCssArray].filter(Boolean).map(s=>`<style>${s}</style>`).join(`
377
407
  `),o=[e.sharedJs||"",...e.moduleJsArray].filter(Boolean).map(s=>`<script>${s}</script>`).join(`
378
408
  `),n=e.renderedModules.join(`
379
409
  `);return`<!DOCTYPE html>
@@ -420,7 +450,7 @@ document.querySelectorAll('img').forEach(function(img){
420
450
  });
421
451
  </script>
422
452
  </body>
423
- </html>`}var Vi=/\{%[-\s]*require_(css|js)\b.*?%\}/gs,zi=/\{%[-\s]*end_require_(css|js)\s*%\}/gs,qi=/\{\{[-\s]*require_(css|js)\(.*?\)\s*\}\}/gs,Qi=/\{\{[-\s]*get_asset_url\(.*?\)\s*\}\}/gs,Xi=/\{%[-\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\b.*?%\}/gs,Zi=/\{%[-\s]*module\b.*?%\}/gs,er=/\{%[-\s]*(extends|block|endblock|set)\b.*?%\}/gs,tr=/\{#.*?#\}/gs,nr=/\{\{[-\s]*content\.\w+.*?\}\}/gs,dn=/\{%[-\s]*if\s+(.*?)\s*-?%\}([\s\S]*?)\{%[-\s]*endif\s*-?%\}/g;function or(e){return e=e.replace(Vi,""),e=e.replace(zi,""),e=e.replace(qi,""),e=e.replace(Qi,""),e=e.replace(Xi,""),e=e.replace(Zi,""),e=e.replace(er,""),e=e.replace(tr,""),e=e.replace(nr,""),e}function Go(e,t){let o=e,n=0;for(;n<30;){n++;let s=sr(o);if(!s)break;let{varName:i,iterExpr:r,body:a,start:l,end:c}=s,u=rr(r,t),p="";Array.isArray(u)&&(p=u.map((f,y)=>{let h={...t,[i]:f,loop:{index:y+1,index0:y,first:y===0,last:y===u.length-1,length:u.length}},v=Go(a,h);return v=Wo(v,h),v=Uo(v,h),v}).join("")),o=o.slice(0,l)+p+o.slice(c)}return o}function sr(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],r=n.index+n[0].length;o.lastIndex=r;let a=1,l;for(;(l=o.exec(e))!==null;)if(l[1].startsWith("for"))a++;else if(a--,a===0){let c=e.slice(r,l.index);return{varName:s,iterExpr:i,body:c,start:n.index,end:l.index+l[0].length}}return null}function Wo(e,t){let o=e,n=0;for(;dn.test(o)&&n<50;)n++,o=o.replace(dn,(s,i,r)=>{let a=r.split(/\{%[-\s]*else\s*-?%\}/),l=a[0],c=a[1]||"",u=l.split(/\{%[-\s]*elif\s+(.*?)\s*-?%\}/);if(u.length>1){if(Qe(i,t))return u[0];for(let p=1;p<u.length;p+=2){let f=u[p],y=u[p+1]||"";if(Qe(f,t))return y}return c}return Qe(i,t)?l:c}),dn.lastIndex=0;return o}function Uo(e,t){return e.replace(/\{\{[-\s]*(.*?)[-\s]*\}\}/g,(o,n)=>{let i=n.trim().split("|"),r=i[0].trim(),a=Le(t,r);for(let l=1;l<i.length;l++)a=Bo(a,i[l].trim());return a==null?"":typeof a=="object"?JSON.stringify(a):String(a)})}function ir(e){return e=e.replace(/\{%.*?%\}/gs,""),e=e.replace(/\{\{.*?\}\}/gs,""),e}function rr(e,t){let o=e.match(/^range\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);if(o){let s=Ho(o[1],t),i=Ho(o[2],t),r=[];for(let a=s;a<i;a++)r.push(a);return r}let n=e.match(/^(.+?)\|split\(['"](.+?)['"]\)$/);if(n){let s=Le(t,n[1].trim());return typeof s=="string"?s.split(n[2]):[]}return Le(t,e)}function Ho(e,t){let n=e.trim().split("|"),s=n[0].trim();if(!isNaN(Number(s)))return Number(s);let i=Le(t,s);for(let r=1;r<n.length;r++)i=Bo(i,n[r].trim());return Number(i)||0}function Le(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 Qe(e,t){let o=e.trim();if(o.startsWith("not "))return!Qe(o.slice(4),t);if(o.includes(" and "))return o.split(" and ").every(i=>Qe(i,t));if(o.includes(" or "))return o.split(" or ").some(i=>Qe(i,t));let n=o.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);if(n){let i=Le(t,n[1].trim()),r=n[2],a=n[3].trim();switch(typeof a=="string"&&a.startsWith('"')&&a.endsWith('"')||typeof a=="string"&&a.startsWith("'")&&a.endsWith("'")?a=a.slice(1,-1):isNaN(Number(a))?a=Le(t,a):a=Number(a),r){case"==":return i==a;case"!=":return i!=a;case">":return Number(i)>Number(a);case"<":return Number(i)<Number(a);case">=":return Number(i)>=Number(a);case"<=":return Number(i)<=Number(a)}}let s=Le(t,o);return Ko(s)}function Ko(e){return!(e==null||e===""||e===0||e===!1||Array.isArray(e)&&e.length===0)}function Bo(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 r=parseInt(i,10);return o.length>r?o.slice(0,r)+"...":o}return o;case"default":return Ko(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 Vo(){let e=I();if(!e)return Yo();let t=ce();if(t.length===0)return Yo();let o=[],n=[],s=[];for(let i of t){if(i.moduleHtml.includes("dnd_area")||i.moduleHtml.includes("extends "))continue;let r;try{let c=JSON.parse(i.fieldsJson);r={module:Lt(c)}}catch{r={module:{}}}let a=un(i.moduleHtml,r),l=i.moduleName.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");o.push(`<div class="vibespot-module" id="${l}" data-module="${i.moduleName}">${a}</div>`),i.moduleCss&&n.push(i.moduleCss),i.moduleJs&&s.push(i.moduleJs)}return mn({renderedModules:o,sharedCss:e.sharedCss,moduleCssArray:n,sharedJs:e.sharedJs,moduleJsArray:s})}function Yo(){return`<!DOCTYPE html>
453
+ </html>`}var oa=/\{%[-\s]*require_(css|js)\b.*?%\}/gs,sa=/\{%[-\s]*end_require_(css|js)\s*%\}/gs,ia=/\{\{[-\s]*require_(css|js)\(.*?\)\s*\}\}/gs,Cs=/\{\{[-\s]*get_asset_url\(["'](?:[^"'\/]+\/)?assets\/(.*?)["']\)\s*\}\}/gs,As=/\{\{[-\s]*get_asset_url\(.*?\)\s*\}\}/gs,ra=/\{%[-\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\b.*?%\}/gs,aa=/\{%[-\s]*module\b.*?%\}/gs,la=/\{%[-\s]*(extends|block|endblock|set)\b.*?%\}/gs,ca=/\{#.*?#\}/gs,da=/\{\{[-\s]*content\.\w+.*?\}\}/gs,On=/\{%[-\s]*if\s+(.*?)\s*-?%\}([\s\S]*?)\{%[-\s]*endif\s*-?%\}/g;function ua(e){return e=e.replace(oa,""),e=e.replace(sa,""),e=e.replace(ia,""),Cs.lastIndex=0,e=e.replace(Cs,(t,o)=>`/theme-assets/${o}`),As.lastIndex=0,e=e.replace(As,""),e=e.replace(ra,""),e=e.replace(aa,""),e=e.replace(la,""),e=e.replace(ca,""),e=e.replace(da,""),e}function $s(e,t){let o=e,n=0;for(;n<30;){n++;let s=ma(o);if(!s)break;let{varName:i,iterExpr:r,body:a,start:l,end:c}=s,u=fa(r,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=$s(a,y);return S=Ts(S,y),S=ks(S,y),S}).join("")),o=o.slice(0,l)+p+o.slice(c)}return o}function ma(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],r=n.index+n[0].length;o.lastIndex=r;let a=1,l;for(;(l=o.exec(e))!==null;)if(l[1].startsWith("for"))a++;else if(a--,a===0){let c=e.slice(r,l.index);return{varName:s,iterExpr:i,body:c,start:n.index,end:l.index+l[0].length}}return null}function Ts(e,t){let o=e,n=0;for(;On.test(o)&&n<50;)n++,o=o.replace(On,(s,i,r)=>{let a=r.split(/\{%[-\s]*else\s*-?%\}/),l=a[0],c=a[1]||"",u=l.split(/\{%[-\s]*elif\s+(.*?)\s*-?%\}/);if(u.length>1){if(nt(i,t))return u[0];for(let p=1;p<u.length;p+=2){let f=u[p],g=u[p+1]||"";if(nt(f,t))return g}return c}return nt(i,t)?l:c}),On.lastIndex=0;return o}function ks(e,t){return e.replace(/\{\{[-\s]*(.*?)[-\s]*\}\}/g,(o,n)=>{let i=n.trim().split("|"),r=i[0].trim(),a=Ge(t,r);for(let l=1;l<i.length;l++)a=Ns(a,i[l].trim());return a==null?"":typeof a=="object"?JSON.stringify(a):String(a)})}function pa(e){return e=e.replace(/\{%.*?%\}/gs,""),e=e.replace(/\{\{.*?\}\}/gs,""),e}function fa(e,t){let o=e.match(/^range\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);if(o){let s=Is(o[1],t),i=Is(o[2],t),r=[];for(let a=s;a<i;a++)r.push(a);return r}let n=e.match(/^(.+?)\|split\(['"](.+?)['"]\)$/);if(n){let s=Ge(t,n[1].trim());return typeof s=="string"?s.split(n[2]):[]}return Ge(t,e)}function Is(e,t){let n=e.trim().split("|"),s=n[0].trim();if(!isNaN(Number(s)))return Number(s);let i=Ge(t,s);for(let r=1;r<n.length;r++)i=Ns(i,n[r].trim());return Number(i)||0}function Ge(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 nt(e,t){let o=e.trim();if(o.startsWith("not "))return!nt(o.slice(4),t);if(o.includes(" and "))return o.split(" and ").every(i=>nt(i,t));if(o.includes(" or "))return o.split(" or ").some(i=>nt(i,t));let n=o.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);if(n){let i=Ge(t,n[1].trim()),r=n[2],a=n[3].trim();switch(typeof a=="string"&&a.startsWith('"')&&a.endsWith('"')||typeof a=="string"&&a.startsWith("'")&&a.endsWith("'")?a=a.slice(1,-1):isNaN(Number(a))?a=Ge(t,a):a=Number(a),r){case"==":return i==a;case"!=":return i!=a;case">":return Number(i)>Number(a);case"<":return Number(i)<Number(a);case">=":return Number(i)>=Number(a);case"<=":return Number(i)<=Number(a)}}let s=Ge(t,o);return Es(s)}function Es(e){return!(e==null||e===""||e===0||e===!1||Array.isArray(e)&&e.length===0)}function Ns(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 r=parseInt(i,10);return o.length>r?o.slice(0,r)+"...":o}return o;case"default":return Es(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 Rs(){let e=$();if(!e)return _s();let t=me();if(t.length===0)return _s();let o=[],n=[],s=[];for(let i of t){if(i.moduleHtml.includes("dnd_area")||i.moduleHtml.includes("extends "))continue;let r;try{let c=JSON.parse(i.fieldsJson);r={module:sn(c)}}catch{r={module:{}}}let a=Mn(i.moduleHtml,r),l=i.moduleName.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");o.push(`<div class="vibespot-module" id="${l}" data-module="${i.moduleName}">${a}</div>`),i.moduleCss&&n.push(i.moduleCss),i.moduleJs&&s.push(i.moduleJs)}return jn({renderedModules:o,sharedCss:e.sharedCss,moduleCssArray:n,sharedJs:e.sharedJs,moduleJsArray:s})}function _s(){return`<!DOCTYPE html>
424
454
  <html lang="en">
425
455
  <head>
426
456
  <meta charset="utf-8">
@@ -471,7 +501,7 @@ document.querySelectorAll('img').forEach(function(img){
471
501
  <div class="welcome__sub">Build Something Great</div>
472
502
  </div>
473
503
  </body>
474
- </html>`}function zo(e){let t=I();if(!t)return"";let o;for(let i of t.templates)if(o=i.modules.find(r=>r.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:Lt(i)}}catch{n={module:{}}}let s=un(o.moduleHtml,n);return mn({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]:[]})}import{execSync as vn}from"child_process";var ee={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 fn(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 r=parseInt(i[1],10);if(r<=o)return null;o=r;let a=Math.max(0,r-5),c=t.slice(a,r+1).lastIndexOf('"');if(c===-1)return null;let u=a+c;if(u>0&&t[u-1]==="\\")return null;t=t.slice(0,u)+'\\"'+t.slice(u+1)}return null}function ar(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,r=!1;for(let u=o+1;u<e.length;u++){let p=e[u];if(r){r=!1;continue}if(p==="\\"){r=!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 fn(c)}function pn(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 qo(e,t){let o=!1,n,s=/```vibespot-modules\s*\n?([\s\S]*?)```/g;for(;(n=s.exec(e))!==null;)try{ee.info("parse","Found vibespot-modules block",{length:n[1].length});let i=fn(n[1]);if(!i||typeof i!="object")throw ee.warn("parse","tryParseJSON returned non-object",{result:typeof i}),new Error("Invalid JSON after repair");let r=i;r.modules&&Array.isArray(r.modules)&&(Mt({modules:r.modules.map(a=>pn(a)),sharedCss:r.sharedCss!==void 0?String(r.sharedCss):void 0,sharedJs:r.sharedJs!==void 0?String(r.sharedJs):void 0}),o=!0)}catch(i){ee.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 r=fn(n[1]);if(!r||typeof r!="object")throw new Error("Invalid JSON after repair");let a=r;a.modules&&Array.isArray(a.modules)&&(Mt({modules:a.modules.map(l=>pn(l)),sharedCss:a.sharedCss!==void 0?String(a.sharedCss):void 0,sharedJs:a.sharedJs!==void 0?String(a.sharedJs):void 0}),o=!0)}catch(r){ee.warn("parse","Failed to parse JSON module block",{error:r instanceof Error?r.message:String(r)})}}if(!o&&(e.match(/```/g)||[]).length%2!==0&&e.includes('"modules"')){ee.info("parse","Detected truncated response (odd fence count), attempting salvage");let r=e.lastIndexOf("```"),a=e.slice(r+3);a=a.replace(/^[\w-]*\s*\n?/,"");let l=ar(a);if(l){let c=l;c.modules&&Array.isArray(c.modules)&&c.modules.length>0&&(ee.info("parse","Salvaged modules from truncated response",{count:c.modules.length}),Mt({modules:c.modules.map(u=>pn(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){ee.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"'),r=/\bmodule|modul/i.test(e)&&(/\bcreated?\b|\berstellt\b|\bgenerat/i.test(e)||/\|.*\|.*\|/m.test(e));if(i||r){let a=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.";ee.warn("parse",a),t&&t(a)}}}import{spawn as lr}from"child_process";function Xe(){let e=I();return e?{pageType:Je()?.pageType,brandAssets:e.brandAssets}:{}}function Ze(e,t,o=!1,n,s){let i=`You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.
504
+ </html>`}function Ps(e){let t=$();if(!t)return"";let o;for(let i of t.templates)if(o=i.modules.find(r=>r.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=Mn(o.moduleHtml,n);return jn({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]:[]})}import{execSync as Kn}from"child_process";var z={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 Jn(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 r=parseInt(i[1],10);if(r<=o)return null;o=r;let a=Math.max(0,r-5),c=t.slice(a,r+1).lastIndexOf('"');if(c===-1)return null;let u=a+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,r=!1;for(let u=o+1;u<e.length;u++){let p=e[u];if(r){r=!1;continue}if(p==="\\"){r=!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 Jn(c)}function Fn(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 Os(e,t){let o=!1,n,s=/```vibespot-modules\s*\n?([\s\S]*?)```/g;for(;(n=s.exec(e))!==null;)try{z.info("parse","Found vibespot-modules block",{length:n[1].length});let i=Jn(n[1]);if(!i||typeof i!="object")throw z.warn("parse","tryParseJSON returned non-object",{result:typeof i}),new Error("Invalid JSON after repair");let r=i;r.modules&&Array.isArray(r.modules)&&(nn({modules:r.modules.map(a=>Fn(a)),sharedCss:r.sharedCss!==void 0?String(r.sharedCss):void 0,sharedJs:r.sharedJs!==void 0?String(r.sharedJs):void 0}),o=!0)}catch(i){z.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 r=Jn(n[1]);if(!r||typeof r!="object")throw new Error("Invalid JSON after repair");let a=r;a.modules&&Array.isArray(a.modules)&&(nn({modules:a.modules.map(l=>Fn(l)),sharedCss:a.sharedCss!==void 0?String(a.sharedCss):void 0,sharedJs:a.sharedJs!==void 0?String(a.sharedJs):void 0}),o=!0)}catch(r){z.warn("parse","Failed to parse JSON module block",{error:r instanceof Error?r.message:String(r)})}}if(!o&&(e.match(/```/g)||[]).length%2!==0&&e.includes('"modules"')){z.info("parse","Detected truncated response (odd fence count), attempting salvage");let r=e.lastIndexOf("```"),a=e.slice(r+3);a=a.replace(/^[\w-]*\s*\n?/,"");let l=ga(a);if(l){let c=l;c.modules&&Array.isArray(c.modules)&&c.modules.length>0&&(z.info("parse","Salvaged modules from truncated response",{count:c.modules.length}),nn({modules:c.modules.map(u=>Fn(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){z.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"'),r=/\bmodule|modul/i.test(e)&&(/\bcreated?\b|\berstellt\b|\bgenerat/i.test(e)||/\|.*\|.*\|/m.test(e));if(i||r){let a=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.";z.warn("parse",a),t&&t(a)}}}import{spawn as ha}from"child_process";function ot(){let e=$();return e?{pageType:De()?.pageType,brandAssets:e.brandAssets}:{}}function st(e,t,o=!1,n,s){let i=`You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.
475
505
 
476
506
  ## Your Role
477
507
  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.
@@ -521,12 +551,17 @@ NEVER respond with only a text summary. The vibespot-modules JSON block is manda
521
551
  - Image fields: type "image", default { "src": "https://placehold.co/800x600/1a1a2e/ffffff?text=Replace+in+HubSpot", "alt": "Placeholder image", "width": 800, "height": 600 }
522
552
 
523
553
  ## Images & Media
524
- - All images are managed through HubSpot's file manager \u2014 users will replace placeholders after publishing
554
+ - Users can upload images that get placed in the theme's assets/ folder automatically
555
+ - When the user uploads an image and wants it on the page, reference it with: {{ get_asset_url("${t}/assets/filename.ext") }}
556
+ - IMPORTANT: get_asset_url() paths must include the theme name prefix "${t}/" because HubSpot resolves from the Design Manager root
557
+ - For background images with uploaded assets: style="background-image: url('{{ get_asset_url(\\"${t}/assets/filename.ext\\") }}')"
558
+ - For images without an uploaded asset, use image fields (type "image") with placehold.co defaults
525
559
  - ALWAYS use image fields (type "image") so users can swap images in the page editor
526
560
  - Use placehold.co URLs as defaults so the preview looks complete (e.g. https://placehold.co/800x600/1a1a2e/ffffff?text=Hero+Image)
527
561
  - In module.html, render images with: <img src="{{ module.field_name.src }}" alt="{{ module.field_name.alt }}" width="{{ module.field_name.width }}" height="{{ module.field_name.height }}">
528
562
  - For background images in CSS, use inline styles: style="background-image: url('{{ module.field_name.src }}')"
529
563
  - Size placeholders appropriately for their context (hero: 1920x800, cards: 600x400, icons: 200x200, avatars: 150x150)
564
+ - If the user's intent is ambiguous (design reference vs page asset), ask them to clarify
530
565
 
531
566
  ## Navigation & Anchor Links
532
567
  - Each module is automatically wrapped with an id derived from its moduleName (lowercase, hyphens for spaces)
@@ -537,7 +572,7 @@ NEVER respond with only a text summary. The vibespot-modules JSON block is manda
537
572
 
538
573
  ## When modifying existing modules
539
574
  When the user asks to change something, include ONLY the modules that changed. Keep module names consistent.
540
- If the change affects shared CSS or JS, include those too.`,r=n?Bn(n):"",a=r?`
575
+ If the change affects shared CSS or JS, include those too.`,r=n?To(n):"",a=r?`
541
576
 
542
577
  ## Page Type Context
543
578
  ${r}`:"",l="";if(!o&&(s?.styleguide&&(l+=`
@@ -546,13 +581,13 @@ ${r}`:"",l="";if(!o&&(s?.styleguide&&(l+=`
546
581
  ${s.styleguide}`),s?.brandvoice&&(l+=`
547
582
 
548
583
  ## Brand Voice
549
- ${s.brandvoice}`),s?.humanify!==!1)){let c=Kn();c&&(l+=`
584
+ ${s.brandvoice}`),s?.humanify!==!1)){let c=$o();c&&(l+=`
550
585
 
551
586
  ## Anti-AI Copy Rules (Humanify)
552
587
  ${c}`)}return o?i+a+`
553
588
 
554
589
  ## HubSpot CMS Rules
555
- ${Ke()}`:i+a+l+`
590
+ ${ze()}`:i+a+l+`
556
591
 
557
592
  ## Design Quality
558
593
  - Use modern, clean design with proper spacing and typography
@@ -577,16 +612,16 @@ When using scroll-animate classes (opacity: 0 \u2192 visible), you MUST include
577
612
  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.
578
613
 
579
614
  ## Design Guide
580
- ${Wn()}
615
+ ${Ao()}
581
616
 
582
617
  ## Content & Copywriting Guide
583
- ${Un()}
618
+ ${Io()}
584
619
 
585
620
  ## HubSpot CMS Rules
586
- ${Ke()}
621
+ ${ze()}
587
622
 
588
623
  ## Conversion Guide Reference
589
- ${e}`}function at(){let e=I(),t=[];if(e.modules.length>0){t.push(`
624
+ ${e}`}function vt(){let e=$(),t=[];if(e.modules.length>0){t.push(`
590
625
 
591
626
  ## Current Module State
592
627
  `);for(let i of e.modules)t.push(`
@@ -617,36 +652,58 @@ ${e.sharedCss}
617
652
  \`\`\`js
618
653
  ${e.sharedJs}
619
654
  \`\`\`
620
- `)}let o=ze(),n=new Set(e.modules.map(i=>i.moduleName)),s=o.filter(i=>!n.has(i.module.moduleName));if(s.length>0){t.push(`
655
+ `)}let o=Ze(),n=new Set(e.modules.map(i=>i.moduleName)),s=o.filter(i=>!n.has(i.module.moduleName));if(s.length>0){t.push(`
621
656
 
622
657
  ## Available modules in this theme (reusable)
623
658
  `);for(let i of s)t.push(`- ${i.module.moduleName} (used in: ${i.usedIn.join(", ")})
624
659
  `);t.push(`
625
660
  The user can ask to reuse any of these modules by name.
626
- `)}return t.join("")}function gn(e){let o=I().messages.slice(-20).map(i=>({role:i.role,content:i.content})),n=at(),s=n?`${e}
661
+ `)}return t.join("")}function Dn(e,t){let o=$(),n=o.messages.slice(-20).map(c=>({role:c.role,content:c.content})),s=vt(),i="";if(o.assets?.length){let c=o.assets.filter(u=>u.type==="image"&&u.usage==="asset");c.length>0&&(i=`
662
+
663
+ ## Available Theme Assets
664
+ These images are in the theme's assets/ folder. Reference them with get_asset_url("${o.themeName}/assets/filename"):
665
+ ${c.map(u=>`- ${u.filename} (${u.originalName}) \u2192 get_asset_url("${o.themeName}/assets/${u.filename}")`).join(`
666
+ `)}`)}let r=e;s&&(r+=`
667
+
668
+ ---
669
+ ${s}`),i&&(r+=i);let a=t&&t.length>0;if(a)for(let c of t)c.type==="document"&&c.extractedText&&(r+=`
670
+
671
+ ---
672
+ [Attached document: ${c.originalName}]
673
+ ${c.extractedText}`),c.type==="image"&&c.usage==="asset"&&c.assetPath&&(r+=`
674
+
675
+ [Uploaded image: ${c.originalName} \u2192 available as get_asset_url("${c.assetPath}")]`);let l=a?t.filter(c=>c.type==="image"&&c.base64):[];if(l.length>0){let c=[];for(let u of l)c.push({type:"image",source:{type:"base64",media_type:u.mimeType,data:u.base64}});c.push({type:"text",text:r}),n.push({role:"user",content:c})}else n.push({role:"user",content:r});return n}var Hn=null;async function ya(){return Hn||(Hn=(await import("@anthropic-ai/sdk")).default),Hn}function Ms(e){if(!e?.length)return"";let t=[];for(let o of e)o.type==="image"&&o.usage==="asset"&&o.assetPath&&t.push(`
676
+ [Uploaded image: ${o.originalName} \u2192 use get_asset_url("${o.assetPath}")]`),o.type==="document"&&o.extractedText&&t.push(`
627
677
 
628
678
  ---
629
- ${n}`:e;return o.push({role:"user",content:s}),o}var hn=null;async function cr(){return hn||(hn=(await import("@anthropic-ai/sdk")).default),hn}var te=["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..."],yn=[10,20,40,60,120];async function Qo(e,t,o,n,s,i,r){let a=await cr(),l=new a({apiKey:t}),c=se(),p=I().modules.length>0,f=gn(e),y=Xe(),h=Ze(c,o,p,y.pageType,y.brandAssets);for(let v=0;;v++)try{let N="",K=0,F=i||(()=>{});F(te[0]);let H=setInterval(()=>{K++,F(te[Math.min(K,te.length-1)])},6e3);try{let z=l.messages.stream({model:n,max_tokens:48e3,system:h,messages:f});for await(let q of z)if(q.type==="content_block_delta"&&q.delta.type==="text_delta"){let O=q.delta.text;N+=O,s(O)}}finally{clearInterval(H)}r&&r(N);return}catch(N){let K=N.status,F=N.error?.type;if(!(K===429||F==="rate_limit_error"||N instanceof Error&&N.message.includes("429"))||v>=yn.length)throw N;let z=yn[v];ee.warn("ai-engine",`Rate limited (429), attempt ${v+1}/${yn.length} \u2014 waiting ${z}s`),i&&i(`Rate limited by Anthropic API \u2014 retrying in ${z}s...`),await new Promise(q=>setTimeout(q,z*1e3)),i&&i("Retrying...")}}async function Xo(e,t,o,n,s,i,r){let a=se(),l=I().modules.length>0,c=gn(e),u=Xe(),p=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:Ze(a,o,l,u.pageType,u.brandAssets)},...c]})});if(!p.ok){let H=await p.text();throw new Error(`OpenAI API error (${p.status}): ${H}`)}let f=0,y=i||(()=>{});y(te[0]);let h=setInterval(()=>{f++,y(te[Math.min(f,te.length-1)])},6e3),v="",N=p.body.getReader(),K=new TextDecoder,F="";try{for(;;){let{done:H,value:z}=await N.read();if(H)break;F+=K.decode(z,{stream:!0});let q=F.split(`
630
- `);F=q.pop()||"";for(let O of q){if(!O.startsWith("data: "))continue;let L=O.slice(6).trim();if(L==="[DONE]")break;try{let Pe=JSON.parse(L).choices?.[0]?.delta?.content;Pe&&(v+=Pe,s(Pe))}catch{}}}}finally{clearInterval(h)}r&&r(v)}async function Zo(e,t,o,n,s,i){let r=se(),a=I(),l=a.modules.length>0,c=at(),u=Xe(),p=[];for(let L of a.messages.slice(-20))p.push({role:L.role==="assistant"?"model":"user",parts:[{text:L.content}]});let f=c?`${e}
679
+ [Attached document: ${o.originalName}]
680
+ ${o.extractedText}`);return t.join("")}var re=["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..."],Ln=[10,20,40,60,120];async function js(e,t,o,n,s,i,r,a){let l=await ya(),c=new l({apiKey:t}),u=ae(),f=$().modules.length>0,g=Dn(e,a),y=ot(),S=st(u,o,f,y.pageType,y.brandAssets);for(let C=0;;C++)try{let T="",k=0,E=i||(()=>{});E(re[0]);let q=setInterval(()=>{k++,E(re[Math.min(k,re.length-1)])},6e3);try{let H=c.messages.stream({model:n,max_tokens:48e3,system:S,messages:g});for await(let P of H)if(P.type==="content_block_delta"&&P.delta.type==="text_delta"){let L=P.delta.text;T+=L,s(L)}}finally{clearInterval(q)}r&&r(T);return}catch(T){let k=T.status,E=T.error?.type;if(!(k===429||E==="rate_limit_error"||T instanceof Error&&T.message.includes("429"))||C>=Ln.length)throw T;let H=Ln[C];z.warn("ai-engine",`Rate limited (429), attempt ${C+1}/${Ln.length} \u2014 waiting ${H}s`),i&&i(`Rate limited by Anthropic API \u2014 retrying in ${H}s...`),await new Promise(P=>setTimeout(P,H*1e3)),i&&i("Retrying...")}}async function Fs(e,t,o,n,s,i,r,a){let l=ae(),c=$().modules.length>0,u=Dn(e,a),p=ot(),f=u.map(H=>typeof H.content=="string"?H:{role:H.role,content:H.content.map(P=>P.type==="text"?{type:"text",text:P.text}:{type:"image_url",image_url:{url:`data:${P.source.media_type};base64,${P.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:st(l,o,c,p.pageType,p.brandAssets)},...f]})});if(!g.ok){let H=await g.text();throw new Error(`OpenAI API error (${g.status}): ${H}`)}let y=0,S=i||(()=>{});S(re[0]);let C=setInterval(()=>{y++,S(re[Math.min(y,re.length-1)])},6e3),T="",k=g.body.getReader(),E=new TextDecoder,q="";try{for(;;){let{done:H,value:P}=await k.read();if(H)break;q+=E.decode(P,{stream:!0});let L=q.split(`
681
+ `);q=L.pop()||"";for(let ee of L){if(!ee.startsWith("data: "))continue;let J=ee.slice(6).trim();if(J==="[DONE]")break;try{let te=JSON.parse(J).choices?.[0]?.delta?.content;te&&(T+=te,s(te))}catch{}}}}finally{clearInterval(C)}r&&r(T)}async function Js(e,t,o,n,s,i,r){let a=ae(),l=$(),c=l.modules.length>0,u=vt(),p=ot(),f=[];for(let J of l.messages.slice(-20))f.push({role:J.role==="assistant"?"model":"user",parts:[{text:J.content}]});let g=u?`${e}
631
682
 
632
683
  ---
633
- ${c}`:e;p.push({role:"user",parts:[{text:f}]});let h=`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse&key=${t}`,v=await fetch(h,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({systemInstruction:{parts:[{text:Ze(r,o,l,u.pageType,u.brandAssets)}]},contents:p,generationConfig:{maxOutputTokens:48e3}})});if(!v.ok){let L=await v.text();throw new Error(`Gemini API error (${v.status}): ${L}`)}let N=0,K=s||(()=>{});K(te[0]);let F=setInterval(()=>{N++,K(te[Math.min(N,te.length-1)])},6e3),H="",z=v.body.getReader(),q=new TextDecoder,O="";try{for(;;){let{done:L,value:Ae}=await z.read();if(L)break;O+=q.decode(Ae,{stream:!0});let Pe=O.split(`
634
- `);O=Pe.pop()||"";for(let pt of Pe){if(!pt.startsWith("data: "))continue;let de=pt.slice(6).trim();try{let he=JSON.parse(de).candidates?.[0]?.content?.parts?.[0]?.text;he&&(H+=he,n(he))}catch{}}}}finally{clearInterval(F)}i&&i(H)}function es(e,t,o,n){return new Promise((s,i)=>{let r={...process.env};delete r.CLAUDECODE;let a=lr(e,t,{stdio:["pipe","pipe","pipe"],env:r,shell:!0}),l="",c="";a.stdout.on("data",u=>{let p=u.toString();l+=p,n&&n(p)}),a.stderr.on("data",u=>{c+=u.toString()}),a.on("error",u=>i(new Error(`${e} failed to start: ${u.message}`))),a.on("close",u=>{u!==0?i(new Error(`${e} exited with code ${u}.
684
+ ${u}`:e;if(r?.length)for(let J of r)J.type==="document"&&J.extractedText&&(g+=`
685
+
686
+ ---
687
+ [Attached document: ${J.originalName}]
688
+ ${J.extractedText}`),J.type==="image"&&J.usage==="asset"&&J.assetPath&&(g+=`
689
+
690
+ [Uploaded image: ${J.originalName} \u2192 available as get_asset_url("${J.assetPath}")]`);let y=[];if(r?.length)for(let J of r)J.type==="image"&&J.base64&&y.push({inlineData:{mimeType:J.mimeType,data:J.base64}});y.push({text:g}),f.push({role:"user",parts:y});let C=`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse&key=${t}`,T=await fetch(C,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({systemInstruction:{parts:[{text:st(a,o,c,p.pageType,p.brandAssets)}]},contents:f,generationConfig:{maxOutputTokens:48e3}})});if(!T.ok){let J=await T.text();throw new Error(`Gemini API error (${T.status}): ${J}`)}let k=0,E=s||(()=>{});E(re[0]);let q=setInterval(()=>{k++,E(re[Math.min(k,re.length-1)])},6e3),H="",P=T.body.getReader(),L=new TextDecoder,ee="";try{for(;;){let{done:J,value:It}=await P.read();if(J)break;ee+=L.decode(It,{stream:!0});let te=ee.split(`
691
+ `);ee=te.pop()||"";for(let pe of te){if(!pe.startsWith("data: "))continue;let Oe=pe.slice(6).trim();try{let pn=JSON.parse(Oe).candidates?.[0]?.content?.parts?.[0]?.text;pn&&(H+=pn,n(pn))}catch{}}}}finally{clearInterval(q)}i&&i(H)}function Ds(e,t,o,n){return new Promise((s,i)=>{let r={...process.env};delete r.CLAUDECODE;let a=ha(e,t,{stdio:["pipe","pipe","pipe"],env:r,shell:!0}),l="",c="";a.stdout.on("data",u=>{let p=u.toString();l+=p,n&&n(p)}),a.stderr.on("data",u=>{c+=u.toString()}),a.on("error",u=>i(new Error(`${e} failed to start: ${u.message}`))),a.on("close",u=>{u!==0?i(new Error(`${e} exited with code ${u}.
635
692
  `+(c?`Stderr: ${c.slice(0,500)}
636
- `:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):s(l)}),a.stdin.on("error",()=>{}),a.stdin.write(o),a.stdin.end(),setTimeout(()=>{a.kill(),i(new Error(`${e} timed out after 10 minutes`))},6e5)})}async function ts(e,t,o,n,s){let i=se(),r=j(),a=I().modules.length>0,l=Xe(),c=Ze(i,t,a,l.pageType,l.brandAssets);c+=`
693
+ `:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):s(l)}),a.stdin.on("error",()=>{}),a.stdin.write(o),a.stdin.end(),setTimeout(()=>{a.kill(),i(new Error(`${e} timed out after 10 minutes`))},6e5)})}async function Hs(e,t,o,n,s,i){let r=ae(),a=N(),l=$().modules.length>0,c=ot(),u=st(r,t,l,c.pageType,c.brandAssets);u+=`
637
694
 
638
695
  ## User Request
639
- `+e,c+=at();let u=["--print"];r.claudeCodeModel&&u.push("--model",r.claudeCodeModel);let p=0,f=n||(()=>{});f(te[0]);let y=setInterval(()=>{p++;let h=te[Math.min(p,te.length-1)];f(h)},6e3);try{let h=await es("claude",u,c,v=>{o(v)});s&&s(h)}finally{clearInterval(y)}}async function bn(e,t,o,n,s,i){let r=se(),a=I().modules.length>0,l=Xe(),c=Ze(r,o,a,l.pageType,l.brandAssets);c+=`
696
+ `+e,u+=vt(),u+=Ms(i);let p=["--print"];a.claudeCodeModel&&p.push("--model",a.claudeCodeModel);let f=0,g=n||(()=>{});g(re[0]);let y=setInterval(()=>{f++;let S=re[Math.min(f,re.length-1)];g(S)},6e3);try{let S=await Ds("claude",p,u,C=>{o(C)});s&&s(S)}finally{clearInterval(y)}}async function Gn(e,t,o,n,s,i,r){let a=ae(),l=$().modules.length>0,c=ot(),u=st(a,o,l,c.pageType,c.brandAssets);u+=`
640
697
 
641
698
  ## User Request
642
- `+t,c+=at();let u,p;e==="gemini"?(u="gemini",p=[]):(u="codex",p=["exec","--full-auto"]);let f=0,y=s||(()=>{});y(te[0]);let h=setInterval(()=>{f++;let v=te[Math.min(f,te.length-1)];y(v)},6e3);try{let v=await es(u,p,c,N=>{n(N)});i&&i(v)}finally{clearInterval(h)}}var Sn=null;function ns(e){Sn=e}var lt=null;function ct(){return lt!==null}function et(e){if(lt){let t=I();if(!t||t.id!==lt){ee.warn("ai-handler","Session changed during generation \u2014 discarding AI output");return}}Fe("assistant",e),qo(e,Sn||void 0),P()}async function wn(e,t,o){let n=I();if(!n)throw new Error("No active session");lt=n.id;try{let i=j(),r=i.aiEngine||dr();switch(r){case"anthropic-api":case"api":{let a=je("anthropic-api",i);if(!a)throw new Error("Anthropic API key not configured. Open Settings to add one.");await Qo(e,a,n.themeName,i.anthropicApiModel||"claude-sonnet-4-6",t,o,et);break}case"openai-api":{let a=je("openai-api",i);if(!a)throw new Error("OpenAI API key not configured. Open Settings to add one.");await Xo(e,a,n.themeName,i.openaiApiModel||"gpt-4o",t,o,et);break}case"gemini-api":{let a=je("gemini-api",i);if(!a)throw new Error("Gemini API key not configured. Open Settings to add one.");await Zo(e,a,n.themeName,t,o,et);break}case"claude-code":await ts(e,n.themeName,t,o,et);break;case"gemini-cli":await bn("gemini",e,n.themeName,t,o,et);break;case"codex-cli":await bn("codex",e,n.themeName,t,o,et);break;default:throw new Error(`Unknown AI engine: ${r}. Open Settings to configure one.`)}}finally{lt=null,Sn=null}}function dr(){let e=j();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 vn("claude --version",{stdio:"pipe"}),"claude-code"}catch{}try{return vn("gemini --version",{stdio:"pipe"}),"gemini-cli"}catch{}try{return vn("codex --version",{stdio:"pipe"}),"codex-cli"}catch{}throw new Error("No AI engine available. Open Settings to configure one.")}import{spawn as os}from"child_process";var He=new Map;function pe(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};He.set(n,s);let i=e.split(" "),r=os(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0});r.stdout?.on("data",l=>{s.output+=l.toString()}),r.stderr?.on("data",l=>{s.output+=l.toString()}),r.on("close",l=>{s.status=l===0?"completed":"failed",s.exitCode=l,s.completedAt=Date.now()}),r.on("error",l=>{s.status="failed",s.output+=`
699
+ `+t,u+=vt(),u+=Ms(r);let p,f;e==="gemini"?(p="gemini",f=[]):(p="codex",f=["exec","--full-auto"]);let g=0,y=s||(()=>{});y(re[0]);let S=setInterval(()=>{g++;let C=re[Math.min(g,re.length-1)];y(C)},6e3);try{let C=await Ds(p,f,u,T=>{n(T)});i&&i(C)}finally{clearInterval(S)}}import{createWriteStream as ba,mkdirSync as Ls,existsSync as Un,readFileSync as Wn}from"fs";import{join as Ue,extname as Sa}from"path";import{randomUUID as va}from"crypto";import wa from"busboy";function d(e,t,o){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(o))}function R(e,t){let o=[];e.on("data",n=>o.push(n)),e.on("end",()=>t(Buffer.concat(o).toString("utf-8")))}var xa=10*1024*1024,Gs=new Set(["image/png","image/jpeg","image/jpg","image/svg+xml","image/webp","image/gif"]),Ca=new Set(["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/markdown","text/plain"]),Aa=new Set([...Gs,...Ca]);function Ia(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_").replace(/_{2,}/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function $a(e,t){if(!Un(Ue(e,t)))return t;let o=Sa(t),n=t.slice(0,-o.length||void 0),s=1;for(;Un(Ue(e,`${n}-${s}${o}`));)s++;return`${n}-${s}${o}`}async function Ta(e){let t=(await import("pdf-parse")).default,o=Wn(e);return(await t(o)).text}async function ka(e){return(await(await import("mammoth")).extractRawText({path:e})).value}function Ea(e){return Wn(e,"utf-8")}function Us(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=[],r=0,a=[],l=wa({headers:e.headers,limits:{fileSize:xa,files:10}});l.on("file",(c,u,p)=>{let{filename:f,mimeType:g}=p;if(r++,!Aa.has(g)){i.push(`Unsupported file type: ${f} (${g})`),u.resume();return}let y=Gs.has(g),S=Ia(f),C=va(),T,k;y?(T=Ue(o.themePath,"assets"),Ls(T,{recursive:!0}),k=$a(T,S)):(T=Ue(o.themePath,".vibespot","uploads"),Ls(T,{recursive:!0}),k=`${C}-${S}`);let E=Ue(T,k),q=ba(E),H=0,P=!1;u.on("data",L=>{H+=L.length}),u.on("limit",()=>{P=!0,i.push(`File too large (>10MB): ${f}`)}),u.pipe(q),a.push(new Promise(L=>{q.on("finish",()=>{if(!P){let ee={id:C,filename:k,originalName:f,type:y?"image":"document",usage:y?"asset":"context",mimeType:g,size:H,addedAt:new Date().toISOString()};s.push(ee),ps(ee)}L()}),q.on("error",()=>{i.push(`Failed to write: ${f}`),L()})}))}),l.on("finish",async()=>{await Promise.all(a);for(let c of s)if(c.type==="document"){let u=Ue(o.themePath,".vibespot","uploads",c.filename);try{c.mimeType==="application/pdf"?c.extractedText=await Ta(u):c.mimeType==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"?c.extractedText=await ka(u):c.extractedText=Ea(u),z.info("upload",`Extracted text from ${c.originalName} (${c.extractedText.length} chars)`)}catch(p){z.warn("upload",`Failed to extract text from ${c.originalName}: ${p}`),c.extractedText=`[Could not extract text from ${c.originalName}]`}}if(r===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=>{z.error("upload",`Busboy error: ${c}`),d(t,500,{error:"Upload failed"})}),e.pipe(l)}function Ws(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=Ue(t.themePath,"assets",n.filename);Un(i)&&(s.base64=Wn(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 Bn=null;function Ks(e){Bn=e}var wt=null;function xt(){return wt!==null}function it(e){if(wt){let t=$();if(!t||t.id!==wt){z.warn("ai-handler","Session changed during generation \u2014 discarding AI output");return}}Le("assistant",e),Os(e,Bn||void 0),F()}async function Yn(e,t,o,n){let s=$();if(!s)throw new Error("No active session");wt=s.id;let r=n?.length?Ws(n):void 0;try{let a=N(),l=a.aiEngine||Na();switch(l){case"anthropic-api":case"api":{let c=Me("anthropic-api",a);if(!c)throw new Error("Anthropic API key not configured. Open Settings to add one.");await js(e,c,s.themeName,a.anthropicApiModel||"claude-sonnet-4-6",t,o,it,r);break}case"openai-api":{let c=Me("openai-api",a);if(!c)throw new Error("OpenAI API key not configured. Open Settings to add one.");await Fs(e,c,s.themeName,a.openaiApiModel||"gpt-4o",t,o,it,r);break}case"gemini-api":{let c=Me("gemini-api",a);if(!c)throw new Error("Gemini API key not configured. Open Settings to add one.");await Js(e,c,s.themeName,t,o,it,r);break}case"claude-code":await Hs(e,s.themeName,t,o,it,r);break;case"gemini-cli":await Gn("gemini",e,s.themeName,t,o,it,r);break;case"codex-cli":await Gn("codex",e,s.themeName,t,o,it,r);break;default:throw new Error(`Unknown AI engine: ${l}. Open Settings to configure one.`)}}finally{wt=null,Bn=null}}function Na(){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 Kn("claude --version",{stdio:"pipe"}),"claude-code"}catch{}try{return Kn("gemini --version",{stdio:"pipe"}),"gemini-cli"}catch{}try{return Kn("codex --version",{stdio:"pipe"}),"codex-cli"}catch{}throw new Error("No AI engine available. Open Settings to configure one.")}import{spawn as Bs}from"child_process";var We=new Map;function be(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};We.set(n,s);let i=e.split(" "),r=Bs(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0});r.stdout?.on("data",l=>{s.output+=l.toString()}),r.stderr?.on("data",l=>{s.output+=l.toString()}),r.on("close",l=>{s.status=l===0?"completed":"failed",s.exitCode=l,s.completedAt=Date.now()}),r.on("error",l=>{s.status="failed",s.output+=`
643
700
  Process error: ${l.message}`,s.completedAt=Date.now()});let a=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(r.kill(),s.status="failed",s.output+=`
644
- Process timed out`,s.completedAt=Date.now())},a),n}function Ht(e){return He.get(e)}function ur(){let e=Date.now()-18e5;for(let[t,o]of He)o.completedAt&&o.completedAt<e&&He.delete(t)}setInterval(ur,600*1e3);function Gt(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};He.set(n,s);let i=e.split(" "),r=os(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0}),a=c=>{for(let u of s.listeners)try{u(c)}catch{}};r.stdout?.on("data",c=>{let u=c.toString();s.output+=u,a(u)}),r.stderr?.on("data",c=>{let u=c.toString();s.output+=u,a(u)}),r.on("close",c=>{s.status=c===0?"completed":"failed",s.exitCode=c,s.completedAt=Date.now()}),r.on("error",c=>{s.status="failed",s.output+=`
701
+ Process timed out`,s.completedAt=Date.now())},a),n}function rn(e){return We.get(e)}function _a(){let e=Date.now()-18e5;for(let[t,o]of We)o.completedAt&&o.completedAt<e&&We.delete(t)}setInterval(_a,600*1e3);function an(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};We.set(n,s);let i=e.split(" "),r=Bs(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0}),a=c=>{for(let u of s.listeners)try{u(c)}catch{}};r.stdout?.on("data",c=>{let u=c.toString();s.output+=u,a(u)}),r.stderr?.on("data",c=>{let u=c.toString();s.output+=u,a(u)}),r.on("close",c=>{s.status=c===0?"completed":"failed",s.exitCode=c,s.completedAt=Date.now()}),r.on("error",c=>{s.status="failed",s.output+=`
645
702
  Process error: ${c.message}`,s.completedAt=Date.now()});let l=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(r.kill(),s.status="failed",s.output+=`
646
- Process timed out`,s.completedAt=Date.now())},l),n}function ss(e,t){let o=He.get(e);if(!o||!("listeners"in o))return;let n=o;if(n.output)try{t(n.output)}catch{}n.listeners.add(t)}function is(e,t){let o=He.get(e);!o||!("listeners"in o)||o.listeners.delete(t)}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")))}import{existsSync as Ce,readdirSync as dt,rmSync as rs,renameSync as mr}from"fs";import{join as fe,basename as pr}from"path";import{homedir as fr}from"os";import{execSync as xn}from"child_process";var ge=fe(fr(),"vibespot-themes"),Wt=null,gr=5e3;function hr(){if(Wt&&Date.now()-Wt.ts<gr)return Wt.data;let e=[];if(Ce(ge))try{for(let t of dt(ge,{withFileTypes:!0}))if(t.isDirectory()){let o=fe(ge,t.name,"theme.json");if(Ce(o)){let n=0,s=fe(ge,t.name,"modules");if(Ce(s))try{n=dt(s,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}e.push({name:t.name,moduleCount:n})}}}catch{}return Wt={data:e,ts:Date.now()},e}function as(e){let t=I(),o=vt(),n=!1;try{xn("hs --version",{encoding:"utf-8",stdio:"pipe"}),n=!0}catch{}let s=Ft().sort((r,a)=>a.updatedAt-r.updatedAt).slice(0,10),i=hr();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 ls(e,t){$(e,o=>{try{if(ct()){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=fe(ge,s);$e(ge),Ce(i)&&rs(i,{recursive:!0,force:!0});let r=new Set(dt(process.cwd()));xn(`hs cms theme create "${s}"`,{encoding:"utf-8",stdio:"pipe"});let a=fe(process.cwd(),s);if(!Ce(a)){let u=dt(process.cwd()).find(p=>!r.has(p)&&Ce(fe(process.cwd(),p)));u&&(a=fe(process.cwd(),u))}a!==i&&Ce(a)&&mr(a,i);let l=fe(i,"templates");if(Ce(l))for(let c of dt(l))c.endsWith(".html")&&rs(fe(l,c));jt(i,s),P(),d(t,200,{ok:!0,themeName:s,themePath:i})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function cs(e,t){$(e,o=>{try{if(ct()){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=fe(ge,n);$e(ge),xn(`hs cms fetch "${n}" "${s}"`,{encoding:"utf-8",stdio:"pipe"}),jt(s,n),Jt(s),P(),d(t,200,{ok:!0,themeName:n,themePath:s,moduleCount:I()?.modules.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function ds(e,t){$(e,o=>{try{if(ct()){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(Ce(s)||(s=fe(ge,n)),!Ce(s)){d(t,400,{error:`Theme folder not found: ${n}`});return}let i=pr(s);jt(s,i),Jt(s),P(),d(t,200,{ok:!0,themeName:i,themePath:s,moduleCount:I()?.modules.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function us(e,t){$(e,o=>{try{if(ct()){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=Dt(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 ms(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}ne({anthropicApiKey:n}),d(t,200,{ok:!0})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}import{existsSync as yr,readFileSync as br,appendFileSync as vr}from"fs";import{join as ps}from"path";import{homedir as fs}from"os";var ut={data:{},ts:0},Sr=600*1e3,gs={"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 wr(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 xr(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 Cr(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 Ar(){if(Date.now()-ut.ts<Sr&&Object.keys(ut.data).length>0)return ut.data;let e=j(),t={...gs},o=[],n=je("anthropic-api",e);n&&o.push(wr(n).then(r=>{r.length&&(t["anthropic-api"]=r)}).catch(()=>{}));let s=je("openai-api",e);s&&o.push(xr(s).then(r=>{r.length&&(t["openai-api"]=r)}).catch(()=>{}));let i=je("gemini-api",e);return i&&o.push(Cr(i).then(r=>{r.length&&(t["gemini-api"]=r,t["gemini-cli"]=r)}).catch(()=>{})),await Promise.all(o),ut.data=t,ut.ts=Date.now(),t}function hs(e){let t=vt(),o=j();Ar().then(n=>{d(e,200,{environment:t,config:{aiEngine:o.aiEngine||null,claudeCodeModel:o.claudeCodeModel||null,anthropicApiModel:o.anthropicApiModel||null,openaiApiModel:o.openaiApiModel||null},models:n})}).catch(()=>{d(e,200,{environment:t,config:{aiEngine:o.aiEngine||null,claudeCodeModel:o.claudeCodeModel||null,anthropicApiModel:o.anthropicApiModel||null,openaiApiModel:o.openaiApiModel||null},models:gs})})}function ys(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 r={aiEngine:n};if(s)switch(n){case"claude-code":r.claudeCodeModel=s;break;case"anthropic-api":r.anthropicApiModel=s;break;case"openai-api":r.openaiApiModel=s;break}ne(r),d(t,200,{ok:!0,engine:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function bs(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}ne(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}ne(i);let r=null;if(!j().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[n];c&&(ne({aiEngine:c}),r=c)}d(t,200,{ok:!0,provider:n,autoSelectedEngine:r})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function vs(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 r=pe(i.cmd,i.desc,{timeout:12e4});d(t,200,{ok:!0,jobId:r})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ss(e,t){$(e,o=>{try{let n=JSON.parse(o||"{}");if(!Ee().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let i=ve();if(i.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:i.portalName,portalId:i.portalId});return}if(n.personalAccessKey){let r=pe(`hs auth --pak="${n.personalAccessKey}"`,"Authenticating with HubSpot",{timeout:3e4});d(t,200,{ok:!0,jobId:r});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 ws(e,t){$(e,o=>{try{let n=JSON.parse(o||"{}");if(!zt().found){d(t,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=qt();if(i.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(n.token){let a=pe(`echo "${n.token}" | gh auth login --with-token`,"Authenticating with GitHub",{timeout:3e4});d(t,200,{ok:!0,jobId:a});return}let r=pe("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});d(t,200,{ok:!0,jobId:r,browserAuthRequired:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function xs(e,t){$(e,o=>{try{let{portalId:n,action:s}=JSON.parse(o);if(!Ee().found){d(t,400,{error:"HubSpot CLI not installed"});return}if(s==="remove"&&n){let r=pe(`hs accounts remove ${n}`,`Removing HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:r});return}if(n){let r=pe(`hs accounts use ${n}`,`Switching to HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:r});return}d(t,400,{error:"portalId required"})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Cs(e){let t=pe("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});d(e,200,{ok:!0,jobId:t})}function As(e,t){$(e,o=>{try{let{cli:n,apiKey:s}=JSON.parse(o||"{}");switch(n){case"claude":{let i=pe("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=pe("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,ne({openaiApiKey:i}),process.platform!=="win32"){let r=`export OPENAI_API_KEY="${i}"`,a=process.env.SHELL?.includes("zsh")?ps(fs(),".zshrc"):ps(fs(),".bashrc");try{(yr(a)?br(a,"utf-8"):"").includes("OPENAI_API_KEY")||vr(a,`
703
+ Process timed out`,s.completedAt=Date.now())},l),n}function Ys(e,t){let o=We.get(e);if(!o||!("listeners"in o))return;let n=o;if(n.output)try{t(n.output)}catch{}n.listeners.add(t)}function Vs(e,t){let o=We.get(e);!o||!("listeners"in o)||o.listeners.delete(t)}import{existsSync as rt,readdirSync as zs,rmSync as Ra}from"fs";import{join as at,basename as Pa}from"path";import{homedir as Oa}from"os";import{execSync as qs}from"child_process";var Se=at(Oa(),"vibespot-themes"),ln=null,Ma=5e3;function cn(){if(ln&&Date.now()-ln.ts<Ma)return ln.data;let e=[];if(rt(Se))try{for(let t of zs(Se,{withFileTypes:!0}))if(t.isDirectory()){let o=at(Se,t.name,"theme.json");if(rt(o)){let n=0,s=at(Se,t.name,"modules");if(rt(s))try{n=zs(s,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}e.push({name:t.name,moduleCount:n})}}}catch{}return ln={data:e,ts:Date.now()},e}function Xs(e){let t=$(),o=Rt(),n=!1;try{qs("hs --version",{encoding:"utf-8",stdio:"pipe"}),n=!0}catch{}let s=et().sort((r,a)=>a.updatedAt-r.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 Qs(e,t){R(e,o=>{try{if(xt()){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=at(Se,s);ke(Se),rt(i)&&Ra(i,{recursive:!0,force:!0}),Dt(i,s),bt(i,s),F(),d(t,200,{ok:!0,themeName:s,themePath:i})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Zs(e,t){R(e,o=>{try{if(xt()){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=fe(),r=N(),a=at(Se,s);ke(Se),r.hubspotUploadMode==="cli"||!i?(qs(`hs cms fetch "${s}" "${a}"`,{encoding:"utf-8",stdio:"pipe"}),bt(a,s),St(a),F(),d(t,200,{ok:!0,themeName:s,themePath:a,moduleCount:$()?.modules.length||0})):Ht(i,s,a).then(()=>{bt(a,s),St(a),F(),d(t,200,{ok:!0,themeName:s,themePath:a,moduleCount:$()?.modules.length||0})}).catch(l=>{d(t,500,{error:l instanceof Error?l.message:String(l)})})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function ei(e,t){R(e,o=>{try{if(xt()){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(rt(s)||(s=at(Se,n)),!rt(s)){d(t,400,{error:`Theme folder not found: ${n}`});return}let i=Pa(s);bt(s,i),St(s),F(),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 ti(e,t){R(e,o=>{try{if(xt()){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=on(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 ni(e,t){R(e,o=>{try{let{apiKey:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"API key is required"});return}Y({anthropicApiKey:n}),d(t,200,{ok:!0})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function oi(e){let t=fe();if(!t){d(e,200,{themes:[],error:"No HubSpot account connected"});return}(async()=>{let o=await yo(t);if(o.length===0){d(e,200,{themes:[]});return}let n=[],s=o.map(async a=>{let l=a.path||a.name;try{let c=await Mt(t,`${l}/theme.json`);c&&!c.folder&&n.push({name:a.name,path:l})}catch{}});await Promise.all(s),n.sort((a,l)=>a.name.localeCompare(l.name));let i=cn(),r=new Set(i.map(a=>a.name));d(e,200,{themes:n.map(a=>({...a,existsLocally:r.has(a.name)}))})})().catch(o=>{d(e,200,{themes:[],error:o instanceof Error?o.message:String(o)})})}import{existsSync as ja,readFileSync as Fa,appendFileSync as Ja}from"fs";import{join as si}from"path";import{homedir as ii}from"os";var Ct={data:{},ts:0},Da=600*1e3,ri={"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 Ha(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 La(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 Ga(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 Ua(){if(Date.now()-Ct.ts<Da&&Object.keys(Ct.data).length>0)return Ct.data;let e=N(),t={...ri},o=[],n=Me("anthropic-api",e);n&&o.push(Ha(n).then(r=>{r.length&&(t["anthropic-api"]=r)}).catch(()=>{}));let s=Me("openai-api",e);s&&o.push(La(s).then(r=>{r.length&&(t["openai-api"]=r)}).catch(()=>{}));let i=Me("gemini-api",e);return i&&o.push(Ga(i).then(r=>{r.length&&(t["gemini-api"]=r,t["gemini-cli"]=r)}).catch(()=>{})),await Promise.all(o),Ct.data=t,Ct.ts=Date.now(),t}function ai(e){let t=Rt(),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=et().length,i=cn().length;Ua().then(r=>{d(e,200,{environment:t,config:n,models:r,sessionCount:s,localThemeCount:i})}).catch(()=>{d(e,200,{environment:t,config:n,models:ri,sessionCount:s,localThemeCount:i})})}function li(e,t){R(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 r={aiEngine:n};if(s)switch(n){case"claude-code":r.claudeCodeModel=s;break;case"anthropic-api":r.anthropicApiModel=s;break;case"openai-api":r.openaiApiModel=s;break}Y(r),d(t,200,{ok:!0,engine:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function ci(e,t){R(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}Y(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}Y(i);let r=null;if(!N().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[n];c&&(Y({aiEngine:c}),r=c)}d(t,200,{ok:!0,provider:n,autoSelectedEngine:r})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function di(e,t){R(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 r=be(i.cmd,i.desc,{timeout:12e4});d(t,200,{ok:!0,jobId:r})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function ui(e,t){R(e,o=>{try{let n=JSON.parse(o||"{}"),s=N(),i=s.hubspotUploadMode||"api";if(n.personalAccessKey)if(i==="api"){Ot(n.personalAccessKey).then(r=>{$t(n.personalAccessKey,r.portalId,r.portalName,r.dataCenter),d(t,200,{ok:!0,portalName:r.portalName,portalId:r.portalId,dataCenter:r.dataCenter})}).catch(r=>{d(t,400,{error:r instanceof Error?r.message:String(r)})});return}else{if(!xe().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let a=be(`hs auth --pak="${n.personalAccessKey}"`,"Authenticating with HubSpot",{timeout:3e4});d(t,200,{ok:!0,jobId:a});return}if(i==="api"){let r=s.hubspotAccounts||[];if(r.length>0&&!n.force){let a=r.find(l=>l.portalId===s.activeHubSpotAccount)||r[0];d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:a.portalName,portalId:a.portalId});return}}else{if(!xe().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let a=Ce();if(a.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:a.portalName,portalId:a.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 mi(e,t){R(e,o=>{try{let n=JSON.parse(o||"{}");if(!bn().found){d(t,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=Sn();if(i.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(n.token){let a=be(`echo "${n.token}" | gh auth login --with-token`,"Authenticating with GitHub",{timeout:3e4});d(t,200,{ok:!0,jobId:a});return}let r=be("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});d(t,200,{ok:!0,jobId:r,browserAuthRequired:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function pi(e,t){R(e,o=>{try{let{portalId:n,action:s}=JSON.parse(o);if((N().hubspotUploadMode||"api")==="api"){if(s==="remove"&&n){ro(n),d(t,200,{ok:!0});return}if(n){ao(n),d(t,200,{ok:!0});return}}else{if(!xe().found){d(t,400,{error:"HubSpot CLI not installed"});return}if(s==="remove"&&n){let l=be(`hs accounts remove ${n}`,`Removing HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:l});return}if(n){let l=be(`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 fi(e){let t=be("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});d(e,200,{ok:!0,jobId:t})}function gi(e,t){R(e,o=>{try{let{cli:n,apiKey:s}=JSON.parse(o||"{}");switch(n){case"claude":{let i=be("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=be("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,Y({openaiApiKey:i}),process.platform!=="win32"){let r=`export OPENAI_API_KEY="${i}"`,a=process.env.SHELL?.includes("zsh")?si(ii(),".zshrc"):si(ii(),".bashrc");try{(ja(a)?Fa(a,"utf-8"):"").includes("OPENAI_API_KEY")||Ja(a,`
647
704
  # Added by vibeSpot
648
705
  ${r}
649
- `)}catch{}}d(t,200,{ok:!0,message:"API key saved"})}else{let i=pe("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 Is(e,t){let o=e.replace("/api/settings/job/","");if(!o){d(t,400,{error:"Job ID required"});return}let n=Ht(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})}import{existsSync as Ir,rmSync as kr}from"fs";import{join as $r}from"path";function ks(e,t,o){if(e==="GET"){let n=I(),s=Ft().sort((i,r)=>r.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);Mo(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 $s(e,t){$(e,o=>{try{let{sessionId:n}=JSON.parse(o),s=Dt(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 Es(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=$r(ge,n);if(!Ir(s)){d(t,404,{error:"Theme not found on disk"});return}kr(s,{recursive:!0,force:!0}),d(t,200,{ok:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ts(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 r=Jo(n,i);r.ok?d(t,200,{ok:!0,newName:i}):d(t,400,{error:r.error})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}import{existsSync as Cn,readFileSync as Er,rmSync as An}from"fs";import{join as mt,basename as Tr}from"path";import{execSync as Nr}from"child_process";function Ns(e){let t=I();if(!t){d(e,404,{error:"No active session"});return}let o=ze();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 _s(e){let t=I();if(!t){d(e,404,{error:"No active session"});return}let o=t.themePath;if(!Cn(o)){d(e,404,{error:"Theme directory not found"});return}let n=t.themeName||"theme",s=mt(o,".."),i=Tr(o);try{let r=`${n}.zip`,a=mt(s,r);Cn(a)&&An(a),Nr(`zip -r "${r}" "${i}" -x "${i}/.git/*" "${i}/.vibespot/*" "${i}/node_modules/*"`,{cwd:s,timeout:3e4});let l=Er(a);An(a),e.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${r}"`,"Content-Length":l.length}),e.end(l)}catch(r){ee.error("download-zip","Failed to create zip archive",r),d(e,500,{error:"Failed to create zip archive"})}}function Rs(e,t,o){let n=I();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:r}=JSON.parse(s);if(!i||!r){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=To(i,r);P(),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(!_o(i)){d(o,404,{error:"Template not found"});return}P(),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 Os(e,t){$(e,o=>{try{let{templateId:n}=JSON.parse(o);if(!n){d(t,400,{error:"templateId is required"});return}if(!ln(n)){d(t,404,{error:"Template not found"});return}P();let i=I();d(t,200,{ok:!0,modules:ce().map(r=>r.moduleName),messageCount:i?.messages.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ps(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(!No(n,s.trim())){d(t,404,{error:"Template not found"});return}P(),d(t,200,{ok:!0,newLabel:s.trim()})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function js(e){let t=ze();d(e,200,{modules:t.map(o=>({moduleName:o.module.moduleName,usedIn:o.usedIn,fieldsJson:o.module.fieldsJson}))})}function Ms(e,t,o){let n=I();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 a=ze().find(u=>u.module.moduleName===i);if(!a){d(o,404,{error:`Module "${i}" not found in library`});return}let l={...a.module};n.modules.find(u=>u.moduleName===l.moduleName)||(n.modules.push(l),n.moduleOrder.push(l.moduleName),n.updatedAt=Date.now()),P(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}})}function Js(e,t,o){let n=I();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:r}=JSON.parse(s);if(!i){d(o,400,{error:"type is required"});return}if(n.brandAssets||(n.brandAssets={}),i==="humanify"){n.brandAssets.humanify=r==="on",n.updatedAt=Date.now(),P(),d(o,200,{ok:!0});return}if(!r){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]=r,n.updatedAt=Date.now();let a=mt(n.themePath,".vibespot");$e(a),E(mt(a,`${i}.md`),r),P(),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 r=mt(n.themePath,".vibespot",`${i}.md`);Cn(r)&&An(r),P(),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"})}import{join as _r}from"path";function Ds(e,t){let o=I();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 Fs(e,t,o){let n=I();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){let s=ce();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:r}=JSON.parse(s);r?Oo(i):Po(i),P(),d(o,200,{ok:!0})});return}d(o,405,{error:"Method not allowed"})}function Ls(e,t){$(e,o=>{let{order:n}=JSON.parse(o);Array.isArray(n)?(Ro(n),P(),d(t,200,{ok:!0})):d(t,400,{error:"order must be an array"})})}async function Hs(e){let t=I();if(!t){d(e,404,{error:"No active session"});return}try{qe();let o=_t(t.themePath),n=Gt(`hs cms upload "${t.themePath}" "${t.themeName}"`,"Uploading to HubSpot",{cwd:_r(t.themePath,".."),timeout:18e4});d(e,200,{ok:!0,jobId:n,fixes:o})}catch(o){d(e,500,{error:String(o)})}}function Gs(e,t){$(e,o=>{try{let{moduleName:n,fieldPath:s,value:i}=JSON.parse(o);jo(n,s,i),P(),d(t,200,{ok:!0})}catch(n){d(t,400,{error:String(n)})}})}function Ws(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=Ln(n),i=s.components.map(a=>`- ${a.name}: ${a.description}`).join(`
706
+ `)}catch{}}d(t,200,{ok:!0,message:"API key saved"})}else{let i=be("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 hi(e,t){R(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}Y({hubspotUploadMode:n}),d(t,200,{ok:!0,mode:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function yi(e,t){R(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}lo(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 bi(e,t){let o=e.replace("/api/settings/job/","");if(!o){d(t,400,{error:"Job ID required"});return}let n=rn(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})}import{existsSync as Wa,rmSync as Ka}from"fs";import{join as Ba}from"path";function Si(e,t,o){if(e==="GET"){let n=$(),s=et().sort((i,r)=>r.updatedAt-i.updatedAt);d(o,200,{activeTheme:n?{id:n.id,themeName:n.themeName}:null,sessions:s});return}if(e==="DELETE"){R(t,n=>{try{let{sessionId:s,deleteFiles:i}=JSON.parse(n);bs(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 vi(e,t){R(e,o=>{try{let{sessionId:n}=JSON.parse(o),s=on(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 wi(e,t){R(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=Ba(Se,n);if(!Wa(s)){d(t,404,{error:"Theme not found on disk"});return}Ka(s,{recursive:!0,force:!0}),d(t,200,{ok:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function xi(e,t){R(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 r=Ss(n,i);r.ok?d(t,200,{ok:!0,newName:i}):d(t,400,{error:r.error})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}import{existsSync as Vn,readFileSync as Ya,rmSync as zn}from"fs";import{join as At,basename as Va}from"path";import{execSync as za}from"child_process";function Ci(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}let o=Ze();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 Ai(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}let o=t.themePath;if(!Vn(o)){d(e,404,{error:"Theme directory not found"});return}let n=t.themeName||"theme",s=At(o,".."),i=Va(o);try{let r=`${n}.zip`,a=At(s,r);Vn(a)&&zn(a),za(`zip -r "${r}" "${i}" -x "${i}/.git/*" "${i}/.vibespot/*" "${i}/node_modules/*"`,{cwd:s,timeout:3e4});let l=Ya(a);zn(a),e.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${r}"`,"Content-Length":l.length}),e.end(l)}catch(r){z.error("download-zip","Failed to create zip archive",r),d(e,500,{error:"Failed to create zip archive"})}}function Ii(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"){R(t,s=>{try{let{pageType:i,label:r}=JSON.parse(s);if(!i||!r){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=ds(i,r);F(),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"){R(t,s=>{try{let{templateId:i}=JSON.parse(s);if(!i){d(o,400,{error:"templateId is required"});return}if(!ms(i)){d(o,404,{error:"Template not found"});return}F(),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 $i(e,t){R(e,o=>{try{let{templateId:n}=JSON.parse(o);if(!n){d(t,400,{error:"templateId is required"});return}if(!Rn(n)){d(t,404,{error:"Template not found"});return}F();let i=$();d(t,200,{ok:!0,modules:me().map(r=>r.moduleName),messageCount:i?.messages.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ti(e,t){R(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(!us(n,s.trim())){d(t,404,{error:"Template not found"});return}F(),d(t,200,{ok:!0,newLabel:s.trim()})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function ki(e){let t=Ze();d(e,200,{modules:t.map(o=>({moduleName:o.module.moduleName,usedIn:o.usedIn,fieldsJson:o.module.fieldsJson}))})}function Ei(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}R(t,s=>{try{let{moduleName:i}=JSON.parse(s);if(!i){d(o,400,{error:"moduleName is required"});return}let a=Ze().find(u=>u.module.moduleName===i);if(!a){d(o,404,{error:`Module "${i}" not found in library`});return}let l={...a.module};n.modules.find(u=>u.moduleName===l.moduleName)||(n.modules.push(l),n.moduleOrder.push(l.moduleName),n.updatedAt=Date.now()),F(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}})}function Ni(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"){R(t,s=>{try{let{type:i,content:r}=JSON.parse(s);if(!i){d(o,400,{error:"type is required"});return}if(n.brandAssets||(n.brandAssets={}),i==="humanify"){n.brandAssets.humanify=r==="on",n.updatedAt=Date.now(),F(),d(o,200,{ok:!0});return}if(!r){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]=r,n.updatedAt=Date.now();let a=At(n.themePath,".vibespot");ke(a),O(At(a,`${i}.md`),r),F(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}if(e==="DELETE"){R(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 r=At(n.themePath,".vibespot",`${i}.md`);Vn(r)&&zn(r),F(),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"})}import{join as qa}from"path";function _i(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 Ri(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){let s=me();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"){R(t,s=>{let{moduleName:i,deleteEntirely:r}=JSON.parse(s);r?gs(i):hs(i),F(),d(o,200,{ok:!0})});return}d(o,405,{error:"Method not allowed"})}function Pi(e,t){R(e,o=>{let{order:n}=JSON.parse(o);Array.isArray(n)?(fs(n),F(),d(t,200,{ok:!0})):d(t,400,{error:"order must be an array"})})}async function Oi(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}try{tt();let o=Xt(t.themePath),n=an(`hs cms upload "${t.themePath}" "${t.themeName}"`,"Uploading to HubSpot",{cwd:qa(t.themePath,".."),timeout:18e4});d(e,200,{ok:!0,jobId:n,fixes:o})}catch(o){d(e,500,{error:String(o)})}}function Mi(e,t){R(e,o=>{try{let{moduleName:n,fieldPath:s,value:i}=JSON.parse(o);ys(n,s,i),F(),d(t,200,{ok:!0})}catch(n){d(t,400,{error:String(n)})}})}function ji(e,t){R(e,o=>{try{let{url:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"url is required"});return}let s=wo(n),i=s.components.map(a=>`- ${a.name}: ${a.description}`).join(`
650
707
  `),r={sourceDir:s.sourceDir,componentCount:s.components.length,components:s.components.map(a=>({name:a.name,description:a.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.
651
708
 
652
709
  Source analysis found ${s.components.length} components:
@@ -656,7 +713,11 @@ Design system: ${s.hasTailwind?"Tailwind CSS":"Custom CSS"}, ${s.cssVarCount} CS
656
713
  Fonts: ${s.fonts.length>0?s.fonts.join(", "):"System fonts"}
657
714
  Interactions: ${s.interactions.join(", ")}
658
715
 
659
- 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,r)}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Us(e,t){let o=I();if(!o){d(t,404,{error:"No active session"});return}if(!me()){d(t,200,{available:!1,commits:[]});return}let s=new URL(e.url||"/","http://localhost").searchParams.get("templateId"),i=s?Ao(o.themePath,s,50):Co(o.themePath,50);d(t,200,{available:!0,commits:i,filtered:!!s})}function Ks(e,t){$(e,o=>{try{let n=I();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(Fe("assistant",`Rolled back to version ${s.slice(0,7)}.`),i){let r=n.templates.find(c=>c.id===i);if(!r){d(t,404,{error:"Template not found"});return}let a=r.moduleOrder.map(c=>`modules/${c}.module`);r.templateFile&&a.push(r.templateFile);let l=ko(n.themePath,i,s,a);if(!l.success){d(t,500,{error:l.error||"Rollback failed"});return}Fo()}else{let r=Io(n.themePath,s);if(!r.success){d(t,500,{error:r.error||"Rollback failed"});return}Do()}P(),d(t,200,{ok:!0,modules:ce().map(r=>r.moduleName)})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}var Mr={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".ico":"image/x-icon",".woff2":"font/woff2"};function zs(e){let{port:t,uiDir:o}=e,n=Rr((i,r)=>Jr(i,r,o)),s=new jr({server:n});return s.on("connection",i=>Fr(i)),new Promise((i,r)=>{n.on("error",a=>{a.code==="EADDRINUSE"?n.listen(t+1,()=>{i({port:t+1,close:()=>{n.close(),s.close()}})}):r(a)}),n.listen(t,()=>{i({port:t,close:()=>{n.close(),s.close()}})})})}function Jr(e,t,o){let n=new URL(e.url||"/",`http://${e.headers.host}`),s=e.method||"GET";if(n.pathname.startsWith("/api/")){Dr(s,n.pathname,e,t);return}if(n.pathname==="/preview"){let i=Vo();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")||"",r=zo(i);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(r||"<!-- module not found -->");return}Lr(n.pathname,o,e,t)}function Dr(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":Ds(e,n);break;case"/api/modules":Fs(e,o,n);break;case"/api/modules/reorder":Ls(o,n);break;case"/api/upload":Hs(n);break;case"/api/field":Gs(o,n);break;case"/api/import":Ws(o,n);break;case"/api/setup":as(n);break;case"/api/setup/create":ls(o,n);break;case"/api/setup/fetch":cs(o,n);break;case"/api/setup/open":ds(o,n);break;case"/api/setup/resume":us(o,n);break;case"/api/setup/apikey":ms(o,n);break;case"/api/settings/status":e==="GET"?hs(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/engine":e==="POST"?ys(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/apikey":e==="POST"?bs(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/install":e==="POST"?vs(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":e==="POST"?Ss(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":e==="POST"?ws(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":e==="POST"?xs(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":e==="POST"?Cs(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":e==="POST"?As(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes":ks(e,o,n);break;case"/api/themes/switch":e==="POST"?$s(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":e==="POST"?Es(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/rename":e==="POST"?Ts(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/history":e==="GET"?Us(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/rollback":e==="POST"?Ks(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/dashboard":e==="GET"?Ns(n):d(n,405,{error:"Method not allowed"});break;case"/api/templates":Rs(e,o,n);break;case"/api/templates/activate":e==="POST"?Os(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/templates/rename":e==="POST"?Ps(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/module-library":e==="GET"?js(n):d(n,405,{error:"Method not allowed"});break;case"/api/brand-assets":Js(e,o,n);break;case"/api/download-zip":e==="GET"?_s(n):d(n,405,{error:"Method not allowed"});break;default:t.startsWith("/api/settings/job/")&&e==="GET"?Is(t,n):t.match(/^\/api\/templates\/[^/]+\/add-module$/)&&e==="POST"?Ms(t,o,n):d(n,404,{error:"Not found"})}}function Fr(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;Fe("user",s),P(),ns(i=>{e.send(JSON.stringify({type:"parse_warning",message:i}))});try{await wn(s,r=>{e.send(JSON.stringify({type:"stream",content:r}))},r=>{e.send(JSON.stringify({type:"stream_status",content:r}))});let i=I();if(i){qe();let r=Je(),a=null;if(r){let l=r.moduleOrder.map(c=>`modules/${c}.module`);r.templateFile&&l.push(r.templateFile),r.sharedCss&&l.push(`css/${i.themeName}-theme.css`),r.sharedJs&&l.push(`js/${i.themeName}-animations.js`),a=xo(i.themePath,r.id,s,l)}else a=nn(i.themePath,s);a&&e.send(JSON.stringify({type:"version_created",hash:a}))}e.send(JSON.stringify({type:"generation_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:ce().map(r=>r.moduleName)}))}catch(i){e.send(JSON.stringify({type:"error",message:i instanceof Error?i.message:String(i)}))}break}case"start_upload":{let s=I();if(!s){e.send(JSON.stringify({type:"error",message:"No active session"}));break}try{qe();let i=_t(s.themePath);i.length>0&&e.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i}));let r=Gt(`hs cms upload "${s.themePath}" "${s.themeName}"`,"Uploading to HubSpot",{cwd:In(s.themePath,".."),timeout:18e4});e.send(JSON.stringify({type:"upload_started",jobId:r}));let a=c=>{e.send(JSON.stringify({type:"upload_output",chunk:c}))};ss(r,a);let l=setInterval(()=>{let c=Ht(r);if(!(!c||c.status==="running"))if(clearInterval(l),is(r,a),c.status==="completed"){let u=ve(),p=u.portalId?yt(u.portalId):"na1";e.send(JSON.stringify({type:"upload_complete",output:c.output,portalId:u.portalId||"",dataCenter:p,themeName:s.themeName}))}else{let u=Nt(c.output);e.send(JSON.stringify({type:"upload_failed",output:c.output,errors:u,exitCode:c.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.
716
+ 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,r)}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Fi(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}if(!ye()){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):ss(o.themePath,50);d(t,200,{available:!0,commits:i,filtered:!!s})}function Ji(e,t){R(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(Le("assistant",`Rolled back to version ${s.slice(0,7)}.`),i){let r=n.templates.find(c=>c.id===i);if(!r){d(t,404,{error:"Template not found"});return}let a=r.moduleOrder.map(c=>`modules/${c}.module`);r.templateFile&&a.push(r.templateFile);let l=as(n.themePath,i,s,a);if(!l.success){d(t,500,{error:l.error||"Rollback failed"});return}ws()}else{let r=rs(n.themePath,s);if(!r.success){d(t,500,{error:r.error||"Rollback failed"});return}vs()}F(),d(t,200,{ok:!0,modules:me().map(r=>r.moduleName)})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}var Li={".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 Gi(e){let{port:t,uiDir:o}=e,n=Xa((i,r)=>el(i,r,o)),s=new Za({server:n});return s.on("connection",i=>nl(i)),new Promise((i,r)=>{n.on("error",a=>{a.code==="EADDRINUSE"?n.listen(t+1,()=>{i({port:t+1,close:()=>{n.close(),s.close()}})}):r(a)}),n.listen(t,()=>{i({port:t,close:()=>{n.close(),s.close()}})})})}function el(e,t,o){let n=new URL(e.url||"/",`http://${e.headers.host}`),s=e.method||"GET";if(n.pathname.startsWith("/api/")){tl(s,n.pathname,e,t);return}if(n.pathname==="/preview"){let i=Rs();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")||"",r=Ps(i);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(r||"<!-- module not found -->");return}if(n.pathname.startsWith("/theme-assets/")){ol(n.pathname.slice(14),t);return}sl(n.pathname,o,e,t)}function tl(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":_i(e,n);break;case"/api/modules":Ri(e,o,n);break;case"/api/modules/reorder":Pi(o,n);break;case"/api/upload":Oi(n);break;case"/api/upload-files":e==="POST"?Us(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/field":Mi(o,n);break;case"/api/import":ji(o,n);break;case"/api/setup":Xs(n);break;case"/api/setup/create":Qs(o,n);break;case"/api/setup/fetch":Zs(o,n);break;case"/api/setup/open":ei(o,n);break;case"/api/setup/resume":ti(o,n);break;case"/api/setup/apikey":ni(o,n);break;case"/api/setup/remote-themes":e==="GET"?oi(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/status":e==="GET"?ai(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/engine":e==="POST"?li(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/apikey":e==="POST"?ci(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/install":e==="POST"?di(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":e==="POST"?ui(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":e==="POST"?mi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":e==="POST"?pi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":e==="POST"?fi(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":e==="POST"?gi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-mode":e==="POST"?hi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-toggle":e==="POST"?yi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes":Si(e,o,n);break;case"/api/themes/switch":e==="POST"?vi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":e==="POST"?wi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/rename":e==="POST"?xi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/history":e==="GET"?Fi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/rollback":e==="POST"?Ji(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/dashboard":e==="GET"?Ci(n):d(n,405,{error:"Method not allowed"});break;case"/api/templates":Ii(e,o,n);break;case"/api/templates/activate":e==="POST"?$i(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/templates/rename":e==="POST"?Ti(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/module-library":e==="GET"?ki(n):d(n,405,{error:"Method not allowed"});break;case"/api/brand-assets":Ni(e,o,n);break;case"/api/download-zip":e==="GET"?Ai(n):d(n,405,{error:"Method not allowed"});break;default:t.startsWith("/api/settings/job/")&&e==="GET"?bi(t,n):t.match(/^\/api\/templates\/[^/]+\/add-module$/)&&e==="POST"?Ei(t,o,n):d(n,404,{error:"Not found"})}}function nl(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;Le("user",s),F(),Ks(r=>{e.send(JSON.stringify({type:"parse_warning",message:r}))});let i=Array.isArray(n.fileIds)?n.fileIds:void 0;try{await Yn(s,a=>{e.send(JSON.stringify({type:"stream",content:a}))},a=>{e.send(JSON.stringify({type:"stream_status",content:a}))},i);let r=$();if(r){tt();let a=De(),l=null;if(a){let c=a.moduleOrder.map(u=>`modules/${u}.module`);a.templateFile&&c.push(a.templateFile),a.sharedCss&&c.push(`css/${r.themeName}-theme.css`),a.sharedJs&&c.push(`js/${r.themeName}-animations.js`),l=os(r.themePath,a.id,s,c)}else l=Tn(r.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:me().map(a=>a.moduleName)}))}catch(r){e.send(JSON.stringify({type:"error",message:r instanceof Error?r.message:String(r)}))}break}case"start_upload":{let s=$();if(!s){e.send(JSON.stringify({type:"error",message:"No active session"}));break}try{tt();let i=Xt(s.themePath);if(i.length>0&&e.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i})),(N().hubspotUploadMode||"api")==="api"){let l=fe();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 Qt(l,s.themePath,s.themeName,{onFileStart:u=>{e.send(JSON.stringify({type:"upload_output",chunk:`Uploading ${u}
717
+ `}))},onFileComplete:u=>{e.send(JSON.stringify({type:"upload_output",chunk:` \u2713 ${u}
718
+ `}))},onFileError:(u,p)=>{e.send(JSON.stringify({type:"upload_output",chunk:` \u2717 ${u}: ${p.message}
719
+ `}))},onProgress:(u,p)=>{e.send(JSON.stringify({type:"upload_progress",completed:u,total:p}))}});if(c.success){let u=Fe();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=zt(c.errors);e.send(JSON.stringify({type:"upload_failed",output:c.errors.map(p=>`${p.file}: ${p.message}`).join(`
720
+ `),errors:u}))}}else{let l=an(`hs cms upload "${s.themePath}" "${s.themeName}"`,"Uploading to HubSpot",{cwd:dn(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}))};Ys(l,c);let u=setInterval(()=>{let p=rn(l);if(!(!p||p.status==="running"))if(clearInterval(u),Vs(l,c),p.status==="completed"){let f=Ce(),g=f.portalId?ut(f.portalId):"na1";e.send(JSON.stringify({type:"upload_complete",output:p.output,portalId:f.portalId||"",dataCenter:g,themeName:s.themeName}))}else{let f=qt(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.
660
721
 
661
722
  IMPORTANT: Be verbose in your response. For each error:
662
723
  1. State exactly which file has the problem and what the error is
@@ -669,9 +730,9 @@ CRITICAL: After fixing the reported errors, scan ALL other module files in the t
669
730
  After fixing all errors, summarize the changes you made.
670
731
 
671
732
  Upload log:
672
- ${s}`;Fe("user",i),P(),e.send(JSON.stringify({type:"upload_fix_started"}));try{await wn(i,a=>{e.send(JSON.stringify({type:"stream",content:a})),e.send(JSON.stringify({type:"upload_fix_stream",content:a}))});let r=I();if(r){qe();let a=nn(r.themePath,"AI fix: upload errors");a&&e.send(JSON.stringify({type:"version_created",hash:a}))}e.send(JSON.stringify({type:"upload_fix_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:ce().map(a=>a.moduleName)}))}catch(r){e.send(JSON.stringify({type:"upload_failed",output:r instanceof Error?r.message:String(r),errors:[{file:"AI fix",message:r instanceof Error?r.message:String(r),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=I();if(t){let o=j(),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=Je();e.send(JSON.stringify({type:"init",sessionId:t.id,themeName:t.themeName,modules:ce().map(i=>i.moduleName),messageCount:t.messages.length,messages:t.messages,gitAvailable:me(),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"}))}var Vs=new Map;function Lr(e,t,o,n){let i=In(t,e==="/"?"/index.html":e);if(!Ys(i)){let c=In(t,"index.html");if(Ys(c)){let u=Bs(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 r=Or(i),a=Mr[r]||"application/octet-stream",l=r===".html";try{let c=Vs.get(i);if(!c){let p=Bs(i),f='"'+Pr("md5").update(p).digest("hex").slice(0,16)+'"';c={buffer:p,etag:f,contentType:a},Vs.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 Gr=4200;async function qs(){let e=Kt.hex("#e8613a"),t=Kt.dim;console.log(""),console.log(e(" v vibeSpot")),console.log(t(` Starting...
673
- `));let o=Wr();o||(console.error(Kt.red(" Could not find UI assets. Is the package installed correctly?")),process.exit(1));try{let{port:n,close:s}=await zs({port:Gr,uiDir:o}),i=`http://localhost:${n}`;console.log(e(` v ${i}`)),console.log(t(` Press Ctrl+C to stop
674
- `));try{process.platform==="darwin"?kn(`open "${i}"`,{stdio:"ignore"}):process.platform==="win32"?kn(`cmd /c start "" "${i}"`,{stdio:"ignore"}):kn(`xdg-open "${i}"`,{stdio:"ignore"})}catch{}await new Promise(r=>{process.on("SIGINT",()=>{console.log(t(`
675
- Saving session...`)),P(),s(),console.log(t(` Goodbye!
676
- `)),r()})})}catch(n){console.error(Kt.red(` Failed to start: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}function Wr(){let e=[Ut(import.meta.dirname,"../../ui"),Ut(import.meta.dirname,"../ui"),Ut(process.cwd(),"ui")];for(let t of e)if(Hr(Ut(t,"index.html")))return t;return null}function Qs(){let e=new Ur;return e.name("vibespot").description("AI-powered HubSpot CMS landing page builder").version("0.7.1").action(qs),e.command("wizard").description("Classic CLI wizard \u2014 step-by-step conversion flow").action(ho),e.command("init").description("Check and install required tools").action(yo),e.command("convert").description("Convert a React project to HubSpot modules").action(bo),e.command("upload").description("Upload theme to HubSpot").action(vo),e.command("doctor").description("Diagnose environment issues").action(So),e}var Kr=Qs();Kr.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
733
+ ${s}`;Le("user",i),F(),e.send(JSON.stringify({type:"upload_fix_started"}));try{await Yn(i,a=>{e.send(JSON.stringify({type:"stream",content:a})),e.send(JSON.stringify({type:"upload_fix_stream",content:a}))});let r=$();if(r){tt();let a=Tn(r.themePath,"AI fix: upload errors");a&&e.send(JSON.stringify({type:"version_created",hash:a}))}e.send(JSON.stringify({type:"upload_fix_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:me().map(a=>a.moduleName)}))}catch(r){e.send(JSON.stringify({type:"upload_failed",output:r instanceof Error?r.message:String(r),errors:[{file:"AI fix",message:r instanceof Error?r.message:String(r),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=De();e.send(JSON.stringify({type:"init",sessionId:t.id,themeName:t.themeName,modules:me().map(i=>i.moduleName),messageCount:t.messages.length,messages:t.messages,gitAvailable:ye(),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 ol(e,t){let o=$();if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("No session");return}let n=dn(o.themePath,"assets",e);if(!Xn(n)){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Asset not found");return}let s=Hi(n),i=Li[s]||"application/octet-stream",r=qn(n);t.writeHead(200,{"Content-Type":i,"Cache-Control":"no-cache"}),t.end(r)}var Di=new Map;function sl(e,t,o,n){let i=dn(t,e==="/"?"/index.html":e);if(!Xn(i)){let c=dn(t,"index.html");if(Xn(c)){let u=qn(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 r=Hi(i),a=Li[r]||"application/octet-stream",l=r===".html";try{let c=Di.get(i);if(!c){let p=qn(i),f='"'+Qa("md5").update(p).digest("hex").slice(0,16)+'"';c={buffer:p,etag:f,contentType:a},Di.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 rl=4200;async function Ui(){let e=mn.hex("#e8613a"),t=mn.dim;console.log(""),console.log(e(" v vibeSpot")),console.log(t(` Starting...
734
+ `));let o=al();o||(console.error(mn.red(" Could not find UI assets. Is the package installed correctly?")),process.exit(1));try{let{port:n,close:s}=await Gi({port:rl,uiDir:o}),i=`http://localhost:${n}`;console.log(e(` v ${i}`)),console.log(t(` Press Ctrl+C to stop
735
+ `));try{process.platform==="darwin"?Qn(`open "${i}"`,{stdio:"ignore"}):process.platform==="win32"?Qn(`cmd /c start "" "${i}"`,{stdio:"ignore"}):Qn(`xdg-open "${i}"`,{stdio:"ignore"})}catch{}await new Promise(r=>{process.on("SIGINT",()=>{console.log(t(`
736
+ Saving session...`)),F(),s(),console.log(t(` Goodbye!
737
+ `)),r()})})}catch(n){console.error(mn.red(` Failed to start: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}function al(){let e=[un(import.meta.dirname,"../../ui"),un(import.meta.dirname,"../ui"),un(process.cwd(),"ui")];for(let t of e)if(il(un(t,"index.html")))return t;return null}function Wi(){let e=new ll;return e.name("vibespot").description("AI-powered HubSpot CMS landing page builder").version("0.7.1").action(Ui),e.command("wizard").description("Classic CLI wizard \u2014 step-by-step conversion flow").action(Xo),e.command("init").description("Check and install required tools").action(Qo),e.command("convert").description("Convert a React project to HubSpot modules").action(Zo),e.command("upload").description("Upload theme to HubSpot").action(es),e.command("doctor").description("Diagnose environment issues").action(ts),e}var cl=Wi();cl.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
677
738
  //# sourceMappingURL=index.js.map