vibespot 0.9.1 → 0.9.3
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/assets/extraction-prompt.md +49 -0
- package/assets/hubspot-rules.md +18 -0
- package/dist/index.js +166 -128
- package/dist/index.js.map +1 -1
- package/package.json +8 -1
- package/ui/code-editor.js +393 -0
- package/ui/dashboard.js +152 -0
- package/ui/dialog.js +136 -0
- package/ui/index.html +38 -1
- package/ui/setup.js +37 -23
- package/ui/styles.css +276 -4
- package/ui/vendor/codemirror-bundle.global.js +24 -0
- package/ui/vendor/marked.umd.js +74 -0
package/dist/index.js
CHANGED
|
@@ -1,31 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
var yr=Object.defineProperty;var Ze=(e,t)=>()=>(e&&(t=e(e=0)),t);var So=(e,t)=>{for(var o in t)yr(e,o,{get:t[o],enumerable:!0})};import Bl from"path";import{fileURLToPath as Vl}from"url";var h=Ze(()=>{"use strict"});import{readFileSync as wo,writeFileSync as br,mkdirSync as xo,existsSync as Rn}from"fs";import{dirname as Sr,join as nt}from"path";function v(e){return wo(e,"utf-8")}function M(e,t){xo(Sr(e),{recursive:!0}),br(e,t,"utf-8")}function b(e){return Rn(e)}function ge(e){xo(e,{recursive:!0})}function Ft(e){let t=[nt(import.meta.dirname,"../../assets",e),nt(import.meta.dirname,"../assets",e),nt(process.cwd(),"assets",e)];for(let o of t)if(Rn(o))return o;throw new Error(`Asset not found: ${e}`)}function ot(){if(tt)return tt;let e=[nt(import.meta.dirname,"../../package.json"),nt(import.meta.dirname,"../package.json"),nt(process.cwd(),"package.json")];for(let t of e)if(Rn(t))try{let o=JSON.parse(wo(t,"utf-8"));if(o.name==="vibespot"&&o.version)return tt=o.version,tt}catch{}return tt="dev",tt}var tt,Q=Ze(()=>{"use strict";h();tt=""});import{join as Io}from"path";import{homedir as vr}from"os";function N(){if(!b(Pn))return{};try{let e=JSON.parse(v(Pn));return e.aiEngine==="api"&&(e.aiEngine="anthropic-api"),e}catch{return{}}}function he(e,t){let o=t||N();switch(e){case"anthropic-api":case"api":return o.anthropicApiKey||process.env.ANTHROPIC_API_KEY;case"openai-api":return o.openaiApiKey||process.env.OPENAI_API_KEY;case"gemini-api":return o.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY;default:return}}function On(e){return e.length<=12?"***":e.slice(0,7)+"..."+e.slice(-4)}function z(e){let o={...N(),...e};M(Pn,JSON.stringify(o,null,2))}function Ke(){let e=N();if(!e.hubspotAccounts?.length)return null;let t=e.activeHubSpotAccount;if(t){let o=e.hubspotAccounts.find(n=>n.portalId===t);if(o)return o}return e.hubspotAccounts[0]||null}function Ht(e,t,o,n){let i=N().hubspotAccounts||[],a=i.findIndex(l=>l.portalId===t),r={portalId:t,portalName:o,personalAccessKey:e,dataCenter:n,addedAt:new Date().toISOString()};a>=0?i[a]=r:i.push(r),z({hubspotAccounts:i,activeHubSpotAccount:t})}function To(e){let t=N(),o=(t.hubspotAccounts||[]).filter(s=>s.portalId!==e),n={hubspotAccounts:o};t.activeHubSpotAccount===e&&(n.activeHubSpotAccount=o[0]?.portalId||void 0),z(n)}function $o(e){z({activeHubSpotAccount:e})}function ue(){return Ke()?.personalAccessKey||null}function Lt(e){return N().enabledCLITools?.includes(e)??!1}function ko(e,t){let o=N(),n=new Set(o.enabledCLITools||[]);t?n.add(e):n.delete(e),z({enabledCLITools:[...n]})}var wr,Pn,Z=Ze(()=>{"use strict";h();Q();wr=Io(vr(),".vibespot"),Pn=Io(wr,"config.json")});import{readFileSync as Ar}from"fs";import{basename as Ir}from"path";async function Po(e){let t=Ro.get(e);if(t&&t.expiresAt-Date.now()>kr)return t;let o=await fetch(`${Me}/localdevauth/v1/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({encodedOAuthRefreshToken:e})});if(!o.ok){let i=await o.text().catch(()=>"");throw new Error(o.status===401||o.status===403?"Invalid or expired Personal Access Key":`Token exchange failed (${o.status}): ${i.slice(0,200)}`)}let n=await o.json(),s={accessToken:n.oauthAccessToken,expiresAt:n.expiresAtMillis,hubId:n.hubId,hubName:n.hubName||""};return Ro.set(e,s),s}async function st(e){let{accessToken:t}=await Po(e);return{Authorization:`Bearer ${t}`}}function Yt(e){return e.replace(/^\/+/,"").split("/").filter(Boolean).map(encodeURIComponent).join("/")}function Er(e){return e.startsWith("pat-eu1-")?"eu1":e.startsWith("pat-na1-")?"na1":e.startsWith("CiRldTE")?"eu1":"na1"}function Nr(e){return new Promise(t=>setTimeout(t,e))}async function At(e,t){let o=`HTTP ${e.status}`,n,s;try{let i=await e.json();if(i.message&&typeof i.message=="string"&&(o=i.message),i.category&&typeof i.category=="string"&&(n=i.category),i.errors&&Array.isArray(i.errors)&&i.errors.length>0){let a=i.errors[0];s=a.message||JSON.stringify(a)}}catch{try{let i=await e.text();i&&(o=i.slice(0,500))}catch{}}return{status:e.status,message:t?`${o} (${t})`:o,category:n,detail:s}}async function It(e,t,o=Tr){for(let n=0;n<=o;n++){let s=await fetch(e,t);if(s.status===429||s.status>=500&&n<o){let i=$r*Math.pow(2,n);await Nr(i);continue}return s}return fetch(e,t)}async function Vt(e){let t=await Po(e),o=`${Me}/account-info/v3/details`,n=await It(o,{headers:await st(e)});if(!n.ok){let r=await At(n);throw new Error(`Failed to get account info: ${r.message}`)}let s=await n.json(),i=String(s.portalId||t.hubId||""),a=t.hubName||s.uiDomain||i;return{portalId:i,portalName:a,dataCenter:Er(e)}}async function Oo(e,t,o){let n=Ar(o),s=Ir(o),i=new FormData,a=new Blob([n]);i.append("file",a,s);let r=`${Me}/cms/v3/source-code/published/content/${Yt(t)}`,l=await It(r,{method:"PUT",headers:await st(e),body:i});if(!l.ok){let c=await At(l,t);return{success:!1,path:t,error:c}}return{success:!0,path:t}}async function Jn(e,t){let o=`${Me}/cms/v3/source-code/published/content/${Yt(t)}`,n=await It(o,{method:"DELETE",headers:await st(e)});if(!n.ok&&n.status!==404){let s=await At(n,t);throw new Error(`Failed to delete ${t}: ${s.message}`)}}async function Mo(e,t){let o=`${Me}/cms/v3/source-code/published/content/${Yt(t)}`,n=await It(o,{method:"GET",headers:await st(e)});if(!n.ok){let i=await At(n,t);throw new Error(`Failed to download ${t}: ${i.message}`)}let s=await n.arrayBuffer();return Buffer.from(s)}async function zt(e,t){let o=`${Me}/cms/v3/source-code/published/metadata/${Yt(t)}`,n=await It(o,{method:"GET",headers:await st(e)});if(n.status===404)return null;if(!n.ok){let s=await At(n,t);throw new Error(`Failed to get metadata for ${t}: ${s.message}`)}return await n.json()}async function jo(e){let t=await st(e),o=[`${Me}/cms/v3/source-code/published/metadata`,`${Me}/cms/v3/source-code/published/metadata/`,`${Me}/designmanager/v1/portals/content/listing`];for(let n of o)try{let s=await fetch(n,{method:"GET",headers:t});if(s.ok){let i=await s.json(),a=i.children||i.objects||(Array.isArray(i)?i:null);if(a&&a.length>0)return a.filter(r=>r.folder)}}catch{}return[]}var Me,Tr,$r,kr,Ro,Ye=Ze(()=>{"use strict";h();Me="https://api.hubapi.com",Tr=3,$r=1e3,kr=300*1e3,Ro=new Map});var Go={};So(Go,{fetchTheme:()=>Tt});import{mkdirSync as Lo,writeFileSync as Or}from"fs";import{join as Mr,dirname as jr}from"path";async function Gn(e,t){let o=await zt(e,t);if(!o)return[];if(!o.folder)return[o.path||t];let n=[],s=o.children||[];for(let i of s){let a=typeof i=="string"?i:i.name;if(!a)continue;let r=`${t}/${a}`;if(typeof i=="string")n.push(...await Gn(e,r));else{let l=i;l.folder?n.push(...await Gn(e,l.path||r)):n.push(l.path||r)}}return n}async function Dr(e,t,o){let n=0;async function s(){for(;n<e.length;){let a=n++;await o(e[a])}}let i=Array.from({length:Math.min(t,e.length)},()=>s());await Promise.all(i)}async function Tt(e,t,o,n={}){let s=n.concurrency??5,i=await Gn(e,t);if(i.length===0)throw new Error(`Theme "${t}" not found on HubSpot or is empty`);Lo(o,{recursive:!0}),await Dr(i,s,async a=>{let r=a.startsWith(t+"/")?a.slice(t.length+1):a,l=Mr(o,r);Lo(jr(l),{recursive:!0});let c=await Mo(e,a);Or(l,c),n.onFile?.(r)})}var en=Ze(()=>{"use strict";h();Ye()});var po={};So(po,{collectThemeFiles:()=>Wi,extractDesignContext:()=>Il});import{existsSync as An,readdirSync as In,readFileSync as vl}from"fs";import{join as Re}from"path";import{spawn as wl}from"child_process";async function xl(){return uo||(uo=(await import("@anthropic-ai/sdk")).default),uo}function Dt(e){try{return vl(e,"utf-8")}catch{return""}}function Wi(e){let t=[],o=0;function n(r,l){if(!l.trim())return!0;let c=`
|
|
2
|
+
### ${r}
|
|
3
|
+
\`\`\`
|
|
4
|
+
${l}
|
|
5
|
+
\`\`\`
|
|
6
|
+
`;return o+c.length>Cl?!1:(t.push(c),o+=c.length,!0)}let s=Dt(Re(e,"theme.json"));s&&n("theme.json",s);let i=Re(e,"css");if(An(i)){for(let r of In(i).filter(l=>l.endsWith(".css")))if(!n(`css/${r}`,Dt(Re(i,r))))break}let a=Re(e,"modules");if(An(a))for(let r of In(a).filter(l=>l.endsWith(".module"))){let l=Re(a,r),c=Dt(Re(l,"module.css"));if(c&&!n(`modules/${r}/module.css`,c))break}if(An(a))for(let r of In(a).filter(l=>l.endsWith(".module"))){let l=Re(a,r),c=Dt(Re(l,"module.html"));if(c&&!n(`modules/${r}/module.html`,c))break}if(An(a))for(let r of In(a).filter(l=>l.endsWith(".module"))){let l=Re(a,r),c=Dt(Re(l,"fields.json"));if(c&&!n(`modules/${r}/fields.json`,c))break}return t.join("")}function Al(){if(!Tn)try{Tn=v(Ft("extraction-prompt.md"))}catch{Tn=""}return Tn}function mo(e,t,o){return new Promise((n,s)=>{let i={...process.env};delete i.CLAUDECODE;let a=wl(e,t,{stdio:["pipe","pipe","pipe"],env:i,shell:!0}),r="",l="";a.stdout.on("data",c=>{r+=c.toString()}),a.stderr.on("data",c=>{l+=c.toString()}),a.on("error",c=>s(new Error(`${e} failed to start: ${c.message}`))),a.on("close",c=>{c===0||r.trim()?n(r.trim()):s(new Error(`${e} exited with code ${c}: ${l.trim()}`))}),a.stdin.write(o),a.stdin.end()})}async function Il(e,t){t?.({status:"Collecting theme files..."});let o=Wi(e);if(!o.trim())throw new Error("No CSS, HTML, or fields.json files found in theme.");let n=Al();if(!n)throw new Error("Extraction prompt not found (assets/extraction-prompt.md).");let s=`Analyze this HubSpot CMS theme and extract the design system:
|
|
7
|
+
${o}`;t?.({status:"Analyzing design patterns..."});let i=N(),a=i.aiEngine||"anthropic-api",r="";switch(a){case"anthropic-api":case"api":{let l=he("anthropic-api");if(!l)throw new Error("Anthropic API key not configured. Open Settings to add one.");let c=await xl();r=(await new c({apiKey:l}).messages.create({model:i.anthropicApiModel||"claude-sonnet-4-6",max_tokens:8e3,system:n,messages:[{role:"user",content:s}]})).content.filter(f=>f.type==="text").map(f=>f.text).join("");break}case"openai-api":{let l=he("openai-api");if(!l)throw new Error("OpenAI API key not configured. Open Settings to add one.");let c=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`},body:JSON.stringify({model:i.openaiApiModel||"gpt-4o",max_tokens:8e3,messages:[{role:"system",content:n},{role:"user",content:s}]})});if(!c.ok)throw new Error(`OpenAI API error: ${c.status} ${await c.text()}`);r=(await c.json()).choices?.[0]?.message?.content||"";break}case"gemini-api":{let l=he("gemini-api");if(!l)throw new Error("Gemini API key not configured. Open Settings to add one.");let c=i.geminiApiModel||"gemini-2.5-flash",u=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${c}:generateContent?key=${l}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({system_instruction:{parts:[{text:n}]},contents:[{role:"user",parts:[{text:s}]}],generationConfig:{maxOutputTokens:8e3}})});if(!u.ok)throw new Error(`Gemini API error: ${u.status} ${await u.text()}`);r=(await u.json()).candidates?.[0]?.content?.parts?.map(f=>f.text).join("")||"";break}case"claude-code":{let l=`${n}
|
|
8
|
+
|
|
9
|
+
## User Request
|
|
10
|
+
${s}`,c=["--print"];i.claudeCodeModel&&c.push("--model",i.claudeCodeModel),r=await mo("claude",c,l);break}case"gemini-cli":{let l=`${n}
|
|
11
|
+
|
|
12
|
+
## User Request
|
|
13
|
+
${s}`;r=await mo("gemini",[],l);break}case"codex-cli":{let l=`${n}
|
|
14
|
+
|
|
15
|
+
## User Request
|
|
16
|
+
${s}`;r=await mo("codex",[],l);break}default:throw new Error(`Unknown AI engine: ${a}. Open Settings to configure one.`)}if(!r.trim())throw new Error("AI returned empty response.");return t?.({status:"Design extraction complete."}),r}var uo,Cl,Tn,fo=Ze(()=>{"use strict";h();Q();Z();uo=null;Cl=8e4;Tn=""});h();h();import{Command as Ll}from"commander";h();h();h();import et from"chalk";var Ie={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},vo=!!process.env.NO_COLOR;function Oe(e){return vo?et:et.hex(e)}var C={accent:Oe(Ie.accent),accentBright:Oe(Ie.accentBright),success:Oe(Ie.success),info:Oe(Ie.info),warn:Oe(Ie.warn),error:Oe(Ie.error),muted:Oe(Ie.muted),vibes:Oe(Ie.vibes),heading:vo?et.bold:et.bold.hex(Ie.accent),command:Oe(Ie.accentBright),dim:et.dim,bold:et.bold};Q();function Te(){let e=C.vibes,t=C.accent,o=C.muted,n=[`${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584\u2584")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${t("\u2584\u2584\u2584\u2584\u2584 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584 \u2580\u2580\u2588\u2588\u2580\u2580")}`,`${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 ")}${e(" \u224B\u224B\u224B\u224B ")}${t("\u2580\u2580\u2580\u2584 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${e(" \u2588\u2584\u2584\u2588\u2580 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${t(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${e(" \u2580\u2580\u2580 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2580\u2580\u2580\u2580\u2580")}${e(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${t("\u2580\u2580\u2580\u2580 \u2588\u2588 \u2580\u2580\u2580\u2580 \u2588\u2588 ")}`];console.log();for(let s of n)console.log(` ${s}`);console.log(),console.log(` ${o("AI-powered HubSpot Landing Pages")} ${C.dim(`v${ot()}`)}`),console.log()}h();h();import{join as Gt}from"path";import{homedir as Ut}from"os";import{readFileSync as Eo,existsSync as Wt,readdirSync as xr}from"fs";h();import{execSync as Co}from"child_process";function A(e,t={}){try{return{stdout:Co(e,{encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:12e4,...t}).trim(),stderr:"",success:!0}}catch(o){let n=o,s=(n.stdout??"").toString().trim(),i=(n.stderr??"").toString().trim();return{stdout:s,stderr:i,success:!1}}}function Ao(e,t={}){try{return Co(e,{stdio:"inherit",timeout:3e5,...t}),!0}catch{return!1}}Z();var Be=process.platform==="win32"?"where":"which";function bt(){let e=A("node --version");return{name:"Node.js",found:e.success,version:e.stdout.replace(/^v/,""),path:A(`${Be} node`).stdout}}function St(){let e=A("git --version");return{name:"Git",found:e.success,version:e.stdout.replace("git version ",""),path:A(`${Be} git`).stdout}}function $e(){let e=A("hs --version");return{name:"HubSpot CLI",found:e.success,version:e.stdout,path:A(`${Be} hs`).stdout}}function vt(){let e=A("claude --version");if(!e.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=Gt(Ut(),".claude"),o=!1,n="Not signed in \u2014 run `claude` to authenticate";try{if(Wt(t)){let s=xr(t);(s.some(a=>a.includes("credentials")||a.includes("auth")||a.includes("token")||a===".credentials.json")||s.length>2)&&(o=!0,n="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:e.stdout,path:A(`${Be} claude`).stdout,authenticated:o,authDetail:n}}function wt(e){try{let t=Gt(Ut(),".hscli","config.yml");if(!Wt(t))return"na1";let o=Eo(t,"utf-8"),n=o.indexOf(`accountId: ${e}`);if(n===-1)return"na1";let s=o.indexOf("personalAccessKey:",n);if(s===-1)return"na1";let a=o.slice(s,s+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!a)return"na1";if(a[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function ke(){let e=A("hs accounts list");if(!e.success||!e.stdout)return{authenticated:!1,portalName:"",portalId:"",accounts:[]};let t=[],o="",n="",s=e.stdout.match(/Account:\s*(.+?)\s*\((\d+)\)/);s&&(o=s[1].trim(),n=s[2].trim());let i=e.stdout.split(`
|
|
17
|
+
`);for(let a of i){let r=a.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(r&&!/Account ID/i.test(a)&&!/^-+$/.test(a.trim())&&!/^Name\s/i.test(a.trim())){let l=r[1].trim(),c=r[2].trim(),u=r[3]?.trim()||"unknown";t.push({name:l,portalId:c,authType:u,isDefault:c===n})}}return s?{authenticated:!0,portalName:o,portalId:n,accounts:t}:t.length>0?{authenticated:!0,portalName:t[0].name,portalId:t[0].portalId,accounts:t}:{authenticated:e.stdout.length>0,portalName:"",portalId:"",accounts:[]}}function xt(){let e=A("gemini --version");if(!e.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=Gt(Ut(),".config","gcloud","application_default_credentials.json"),o=Wt(t),n=!!(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||process.env.GOOGLE_AI_API_KEY),s=o||n;return{name:"Gemini CLI",found:!0,version:e.stdout,path:A(`${Be} gemini`).stdout,authenticated:s,authDetail:s?"Authenticated":"Run `gemini` to sign in with Google"}}function Ct(){let e=A("codex --version");if(!e.success)return{name:"OpenAI Codex CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let t=!!process.env.OPENAI_API_KEY,o=!1;try{let i=Gt(Ut(),".codex","auth.json");Wt(i)&&(o=Eo(i,"utf-8").length>10)}catch{}let n=t||o,s=o?"Authenticated (OAuth)":t?"Authenticated (API key)":"Not authenticated";return{name:"OpenAI Codex CLI",found:!0,version:e.stdout,path:A(`${Be} codex`).stdout,authenticated:n,authDetail:s}}function jn(){let e=A("gh --version");return{name:"GitHub CLI",found:e.success,version:e.stdout.split(`
|
|
18
|
+
`)[0]?.replace("gh version ","").split(" ")[0]||"",path:A(`${Be} gh`).stdout}}function Dn(){let e=A("gh auth status 2>&1");if(!e.success&&!e.stdout)return{authenticated:!1,username:""};let t=e.stdout||e.stderr||"",o=t.match(/Logged in to github\.com.*account\s+(\S+)/);if(o)return{authenticated:!0,username:o[1]};let n=t.match(/account\s+(\S+)/);return n&&t.includes("Logged in")?{authenticated:!0,username:n[1]}:{authenticated:t.includes("Logged in"),username:""}}function No(){return!!process.env.ANTHROPIC_API_KEY}function Kt(e){return parseInt(e.split(".")[0],10)>=18}function _o(e){let t=parseInt(e.split(".")[0],10);return!isNaN(t)&&t>=8}function Cr(){let e=N(),t=e.hubspotUploadMode||"api",o=e.hubspotAccounts||[],n=o.map(i=>({name:i.portalName,portalId:i.portalId,authType:"personalaccesskey",isDefault:i.portalId===(e.activeHubSpotAccount||o[0]?.portalId)})),s=Ke();return{authenticated:!!s,portalName:s?.portalName||"",portalId:s?.portalId||"",dataCenter:s?s.dataCenter:"na1",accounts:n,uploadMode:t}}var Mn={name:"",found:!1,version:"",path:"",authenticated:!1,authDetail:"Disabled"};function Bt(){let e=N(),t=bt(),o=St(),n=e.hubspotUploadMode||"api",s;if(n==="cli"){let w=$e(),k=w.found?ke():{authenticated:!1,portalName:"",portalId:"",accounts:[]},E=k.portalId?wt(k.portalId):"na1";s={...w,...k,dataCenter:E,uploadMode:"cli"}}else s={name:"HubSpot API",found:!0,version:"v3",path:"",...Cr()};let i=jn(),a=i.found?Dn():{authenticated:!1,username:""},r=e.enabledCLITools||[],l=Lt("claude-code")?vt():{...Mn,name:"Claude Code"},c=Lt("gemini-cli")?xt():{...Mn,name:"Gemini CLI"},u=Lt("codex-cli")?Ct():{...Mn,name:"OpenAI Codex CLI"};function p(w,...k){if(w)return{configured:!0,masked:On(w),source:"config"};for(let E of k)if(process.env[E])return{configured:!0,masked:On(process.env[E]),source:"env"};return{configured:!1,masked:"",source:null}}let f=p(e.anthropicApiKey,"ANTHROPIC_API_KEY"),g=p(e.openaiApiKey,"OPENAI_API_KEY"),y=p(e.geminiApiKey,"GEMINI_API_KEY","GOOGLE_AI_API_KEY"),S=[];return l.found&&l.authenticated&&S.push("claude-code"),f.configured&&S.push("anthropic-api"),g.configured&&S.push("openai-api"),c.found&&c.authenticated&&S.push("gemini-cli"),y.configured&&S.push("gemini-api"),u.found&&u.authenticated&&S.push("codex-cli"),{tools:{node:t,git:o,hubspot:s,github:{...i,...a},claudeCode:l,geminiCli:c,codexCli:u},apiKeys:{anthropic:f,openai:g,gemini:y},activeEngine:e.aiEngine||null,availableEngines:S,enabledCLITools:r}}Z();Ye();h();import*as U from"@clack/prompts";function Fn(e){U.isCancel(e)&&(U.cancel(C.muted("Operation cancelled.")),process.exit(0))}async function re(e){U.intro(C.heading(e))}async function ae(e){U.outro(C.success(e))}async function Ee(e,t){U.note(e,t?C.heading(t):void 0)}async function ve(e){let t=await U.text({message:C.accent(e.message),placeholder:e.placeholder,defaultValue:e.defaultValue,validate:e.validate});return Fn(t),t}async function ee(e){let t=await U.confirm({message:C.accent(e.message),initialValue:e.initialValue??!0});return Fn(t),t}async function it(e){let t=await U.select({message:C.accent(e.message),options:e.options});return Fn(t),t}async function le(){let e=U.spinner();return{start:t=>e.start(C.muted(t)),stop:t=>e.stop(C.success(t)),message:t=>e.message(C.muted(t))}}function B(e){U.log.info(e)}function P(e){U.log.success(C.success(e))}function W(e){U.log.warn(C.warn(e))}function D(e){U.log.error(C.error(e))}async function qt(){await re("Checking your environment");let e=bt();e.found||(D("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),Kt(e.version)||(D(`Node.js ${e.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),P(`Node.js v${e.version}`);let t=St();t.found||(D("Git not found. Install it from https://git-scm.com"),process.exit(1)),P(`Git ${t.version}`);let o=N(),n=o.hubspotUploadMode!=="cli",s="",i="";if(n){let S=ue(),w=Ke();if(S)s=w?.portalId||"",i=w?.portalName||"",P(`HubSpot${i?`: ${i}`:""}${s?` (${s})`:""} \u2014 API mode`);else{W("No HubSpot account connected"),await Ee(`You need a Personal Access Key to deploy themes.
|
|
4
19
|
Create one at: https://app.hubspot.com/l/personal-access-key
|
|
5
|
-
Make sure the Content scope is enabled.`,"HubSpot connection required");let
|
|
20
|
+
Make sure the Content scope is enabled.`,"HubSpot connection required");let k=await ve({message:"Paste your Personal Access Key:",placeholder:"pat-na1-...",validate:R=>R.trim()?void 0:"Key is required"}),E=await le();E.start("Validating key...");try{let R=await Vt(k);Ht(k,R.portalId,R.portalName,R.dataCenter),S=k,s=R.portalId,i=R.portalName,E.stop(`Connected to ${R.portalName} (${R.portalId})`)}catch(R){E.stop("Validation failed"),D(`Invalid key: ${R instanceof Error?R.message:String(R)}`),process.exit(1)}}}else{let S=$e();if(S.found)P(`HubSpot CLI v${S.version}`);else{W("HubSpot CLI not found"),await ee({message:"Install HubSpot CLI globally?"})||(D("HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli"),process.exit(1));let E=await le();E.start("Installing HubSpot CLI..."),A("npm install -g @hubspot/cli").success||(E.stop("Failed"),D("Try: npm install -g @hubspot/cli"),process.exit(1)),S=$e(),E.stop(`HubSpot CLI v${S.version} installed`)}let w=ke();if(w.authenticated)P(`HubSpot portal${w.portalName?`: ${w.portalName}`:""} (ID: ${w.portalId})`);else{W("HubSpot not authenticated"),await ee({message:"Run `hs init` now?"})||(D("Run `hs init` manually."),process.exit(1));let E=await le();E.start("Waiting for HubSpot authentication..."),Ao("hs init")||(E.stop("Authentication failed"),process.exit(1)),w=ke(),E.stop(`Connected to portal${w.portalName?`: ${w.portalName}`:""} (ID: ${w.portalId})`)}s=w.portalId,i=w.portalName}let a=vt(),r=xt(),l=Ct(),c=No(),u={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"},p,f=o.aiEngine,g=[];if(a.found&&g.push({value:"claude-code",label:"Claude Code",hint:f==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),r.found&&g.push({value:"gemini-cli",label:"Gemini CLI",hint:f==="gemini-cli"?"last used":"uses your existing Gemini setup"}),l.found&&g.push({value:"codex-cli",label:"OpenAI Codex",hint:f==="codex-cli"?"last used":"uses your existing OpenAI setup"}),c&&g.push({value:"api",label:"Anthropic API",hint:f==="api"?"last used":"uses your API key"}),f&&g.sort((S,w)=>S.value===f?-1:w.value===f?1:0),g.length===1)p=g[0].value,P(`AI engine: ${u[p]} (auto-detected)`);else if(g.length>1)p=await it({message:"Choose your AI engine:",options:g});else if(await Ee(`You need an AI coding assistant to power the conversion.
|
|
6
21
|
|
|
7
|
-
${
|
|
22
|
+
${C.bold("Option 1:")} Install Claude Code ${C.muted("(recommended)")}
|
|
8
23
|
https://claude.ai/code
|
|
9
24
|
|
|
10
|
-
${
|
|
25
|
+
${C.bold("Option 2:")} Install Gemini CLI
|
|
11
26
|
https://github.com/google-gemini/gemini-cli
|
|
12
27
|
|
|
13
|
-
${
|
|
28
|
+
${C.bold("Option 3:")} Install OpenAI Codex
|
|
14
29
|
https://github.com/openai/codex
|
|
15
30
|
|
|
16
|
-
${
|
|
31
|
+
${C.bold("Option 4:")} Set an Anthropic API key
|
|
17
32
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
18
|
-
(get one at https://console.anthropic.com)`,"AI engine required"),p=await
|
|
19
|
-
`),u=i?`Tailwind + custom CSS (${
|
|
33
|
+
(get one at https://console.anthropic.com)`,"AI engine required"),p=await it({message:"Which will you set up?",options:[{value:"claude-code",label:"Claude Code",hint:"I'll install it now"},{value:"gemini-cli",label:"Gemini CLI",hint:"I'll install it now"},{value:"codex-cli",label:"OpenAI Codex",hint:"I'll install it now"},{value:"api",label:"Anthropic API",hint:"I'll enter my key"}]}),p==="api"){let S=await ve({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:w=>w.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=S,z({anthropicApiKey:S})}let y;return p==="claude-code"&&(y=await it({message:"Which model?",options:[{value:"sonnet",label:"Sonnet",hint:"fast, recommended"},{value:"opus",label:"Opus",hint:"most capable"},{value:"haiku",label:"Haiku",hint:"fastest, cheapest"}]})),z({aiEngine:p}),await ae("Environment ready!"),{aiEngine:p,model:y,portalId:s,portalName:i}}h();import{readdirSync as Hn,statSync as _r}from"fs";import{join as Y,basename as Ln,extname as Rr}from"path";Q();function Do(e){let t=[],o=[Y(e,"src/components/landing"),Y(e,"src/components/sections"),Y(e,"src/components"),Y(e,"src/pages"),Y(e,"app/components"),Y(e,"components")];for(let n of o)if(b(n))try{let s=Hn(n);for(let i of s){let a=Y(n,i);if(!_r(a).isFile())continue;let l=Rr(i);if(![".tsx",".jsx"].includes(l))continue;let c=Ln(i,l);if(c.startsWith("ui")||c==="index")continue;let u=v(a),p=Pr(c,u);t.push({name:c,path:a,description:p})}}catch{}return t}function Pr(e,t){let o=[];return/carousel|slider|swiper|embla/i.test(t)&&o.push("carousel"),/accordion|collapsible|expand/i.test(t)&&o.push("accordion"),/form|submit|input.*email/i.test(t)&&o.push("form"),/nav|navigation|menu/i.test(t)&&o.push("navigation"),/hero|headline|tagline/i.test(t)&&o.push("hero"),/footer|copyright/i.test(t)&&o.push("footer"),/testimonial|quote|review/i.test(t)&&o.push("testimonials"),/pricing|plan|tier/i.test(t)&&o.push("pricing"),/faq|question.*answer/i.test(t)&&o.push("FAQ"),/feature|benefit|advantage/i.test(t)&&o.push("features"),/contact|get.in.touch/i.test(t)&&o.push("contact"),/cta|call.to.action/i.test(t)&&o.push("CTA"),/team|member|bio/i.test(t)&&o.push("team"),o.length===0?e.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim():o.join(", ")}function Jo(e){let t=[Y(e,"src/index.css"),Y(e,"src/globals.css"),Y(e,"src/app/globals.css"),Y(e,"app/globals.css")],o=0,n=[];for(let s of t){if(!b(s))continue;let i=v(s),a=i.match(/--[\w-]+:/g);a&&(o+=a.length);let r=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(r)for(let c of r){let u=c.match(/['"]([^'"]+)['"]/)?.[1];u&&!n.includes(u)&&n.push(u)}let l=i.match(/@import\s+url\([^)]*fonts\.googleapis\.com[^)]*family=([^&)]+)/g);if(l)for(let c of l){let u=c.match(/family=([^&)]+)/)?.[1]?.replace(/\+/g," ");u&&!n.includes(u)&&n.push(u)}}return{varCount:o,fonts:n}}function Fo(e){let t=[],o=Y(e,"src/hooks");if(b(o))try{let s=Hn(o);for(let i of s)/scroll/i.test(i)&&t.push("Scroll animations"),/intersection/i.test(i)&&t.push("Scroll animations")}catch{}let n=Y(e,"src/components/landing");if(b(n))try{let s=Hn(n);for(let i of s){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let a=v(Y(n,i));/carousel|embla|swiper/i.test(a)&&!t.includes("Carousel")&&t.push("Carousel"),/accordion|collapsible/i.test(a)&&!t.includes("Accordion")&&t.push("Accordion"),/typing|typewriter/i.test(a)&&!t.includes("Typing animation")&&t.push("Typing animation"),/parallax|requestAnimationFrame/i.test(a)&&!t.includes("Parallax")&&t.push("Parallax")}}catch{}return t.length===0&&t.push("Scroll animations"),t}function Ho(e){let t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let l=Ln(e.replace(/\.git$/,""))||"react-source";if(t=Y(process.cwd(),"workspace",l),!b(t)){let c=A(`git clone --depth 1 "${e}" "${t}"`);if(!c.success)throw new Error(`Failed to clone ${e}: ${c.stderr}`)}}else if(t=e,!b(t))throw new Error(`Directory not found: ${t}`);let n=Do(t),s=b(Y(t,"tailwind.config.ts"))||b(Y(t,"tailwind.config.js")),{varCount:i,fonts:a}=Jo(t),r=Fo(t);return{sourceDir:t,wasCloned:o,components:n,hasTailwind:s,cssVarCount:i,fonts:a,interactions:r}}async function Xt(){await re("Source Project");let e=await ve({message:"GitHub URL or local path to your React project:",placeholder:"https://github.com/user/my-lovable-page",validate:y=>{if(!y.trim())return"Please enter a URL or path"}}),t,o=!1;if(e.startsWith("http")||e.startsWith("git@")){o=!0;let y=Ln(e.replace(/\.git$/,""))||"react-source";if(t=Y(process.cwd(),"workspace",y),b(t))P(`Using existing clone: ${C.dim(t)}`);else{let S=await le();S.start("Cloning repository..."),A(`git clone --depth 1 "${e}" "${t}"`).success||(S.stop("Clone failed"),D(`Failed to clone ${e}. Check the URL and your access permissions.`),process.exit(1)),S.stop(`Cloned to ${C.dim(t)}`)}}else t=e,b(t)||(D(`Directory not found: ${t}`),process.exit(1)),P(`Using local source: ${C.dim(t)}`);let n=await le();n.start("Analyzing project structure...");let s=Do(t),i=b(Y(t,"tailwind.config.ts"))||b(Y(t,"tailwind.config.js")),{varCount:a,fonts:r}=Jo(t),l=Fo(t);n.stop(`Found ${s.length} landing page components`),s.length===0&&(W("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=s.map((y,S)=>` ${C.dim(`${S+1}.`)} ${C.bold(y.name)} ${C.muted(`\u2014 ${y.description}`)}`).join(`
|
|
34
|
+
`),u=i?`Tailwind + custom CSS (${a} variables)`:`Custom CSS (${a} variables)`,p=r.length>0?r.join(", "):"System fonts",f=l.join(", ");return await Ee(`${c}
|
|
20
35
|
|
|
21
36
|
CSS: ${u}
|
|
22
37
|
JS: ${f}
|
|
23
|
-
Font: ${p}`,`${s.length} components detected`),await
|
|
24
|
-
`),
|
|
38
|
+
Font: ${p}`,`${s.length} components detected`),await ee({message:"Does this look right?"})||(D("Please adjust your source directory and try again."),process.exit(0)),await ae("Source analyzed!"),{sourceDir:t,wasCloned:o,components:s,hasTailwind:i,cssVarCount:a,fonts:r,interactions:l}}h();import{join as $t}from"path";Q();Z();h();import{mkdirSync as Le,writeFileSync as Qt}from"fs";import{join as we}from"path";function Zt(e,t){Le(e,{recursive:!0}),Le(we(e,"templates"),{recursive:!0}),Le(we(e,"modules"),{recursive:!0}),Le(we(e,"css"),{recursive:!0}),Le(we(e,"js"),{recursive:!0}),Le(we(e,"images"),{recursive:!0}),Le(we(e,"assets"),{recursive:!0});let o={label:t,preview_path:"./templates/home.html",screenshot_path:"./images/template-previews/home.png",enable_domain_stylesheets:!1,version:"1.0.0",author:{name:"vibeSpot",url:"https://github.com/borismichel/vibespot"}};Qt(we(e,"theme.json"),JSON.stringify(o,null,2)+`
|
|
39
|
+
`),Qt(we(e,"fields.json"),`[]
|
|
25
40
|
`);let n=`<!--
|
|
26
41
|
templateType: page
|
|
27
|
-
isAvailableForNewContent:
|
|
28
|
-
label: ${t}
|
|
42
|
+
isAvailableForNewContent: false
|
|
43
|
+
label: ${t} (placeholder)
|
|
29
44
|
screenshotPath: ../images/template-previews/home.png
|
|
30
45
|
-->
|
|
31
46
|
{% extends "./layouts/base.html" %}
|
|
@@ -37,7 +52,7 @@ ${v.bold("Option 4:")} Set an Anthropic API key
|
|
|
37
52
|
%}
|
|
38
53
|
{% end_dnd_area %}
|
|
39
54
|
{% endblock body %}
|
|
40
|
-
`;
|
|
55
|
+
`;Qt(we(e,"templates","home.html"),n);let s=`<!--
|
|
41
56
|
templateType: none
|
|
42
57
|
isAvailableForNewContent: false
|
|
43
58
|
label: Base Layout
|
|
@@ -47,19 +62,25 @@ ${v.bold("Option 4:")} Set an Anthropic API key
|
|
|
47
62
|
<head>
|
|
48
63
|
<meta charset="utf-8">
|
|
49
64
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
65
|
+
{% if template_css %}
|
|
66
|
+
{{ require_css(get_asset_url(template_css)) }}
|
|
67
|
+
{% endif %}
|
|
50
68
|
{{ standard_header_includes }}
|
|
51
69
|
</head>
|
|
52
70
|
<body>
|
|
53
71
|
{% block body %}{% endblock body %}
|
|
72
|
+
{% if template_js %}
|
|
73
|
+
{{ require_js(get_asset_url(template_js)) }}
|
|
74
|
+
{% endif %}
|
|
54
75
|
{{ standard_footer_includes }}
|
|
55
76
|
</body>
|
|
56
77
|
</html>
|
|
57
|
-
`;
|
|
78
|
+
`;Le(we(e,"templates","layouts"),{recursive:!0}),Qt(we(e,"templates","layouts","base.html"),s)}en();async function tn(){await re("HubSpot Theme Setup");let e=await it({message:"Do you have an existing HubSpot theme?",options:[{value:"fetch",label:"Fetch my existing theme from HubSpot",hint:"downloads your current theme"},{value:"create",label:"Start fresh (HubSpot Boilerplate)",hint:"creates a new starter theme"}]}),t,o,n=$t(process.cwd(),"workspace");if(ge(n),e==="fetch"){t=await ve({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:p=>p.trim()?void 0:"Theme name is required"}),o=$t(n,t);let l=await le();l.start("Fetching theme from HubSpot...");let c=N(),u=ue();if(c.hubspotUploadMode==="cli"||!u)A(`hs cms fetch "${t}" "${o}"`).success||(l.stop("Fetch failed"),D(`Could not fetch theme "${t}". Check the name in HubSpot Design Manager.`),process.exit(1));else try{await Tt(u,t,o)}catch(p){l.stop("Fetch failed"),D(`Could not fetch theme "${t}": ${p instanceof Error?p.message:String(p)}`),process.exit(1)}l.stop(`Theme fetched: ${C.dim(o)}`)}else{t=await ve({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),o=$t(n,t);let l=await le();l.start("Creating theme...");try{Zt(o,t)}catch(c){l.stop("Creation failed"),D(`Could not create theme "${t}": ${c instanceof Error?c.message:String(c)}`),process.exit(1)}l.stop(`Theme created: ${C.dim(o)}`)}await re("Checking theme compatibility");let s=$t(o,"templates/layouts/base.html");b(s)||(D(`base.html not found at ${s}. Your theme may have a different structure.`),process.exit(1)),P("base.html found");let i=v(s),a=!1;if(i.includes("template_css"))P("template_css support");else{W("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
|
|
58
79
|
`,i.indexOf("theme-overrides.css"))):i.lastIndexOf("require_css");if(l>0){let c=i.lastIndexOf(`
|
|
59
80
|
`,l);i=i.slice(0,c)+`
|
|
60
81
|
{% if template_css %}
|
|
61
82
|
{{ require_css(get_asset_url(template_css)) }}
|
|
62
|
-
{% endif %}`+i.slice(c),
|
|
83
|
+
{% endif %}`+i.slice(c),a=!0}}if(i.includes("template_js"))P("template_js support");else{W("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
|
|
63
84
|
`,l),u=i.indexOf(`
|
|
64
85
|
`,c+1),p=`
|
|
65
86
|
{% if template_js %}
|
|
@@ -67,14 +88,14 @@ ${v.bold("Option 4:")} Set an Anthropic API key
|
|
|
67
88
|
{% endif %}`,f=i.indexOf("}}",l)+2+i.slice(i.indexOf("}}",l)+2).indexOf(`
|
|
68
89
|
`)+1;i=i.slice(0,i.indexOf(`
|
|
69
90
|
`,i.indexOf("}}",l)+2))+p+i.slice(i.indexOf(`
|
|
70
|
-
`,i.indexOf("}}",l)+2)),
|
|
91
|
+
`,i.indexOf("}}",l)+2)),a=!0}}if(a){let l=await le();l.start("Patching base.html..."),M(s,i),l.stop("base.html patched with template_css/template_js support")}let r=$t(o,".hsignore");if(b(r)){let l=v(r);l.includes("docs/")||(M(r,l+`
|
|
71
92
|
docs/
|
|
72
|
-
`),
|
|
93
|
+
`),P("Added docs/ to .hsignore"))}else M(r,`docs/
|
|
73
94
|
*.md
|
|
74
95
|
node_modules/
|
|
75
96
|
.git
|
|
76
|
-
`),
|
|
77
|
-
## `,s+n.length);return i>=0?t.slice(s,i).trim():t.slice(s).trim()}function
|
|
97
|
+
`),P("Created .hsignore");return await ae("Theme ready!"),{themePath:o,themeName:t}}h();import{join as ye}from"path";import{readdirSync as kt,rmSync as ts}from"fs";h();import{spawn as Jr}from"child_process";import{join as F,basename as Fr}from"path";import{readdirSync as Ne,statSync as Zo,writeFileSync as Hr}from"fs";h();Q();var Uo=new Map;function rt(e){let t=Uo.get(e);if(t!==void 0)return t;try{t=v(Ft(e))}catch{t=""}return Uo.set(e,t),t}function de(){return rt("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function Wo(){return rt("design-guide.md")}function Ko(){return rt("content-guide.md")}function at(){return rt("hubspot-rules.md")}function Bo(){return rt("humanify-guide.md")}function Yo(e){let t=rt("page-types.md");if(!t)return"";let n={landing_page:"## Landing Page",blog_post:"## Blog Post",website_page:"## Website Page",module_only:"## Module Only"}[e];if(!n)return"";let s=t.indexOf(n);if(s<0)return"";let i=t.indexOf(`
|
|
98
|
+
## `,s+n.length);return i>=0?t.slice(s,i).trim():t.slice(s).trim()}function Vo(e){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
|
|
78
99
|
|
|
79
100
|
## Rules
|
|
80
101
|
Follow the conversion guide below EXACTLY. Key rules:
|
|
@@ -91,10 +112,10 @@ Follow the conversion guide below EXACTLY. Key rules:
|
|
|
91
112
|
- Convert React hooks to vanilla JS (no React, no npm packages)
|
|
92
113
|
|
|
93
114
|
## HubSpot CMS Rules
|
|
94
|
-
${
|
|
115
|
+
${at()}
|
|
95
116
|
|
|
96
117
|
## Conversion Guide
|
|
97
|
-
${e}`}function
|
|
118
|
+
${e}`}function zo(e,t,o){return`Convert this React component to a HubSpot module named "${t}".
|
|
98
119
|
|
|
99
120
|
Return a JSON object with these keys:
|
|
100
121
|
- fieldsJson: complete fields.json content (as JSON string)
|
|
@@ -109,7 +130,7 @@ ${o}
|
|
|
109
130
|
React component source:
|
|
110
131
|
${e}
|
|
111
132
|
|
|
112
|
-
Return ONLY valid JSON, no markdown fences.`}function
|
|
133
|
+
Return ONLY valid JSON, no markdown fences.`}function qo(e,t,o){return`Create a shared CSS file for a HubSpot CMS landing page.
|
|
113
134
|
|
|
114
135
|
Extract the design system from the source CSS and Tailwind config below.
|
|
115
136
|
Use the class prefix ".${o}-" for all custom classes.
|
|
@@ -133,7 +154,7 @@ ${e}
|
|
|
133
154
|
Tailwind config:
|
|
134
155
|
${t}
|
|
135
156
|
|
|
136
|
-
Return ONLY the CSS content, no markdown fences.`}function
|
|
157
|
+
Return ONLY the CSS content, no markdown fences.`}function Xo(e,t,o){return`Create a shared vanilla JS file for a HubSpot CMS landing page.
|
|
137
158
|
|
|
138
159
|
Convert the React hooks and interactive components below to plain JavaScript.
|
|
139
160
|
Use the class prefix "${o}-" to match the CSS.
|
|
@@ -151,7 +172,7 @@ ${e}
|
|
|
151
172
|
Interactive component sources:
|
|
152
173
|
${t}
|
|
153
174
|
|
|
154
|
-
Return ONLY the JavaScript content, no markdown fences.`}function
|
|
175
|
+
Return ONLY the JavaScript content, no markdown fences.`}function Qo(e,t,o){return`Create a HubSpot page template that assembles these modules:
|
|
155
176
|
|
|
156
177
|
${e.map((n,s)=>`${s+1}. ${n}.module`).join(`
|
|
157
178
|
`)}
|
|
@@ -166,11 +187,11 @@ Template requirements:
|
|
|
166
187
|
- Each module in its own dnd_section with padding zeroed and full_width=true
|
|
167
188
|
- dnd_area label: "${t} Landing Page"
|
|
168
189
|
|
|
169
|
-
Return ONLY the template HTML content, no markdown fences.`}var
|
|
190
|
+
Return ONLY the template HTML content, no markdown fences.`}Q();var Lr=new Set(["about.html","blog-index.html","blog-post.html","contact.html","home.html","hubdb.html","landing-page.html","pricing.html","qa-test.html","base.html"]),nn=class{model;reported=new Set;moduleCount=0;expectedModules=0;constructor(t){this.model=t}async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||de();this.reported.clear(),this.moduleCount=0,this.expectedModules=0;let a=this.countSourceComponents(o),r=this.listModules(n),l=this.listDir(F(n,"css")),c=this.listDir(F(n,"js")),u=this.listDir(F(n,"templates")),p=this.buildFullPrompt(o,n,i);s("convert",`Starting Claude Code (${a} source components found)...`);let f="",g="",y=setInterval(()=>{this.reportProgress(n,r,l,c,u,s)},3e3);try{await new Promise((E,R)=>{let X={...process.env};delete X.CLAUDECODE;let L=["--print","--max-turns","50","--allowedTools","Read,Glob,Grep,Write,Edit,Bash"];this.model&&L.push("--model",this.model);let O=Jr("claude",L,{cwd:n,stdio:["pipe","pipe","pipe"],env:X,shell:!0});O.stdout.on("data",G=>{f+=G.toString()}),O.stderr.on("data",G=>{g+=G.toString()}),O.on("error",G=>R(new Error(`Claude Code failed to start: ${G.message}`))),O.on("close",G=>{G!==0?R(new Error(`Claude Code exited with code ${G}.
|
|
170
191
|
`+(g?`Stderr: ${g.slice(0,500)}
|
|
171
|
-
`:"")+(f?`Output: ${f.slice(0,500)}`:"No output"))):
|
|
192
|
+
`:"")+(f?`Output: ${f.slice(0,500)}`:"No output"))):E()}),O.stdin.on("error",()=>{}),O.stdin.write(p),O.stdin.end(),setTimeout(()=>{O.kill(),R(new Error("Claude Code timed out after 30 minutes"))},18e5)})}finally{clearInterval(y)}let S=F(n,"..","vibespot-conversion.log");try{let R=["=== vibeSpot Conversion Log ===",`Timestamp: ${new Date().toISOString()}`,`Source: ${o}`,`Theme: ${n}`,`Model: ${this.model||"default"}`,"","=== PROMPT SENT ===",p.slice(0,500)+`
|
|
172
193
|
... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",f||"(empty)","","=== CLAUDE CODE STDERR ===",g||"(empty)",""].join(`
|
|
173
|
-
`);
|
|
194
|
+
`);Hr(S,R,"utf-8"),s("status",`Log written to ${Fr(S)}`)}catch{}s("scan","Scanning generated files...");let w=this.scanGeneratedFiles(n);if(w.modules.filter(E=>!r.has(E.moduleName+".module")).length===0){let E=f.slice(0,1500)||"(no output)",R=g.slice(0,500);throw new Error(`Claude Code did not create any new module files.
|
|
174
195
|
|
|
175
196
|
This usually means the model described the conversion instead of using Write tool to create files.
|
|
176
197
|
|
|
@@ -181,12 +202,12 @@ Possible causes:
|
|
|
181
202
|
|
|
182
203
|
Source: ${t.sourceDir}
|
|
183
204
|
Theme: ${n}
|
|
184
|
-
`+(
|
|
205
|
+
`+(R?`
|
|
185
206
|
Stderr:
|
|
186
|
-
${
|
|
207
|
+
${R}
|
|
187
208
|
`:"")+`
|
|
188
209
|
Claude output:
|
|
189
|
-
${
|
|
210
|
+
${E}`)}return w}reportProgress(t,o,n,s,i,a){let r=0,l=this.listDir(F(t,"css"));for(let f of l){if(n.has(f)||!f.endsWith(".css"))continue;let g=`css:${f}`;this.reported.has(g)||(this.reported.add(g),a("created",`Shared CSS (${f})`),r++)}let c=this.listDir(F(t,"js"));for(let f of c){if(s.has(f)||!f.endsWith(".js"))continue;let g=`js:${f}`;this.reported.has(g)||(this.reported.add(g),a("created",`Shared JS (${f})`),r++)}this.expectedModules===0&&(this.expectedModules=this.detectExpectedModules(t,i));let u=this.listModules(t);for(let f of u){if(o.has(f))continue;let g=`module:${f}`;if(!this.reported.has(g)){this.reported.add(g),this.moduleCount++;let y=this.expectedModules>0?`[${this.moduleCount}/${this.expectedModules}]`:`[${this.moduleCount}]`;a("created",`Module ${y}: ${f.replace(".module","")}`),r++}}let p=this.listDir(F(t,"templates"));for(let f of p){if(i.has(f)||!f.endsWith(".html"))continue;let g=`template:${f}`;this.reported.has(g)||(this.reported.add(g),a("created",`Page template (${f})`),r++)}if(r===0)if(this.moduleCount>0){let f=this.expectedModules>0?`/${this.expectedModules}`:"";a("status",`${this.moduleCount}${f} modules created, conversion continuing...`)}else this.reported.size>0?a("status","Shared assets created, building modules..."):a("status","Claude Code is analyzing source files...")}buildFullPrompt(t,o,n){return`You are converting a React landing page to native HubSpot CMS modules.
|
|
190
211
|
|
|
191
212
|
SOURCE DIRECTORY: ${t}
|
|
192
213
|
THEME DIRECTORY: ${o}
|
|
@@ -229,16 +250,16 @@ CSS QUALITY: The converted page must visually match the original React page. Eve
|
|
|
229
250
|
Do NOT run hs upload \u2014 I will handle that separately.
|
|
230
251
|
|
|
231
252
|
HUBSPOT CMS RULES:
|
|
232
|
-
${
|
|
253
|
+
${at()}
|
|
233
254
|
|
|
234
255
|
CONVERSION GUIDE:
|
|
235
|
-
${n}`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=
|
|
236
|
-
${
|
|
256
|
+
${n}`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=F(t,"css");if(b(n)){for(let r of Ne(n))if(r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){o.sharedCss=v(F(n,r));break}}let s=F(t,"js");if(b(s)){for(let r of Ne(s))if(r.endsWith(".js")&&r!=="main.js"){o.sharedJs=v(F(s,r));break}}let i=F(t,"templates");if(b(i)){for(let r of Ne(i))if(r.startsWith("lp-")&&r.endsWith(".html")){o.template=v(F(i,r));break}if(!o.template){for(let r of Ne(i))if(r.endsWith(".html")&&!Lr.has(r)&&!r.startsWith("system")){let l=v(F(i,r));if(l.includes("dnd_area")){o.template=l;break}}}if(!o.template){for(let r of Ne(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=v(F(i,r));if(l.includes("dnd_area")){o.template=l;break}}}}let a=F(t,"modules");if(b(a))for(let r of Ne(a)){if(!r.endsWith(".module"))continue;let l=F(a,r);if(!Zo(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=F(l,"fields.json");b(u)&&(c.fieldsJson=v(u));let p=F(l,"meta.json");b(p)&&(c.metaJson=v(p));let f=F(l,"module.html");b(f)&&(c.moduleHtml=v(f));let g=F(l,"module.css");b(g)&&(c.moduleCss=v(g));let y=F(l,"module.js");b(y)&&(c.moduleJs=v(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}listModules(t){let o=F(t,"modules");return b(o)?new Set(Ne(o).filter(n=>n.endsWith(".module"))):new Set}listDir(t){return b(t)?new Set(Ne(t)):new Set}detectExpectedModules(t,o){let n=F(t,"templates");if(!b(n))return 0;for(let s of Ne(n))if(!o.has(s)&&!(!s.endsWith(".html")||s==="base.html"||s.startsWith("system")))try{let i=v(F(n,s));if(i.includes("dnd_area")){let a=i.match(/dnd_module/g);return a?a.length:0}}catch{}return 0}countSourceComponents(t){let o=F(t,"src");return b(o)?this.countComponentsRecursive(o):0}countComponentsRecursive(t){let o=0;for(let n of Ne(t)){let s=F(t,n);try{Zo(s).isDirectory()&&n!=="node_modules"&&n!==".git"?o+=this.countComponentsRecursive(s):/\.(tsx|jsx)$/.test(n)&&!n.includes(".test.")&&!n.includes(".spec.")&&o++}catch{}}return o}};h();import Gr from"@anthropic-ai/sdk";import{join as K,basename as Ur}from"path";import{readdirSync as es}from"fs";Q();var on=class{client;model="claude-sonnet-4-6";constructor(t){this.client=new Gr({apiKey:t||process.env.ANTHROPIC_API_KEY})}async convert(t){let{sourceDir:o,themePath:n,conversionGuide:s,onProgress:i}=t,a=Vo(s),r=Ur(o)||"page",l=r.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,15);i("css","Analyzing design system...");let c=this.findAndReadCSS(o),u=this.findAndReadTailwind(o),p=await this.complete(a,qo(c,u,l)),f=K(n,"css",`${l}-theme.css`);M(f,p),i("css-done",`Created css/${l}-theme.css`),i("js","Creating shared JavaScript...");let g=this.findAndReadHooks(o),y=this.findInteractiveComponents(o),S=await this.complete(a,Xo(g,y,l)),w=K(n,"js",`${l}-animations.js`);M(w,S),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let k=this.findComponents(o),E=[];for(let O=0;O<k.length;O++){let G=k[O],oe=G.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${oe}.module (${O+1}/${k.length})...`);let H=v(G.path),Jt=await this.complete(a,zo(H,oe,`See css/${l}-theme.css`));try{let se=JSON.parse(Jt),Se={moduleName:oe,fieldsJson:typeof se.fieldsJson=="string"?se.fieldsJson:JSON.stringify(se.fieldsJson,null,2),metaJson:typeof se.metaJson=="string"?se.metaJson:JSON.stringify(se.metaJson,null,2),moduleHtml:se.moduleHtml||"",moduleCss:se.moduleCss||"",moduleJs:se.moduleJs||void 0},He=K(n,"modules",`${oe}.module`);ge(He),M(K(He,"fields.json"),Se.fieldsJson),M(K(He,"meta.json"),Se.metaJson),M(K(He,"module.html"),Se.moduleHtml),M(K(He,"module.css"),Se.moduleCss),Se.moduleJs&&M(K(He,"module.js"),Se.moduleJs),E.push(Se),i("module-done",`${oe}.module (${this.countFiles(Se)} files)`)}catch{i("module-error",`Failed to parse ${oe} \u2014 skipping`)}}i("template","Creating page template...");let R=E.map(O=>O.moduleName),X=await this.complete(a,Qo(R,r,l)),L=K(n,"templates",`lp-${l}.html`);return M(L,X),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:p,sharedJs:S,template:X,modules:E}}async complete(t,o){return(await this.client.messages.create({model:this.model,max_tokens:8192,system:t,messages:[{role:"user",content:o}]})).content.find(i=>i.type==="text")?.text||""}findAndReadCSS(t){let o=[K(t,"src/index.css"),K(t,"src/globals.css"),K(t,"src/app/globals.css"),K(t,"app/globals.css")];for(let n of o)if(b(n))return v(n);return""}findAndReadTailwind(t){let o=[K(t,"tailwind.config.ts"),K(t,"tailwind.config.js"),K(t,"tailwind.config.mjs")];for(let n of o)if(b(n))return v(n);return""}findAndReadHooks(t){let o=K(t,"src/hooks");if(!b(o))return"";try{return es(o).filter(n=>n.endsWith(".ts")||n.endsWith(".tsx")).map(n=>`// ${n}
|
|
257
|
+
${v(K(o,n))}`).join(`
|
|
237
258
|
|
|
238
|
-
`)}catch{return""}}findInteractiveComponents(t){let o=this.findComponents(t),n=[];for(let s of o){let i=
|
|
259
|
+
`)}catch{return""}}findInteractiveComponents(t){let o=this.findComponents(t),n=[];for(let s of o){let i=v(s.path);/carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(i)&&n.push(`// ${s.name}
|
|
239
260
|
${i}`)}return n.join(`
|
|
240
261
|
|
|
241
|
-
`)}findComponents(t){let o=[
|
|
262
|
+
`)}findComponents(t){let o=[K(t,"src/components/landing"),K(t,"src/components/sections"),K(t,"src/components")];for(let n of o)if(b(n))try{return es(n).filter(s=>(s.endsWith(".tsx")||s.endsWith(".jsx"))&&!s.startsWith("ui")&&s!=="index.tsx"&&s!=="index.jsx").map(s=>({name:s.replace(/\.(tsx|jsx)$/,""),path:K(n,s)}))}catch{continue}return[]}countFiles(t){let o=3;return t.moduleCss&&o++,t.moduleJs&&o++,o}};h();import{spawn as Wr}from"child_process";import{join as me}from"path";import{readdirSync as sn,statSync as Kr}from"fs";Q();var rn=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||de(),a=this.buildFullPrompt(o,n,i);return s("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Wr("gemini",["-p",a],{cwd:n,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),u="",p="";c.stdout.on("data",f=>{u+=f.toString()}),c.stderr.on("data",f=>{p+=f.toString()}),c.on("error",f=>l(new Error(`Gemini CLI failed: ${f.message}`))),c.on("close",f=>{f!==0&&p&&!u?l(new Error(`Gemini CLI failed: ${p}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Gemini CLI timed out after 10 minutes"))},6e5)}),s("scan","Scanning generated files..."),this.scanGeneratedFiles(n)}buildFullPrompt(t,o,n){return`Read the conversion guide below, then convert the React landing page at ${t} into native HubSpot CMS modules for the theme at ${o}.
|
|
242
263
|
|
|
243
264
|
INSTRUCTIONS:
|
|
244
265
|
1. Analyze all .tsx/.jsx components in the React source
|
|
@@ -253,7 +274,7 @@ CONVERSION GUIDE:
|
|
|
253
274
|
${n}
|
|
254
275
|
|
|
255
276
|
Do NOT run hs upload \u2014 I will handle that separately.
|
|
256
|
-
Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=
|
|
277
|
+
Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=me(t,"css");if(b(n)){for(let r of sn(n))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){o.sharedCss=v(me(n,r));break}}let s=me(t,"js");if(b(s)){for(let r of sn(s))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){o.sharedJs=v(me(s,r));break}}let i=me(t,"templates");if(b(i)){for(let r of sn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=v(me(i,r));if(l.includes("dnd_area")){o.template=l;break}}}let a=me(t,"modules");if(b(a))for(let r of sn(a)){if(!r.endsWith(".module"))continue;let l=me(a,r);if(!Kr(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=me(l,"fields.json");b(u)&&(c.fieldsJson=v(u));let p=me(l,"meta.json");b(p)&&(c.metaJson=v(p));let f=me(l,"module.html");b(f)&&(c.moduleHtml=v(f));let g=me(l,"module.css");b(g)&&(c.moduleCss=v(g));let y=me(l,"module.js");b(y)&&(c.moduleJs=v(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};h();import{spawn as Br}from"child_process";import{join as pe}from"path";import{readdirSync as an,statSync as Yr}from"fs";Q();var ln=class{async convert(t){let{sourceDir:o,themePath:n,onProgress:s}=t,i=t.conversionGuide||de(),a=this.buildFullPrompt(o,n,i);return s("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Br("codex",["exec","--full-auto",a],{cwd:n,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),u="",p="";c.stdout.on("data",f=>{u+=f.toString()}),c.stderr.on("data",f=>{p+=f.toString()}),c.on("error",f=>l(new Error(`Codex CLI failed: ${f.message}`))),c.on("close",f=>{f!==0&&p&&!u?l(new Error(`Codex CLI failed: ${p}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Codex CLI timed out after 10 minutes"))},6e5)}),s("scan","Scanning generated files..."),this.scanGeneratedFiles(n)}buildFullPrompt(t,o,n){return`Read the conversion guide below, then convert the React landing page at ${t} into native HubSpot CMS modules for the theme at ${o}.
|
|
257
278
|
|
|
258
279
|
INSTRUCTIONS:
|
|
259
280
|
1. Analyze all .tsx/.jsx components in the React source
|
|
@@ -268,55 +289,55 @@ CONVERSION GUIDE:
|
|
|
268
289
|
${n}
|
|
269
290
|
|
|
270
291
|
Do NOT run hs upload \u2014 I will handle that separately.
|
|
271
|
-
Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=
|
|
272
|
-
HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let t=
|
|
273
|
-
${u}/${l.length} checks passed`),await
|
|
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(
|
|
292
|
+
Create all files directly in the theme directory.`}scanGeneratedFiles(t){let o={sharedCss:"",sharedJs:"",template:"",modules:[]},n=pe(t,"css");if(b(n)){for(let r of an(n))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){o.sharedCss=v(pe(n,r));break}}let s=pe(t,"js");if(b(s)){for(let r of an(s))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){o.sharedJs=v(pe(s,r));break}}let i=pe(t,"templates");if(b(i)){for(let r of an(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=v(pe(i,r));if(l.includes("dnd_area")){o.template=l;break}}}let a=pe(t,"modules");if(b(a))for(let r of an(a)){if(!r.endsWith(".module"))continue;let l=pe(a,r);if(!Yr(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},u=pe(l,"fields.json");b(u)&&(c.fieldsJson=v(u));let p=pe(l,"meta.json");b(p)&&(c.metaJson=v(p));let f=pe(l,"module.html");b(f)&&(c.moduleHtml=v(f));let g=pe(l,"module.css");b(g)&&(c.moduleCss=v(g));let y=pe(l,"module.js");b(y)&&(c.moduleJs=v(y)),c.fieldsJson&&c.moduleHtml&&o.modules.push(c)}return o}};Q();function Vr(e,t){switch(e){case"claude-code":return new nn(t);case"gemini-cli":return new rn;case"codex-cli":return new ln;case"api":return new on}}async function cn(e){await re("Converting React to HubSpot Modules"),await Ee(`AI will now analyze your React code and create
|
|
293
|
+
HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let t=Vr(e.aiEngine,e.model),o=de(),n=await le();n.start("Starting AI conversion...");let s=Date.now(),i=await t.convert({sourceDir:e.sourceDir,themePath:e.themePath,conversionGuide:o,onProgress:(y,S)=>{y==="created"?P(S):n.message(S)}}),a=((Date.now()-s)/1e3).toFixed(0);n.stop(`AI conversion complete (${a}s)`);let r=zr(e.themePath);for(let y of r)P(`Auto-fixed: ${y}`);let l=qr(e.themePath,i),c=[];for(let y of l){let S=y.passed?"\u2705":"\u274C",w=y.passed?"":y.critical?" (CRITICAL)":" (cosmetic)";c.push(`${S} ${y.label}${w}`)}let u=l.filter(y=>y.passed).length;c.push(`
|
|
294
|
+
${u}/${l.length} checks passed`),await Ee(c.join(`
|
|
295
|
+
`),"Conversion Checklist");let p=l.filter(y=>!y.passed&&y.critical),f=l.filter(y=>!y.passed&&!y.critical);if(p.length>0){if(D(`${p.length} critical issue(s) \u2014 upload will likely fail:
|
|
275
296
|
`+p.map(S=>` - ${S.label}`).join(`
|
|
276
|
-
`)),!await
|
|
297
|
+
`)),!await ee({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else f.length>0&&W(`${f.length} non-critical issue(s) \u2014 page will work but may look incomplete:
|
|
277
298
|
`+f.map(y=>` - ${y.label}`).join(`
|
|
278
|
-
`));let g=
|
|
279
|
-
`,l=!0)}catch{t.push(`${
|
|
280
|
-
templateType: page`),
|
|
299
|
+
`));let g=ye(e.themePath,"..","vibespot-conversion.log");return b(g)&&(await ee({message:"Keep conversion log file for debugging?",initialValue:!1})?P(`Log saved: ${g}`):ts(g)),await ae("Files ready for upload!"),i}function zr(e){let t=[];Xr(e),Qr(e);let o=ye(e,"modules");if(b(o))for(let s of kt(o)){if(!s.endsWith(".module"))continue;let i=ye(o,s,"fields.json");if(!b(i))continue;let a=s.replace(".module",""),r=v(i),l=!1;r.includes('"textarea"')&&(r=r.replace(/"textarea"/g,'"text"'),l=!0,t.push(`${a}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(r)&&(r=r.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,t.push(`${a}: reserved field name "name" \u2192 "item_name"`));try{let u=JSON.parse(r),p=!1;ns(u)&&(p=!0,t.push(`${a}: fixed choice field format`)),os(u)&&(p=!0,t.push(`${a}: fixed link field default value`)),p&&(r=JSON.stringify(u,null,2)+`
|
|
300
|
+
`,l=!0)}catch{t.push(`${a}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&M(i,r);let c=ye(o,s,"module.html");if(b(c)){let u=v(c);u.includes("now()")&&(u=u.replace(/now\(\)/g,"local_dt"),M(c,u),t.push(`${a}: now() \u2192 local_dt`))}}let n=ye(e,"templates");if(b(n))for(let s of kt(n)){if(!s.endsWith(".html"))continue;let i=ye(n,s),a=v(i);(a.includes("hubdb_table")||a.includes("hubdb_table_rows"))&&(ts(i),t.push(`Removed ${s} (HubDB requires CMS Hub Pro/Enterprise)`))}return t}function ns(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;n.type==="choice"&&Array.isArray(n.choices)&&n.choices.some(i=>typeof i=="string")&&(n.choices=n.choices.map(i=>{if(typeof i=="string"){let a=i.charAt(0).toUpperCase()+i.slice(1);return[i,a]}return i}),t=!0),Array.isArray(n.children)&&ns(n.children)&&(t=!0)}return t}function os(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;if(n.type==="link"){let s=n.default;if(typeof s=="string"||s===void 0||s===null||typeof s=="object"&&!s.url){let a=typeof s=="string"?s:"";n.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&os(n.children)&&(t=!0)}return t}function qr(e,t){let o=[],n=t.modules.length;o.push({label:`Modules created (${n})`,passed:n>0,critical:!0});let s=!0;for(let p of t.modules)if(p.fieldsJson.includes('"textarea"')||/"name":\s*"name"/.test(p.fieldsJson)){s=!1;break}o.push({label:"fields.json valid (no textarea, no reserved names)",passed:n>0&&s,critical:!0});let i=t.modules.every(p=>p.moduleHtml.length>0);o.push({label:"module.html created for each module",passed:n>0&&i,critical:!0});let a=t.modules.filter(p=>!p.moduleCss).map(p=>p.moduleName),r=a.length===0;o.push({label:r?"module.css created for each module":`module.css missing for: ${a.join(", ")}`,passed:n>0&&r,critical:!1});let l=t.modules.some(p=>p.fieldsJson.includes('"STYLE"'));o.push({label:"Style tab fields (color pickers)",passed:l,critical:!1}),o.push({label:"Shared CSS with design system variables",passed:t.sharedCss.length>50,critical:!1}),o.push({label:"Shared JS for scroll animations",passed:t.sharedJs.length>50,critical:!1}),o.push({label:"Page template with dnd_area",passed:t.template.length>0&&t.template.includes("dnd_area"),critical:!0});let c=ye(e,"templates"),u=!1;if(b(c))for(let p of kt(c)){if(!p.endsWith(".html")||p==="base.html"||p.startsWith("system"))continue;let f=v(ye(c,p));if(f.includes("dnd_area")&&/templateType\s*:\s*page/i.test(f)){u=!0;break}}return o.push({label:"Template annotations (templateType: page)",passed:u,critical:!0}),o}function Xr(e){let t=ye(e,"templates");if(b(t))for(let o of kt(t)){if(!o.endsWith(".html")||o==="base.html"||o.startsWith("system"))continue;let n=ye(t,o),s=v(n);if(!s.includes("dnd_area")&&!s.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(s),a=/isAvailableForNewContent\s*:\s*true/i.test(s);if(i&&a)continue;let r=o.replace(".html","").replace(/[-_]/g," ").replace(/\b\w/g,l=>l.toUpperCase());if(s.includes("<!--")&&s.indexOf("-->")<200){let l=s.indexOf("-->"),c=s.slice(0,l);i||(c+=`
|
|
301
|
+
templateType: page`),a||(c+=`
|
|
281
302
|
isAvailableForNewContent: true`),/label\s*:/i.test(c)||(c+=`
|
|
282
|
-
label: ${
|
|
303
|
+
label: ${r}`),s=c+s.slice(l)}else s=`<!--
|
|
283
304
|
templateType: page
|
|
284
305
|
isAvailableForNewContent: true
|
|
285
|
-
label: ${
|
|
306
|
+
label: ${r}
|
|
286
307
|
-->
|
|
287
|
-
`+s;
|
|
288
|
-
`)}catch{}}}import{join as
|
|
289
|
-
`),t=!0)}catch{}}return t}function
|
|
290
|
-
`),t=!0)}catch{}}return t}function
|
|
291
|
-
`);c=
|
|
292
|
-
You can check your HubSpot Design Manager to verify.`),await
|
|
293
|
-
The theme may work \u2014 check HubSpot Design Manager.`),await
|
|
308
|
+
`+s;M(n,s),P(`Template "${o}" \u2014 annotations verified`)}}function Qr(e){let t=ye(e,"modules");if(b(t))for(let o of kt(t)){if(!o.endsWith(".module"))continue;let n=ye(t,o,"meta.json");if(b(n))try{let s=JSON.parse(v(n)),i=!1;(!s.host_template_types||!s.host_template_types.includes("PAGE"))&&(s.host_template_types=["PAGE"],i=!0),s.is_available_for_new_content||(s.is_available_for_new_content=!0,i=!0),i&&M(n,JSON.stringify(s,null,2)+`
|
|
309
|
+
`)}catch{}}}h();import{join as fs,basename as la}from"path";h();Q();import{join as te}from"path";import{readdirSync as De,rmSync as Zr}from"fs";function dn(e){let t=[];for(let o of e){let n=`${o.message}${o.detail?` \u2014 ${o.detail}`:""}`,s=!1;/textarea|unknown.*field.*type/i.test(n)&&(s=!0),/reserved.*name|missing field name|field null/i.test(n)&&(s=!0),/could not resolve.*now/i.test(n)&&(s=!0),/hubdb|do not have access/i.test(n)&&(s=!0),/invalid default value|link.*invalid|deserializ/i.test(n)&&(s=!0),/color.*invalid/i.test(n)&&(s=!0),t.push({file:o.file||"unknown",message:n,fixable:s})}return t}function un(e){let t=[];if(/textarea.*not.*valid|unknown.*field.*type/i.test(e)){let o=e.match(/(?:in|file:?)\s+(\S+fields\.json)/i);t.push({file:o?.[1]||"fields.json",message:'"textarea" is not a valid field type',fixable:!0})}if(/missing field name|field null/i.test(e)){let o=e.match(/(?:in|file:?)\s+(\S+fields\.json)/i);t.push({file:o?.[1]||"fields.json",message:'"name" is a reserved field name',fixable:!0})}if(/could not resolve.*now/i.test(e)&&t.push({file:"module.html",message:"now() is not a valid HubL function",fixable:!0}),/hubdb|do not have access to hubdb/i.test(e)&&t.push({file:"templates",message:"HubDB requires CMS Hub Pro/Enterprise",fixable:!0}),/invalid default value|link.*field.*invalid/i.test(e)){let o=e.match(/field.*?(\w+)\s+has an invalid/i);t.push({file:o?.[1]||"fields.json",message:"Link field has invalid default value",fixable:!0})}if(/failed to deserialize/i.test(e)){let o=e.match(/file '([^']+)'/i);t.push({file:o?.[1]||"fields.json",message:"fields.json deserialization error",fixable:!0})}return/format for the color value is invalid/i.test(e)&&t.push({file:"fields.json",message:"Color field has invalid format (rgba/rgb/named \u2014 must be hex)",fixable:!0}),t}function mn(e){let t=[];return is(e)&&t.push("textarea \u2192 text"),rs(e)&&t.push("name \u2192 item_name"),as(e)&&t.push("now() \u2192 local_dt"),ls(e)&&t.push("Removed HubDB templates"),cs(e)&&t.push("Fixed link field defaults"),ds(e)&&t.push("Fixed rgba/invalid color values \u2192 hex"),ea(e)&&t.push("Stripped CDN @import statements"),t}function ss(e,t){return t.message.includes("textarea")?is(e):t.message.includes("reserved field name")?rs(e):t.message.includes("now()")?as(e):t.message.includes("HubDB")?ls(e):t.message.includes("invalid default value")||t.message.includes("deserialization")?cs(e):t.message.includes("invalid format")&&t.message.includes("color")?ds(e):!1}function is(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(!b(s))continue;let i=v(s);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),M(s,i),t=!0)}return t}function rs(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(!b(s))continue;let i=v(s);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),M(s,i),t=!0)}return t}function as(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"module.html");if(!b(s))continue;let i=v(s);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),M(s,i),t=!0)}return t}function ls(e){let t=!1,o=te(e,"templates");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".html"))continue;let s=te(o,n),i=v(s);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(Zr(s),t=!0)}return t}function cs(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(b(s))try{let i=JSON.parse(v(s));ms(i)&&(M(s,JSON.stringify(i,null,2)+`
|
|
310
|
+
`),t=!0)}catch{}}return t}function ea(e){let t=!1,o=te(e,"css");if(b(o))for(let s of De(o)){if(!s.endsWith(".css"))continue;let i=te(o,s),a=v(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(M(i,r),t=!0)}let n=te(e,"modules");if(b(n))for(let s of De(n)){if(!s.endsWith(".module"))continue;let i=te(n,s,"module.css");if(!b(i))continue;let a=v(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(M(i,r),t=!0)}if(b(n))for(let s of De(n)){if(!s.endsWith(".module"))continue;let i=te(n,s,"module.html");if(!b(i))continue;let a=v(i),r=a.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");r!==a&&(M(i,r),t=!0)}return t}function ds(e){let t=!1,o=te(e,"modules");if(!b(o))return!1;for(let n of De(o)){if(!n.endsWith(".module"))continue;let s=te(o,n,"fields.json");if(b(s))try{let i=JSON.parse(v(s));us(i)&&(M(s,JSON.stringify(i,null,2)+`
|
|
311
|
+
`),t=!0)}catch{}}return t}function us(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;if(n.type==="color"&&n.default&&typeof n.default=="object"){let s=n.default,i=s.color;if(typeof i=="string"&&!ta(i)){let a=na(i);a&&(s.color=a.hex,a.opacity!==void 0&&(s.opacity=a.opacity),t=!0)}}Array.isArray(n.children)&&us(n.children)&&(t=!0)}return t}function ta(e){return/^#[0-9a-fA-F]{6}$/.test(e)}function na(e){let t=e.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);if(t)return{hex:`#${t[1]}${t[1]}${t[2]}${t[2]}${t[3]}${t[3]}`};let o=e.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/i);if(o){let i=Math.min(255,parseInt(o[1])),a=Math.min(255,parseInt(o[2])),r=Math.min(255,parseInt(o[3])),l=`#${i.toString(16).padStart(2,"0")}${a.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}`,c=o[4]!==void 0?Math.round(parseFloat(o[4])*100):void 0;return{hex:l,opacity:c}}let n={white:"#ffffff",black:"#000000",red:"#ff0000",green:"#008000",blue:"#0000ff",yellow:"#ffff00",orange:"#ffa500",purple:"#800080",gray:"#808080",grey:"#808080",transparent:"#000000"},s=e.toLowerCase().trim();return n[s]?{hex:n[s],opacity:s==="transparent"?0:void 0}:null}function ms(e){let t=!1;for(let o of e){if(typeof o!="object"||o===null)continue;let n=o;if(n.type==="link"){let s=n.default;if(typeof s=="string"||s===void 0||s===null||typeof s=="object"&&!s.url){let a=typeof s=="string"?s:"";n.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},t=!0}}Array.isArray(n.children)&&ms(n.children)&&(t=!0)}return t}Z();h();Ye();Ye();import{readdirSync as oa}from"fs";import{join as sa,relative as ia}from"path";var ra=new Set([".git","node_modules",".vibespot",".DS_Store"]);function ps(e){let t=[];for(let o of oa(e,{withFileTypes:!0})){if(ra.has(o.name)||o.name.startsWith(".")&&o.name!==".gitkeep")continue;let n=sa(e,o.name);o.isDirectory()?t.push(...ps(n)):o.isFile()&&t.push(n)}return t}async function aa(e,t,o){let n=0;async function s(){for(;n<e.length;){let a=n++;await o(e[a])}}let i=Array.from({length:Math.min(t,e.length)},()=>s());await Promise.all(i)}async function pn(e,t,o,n={}){let s=n.concurrency??5,i=ps(t),a=i.length,r=0,l=0,c=[];return await aa(i,s,async u=>{let p=ia(t,u).replace(/\\/g,"/"),f=`${o}/${p}`;n.onFileStart?.(p);let g=await Oo(e,f,u);if(g.success)r++,n.onFileComplete?.(p);else{l++;let y={file:p,status:g.error?.status||0,message:g.error?.message||"Unknown error",category:g.error?.category,detail:g.error?.detail};c.push(y),n.onFileError?.(p,y)}n.onProgress?.(r+l,a)}),{success:l===0,uploaded:r,failed:l,total:a,errors:c}}function ca(e){return(e.match(/^Uploaded file /gm)||[]).length}async function lt(e){await re("Uploading to HubSpot");let t=la(e)||e,o=N(),n=ue(),s=o.hubspotUploadMode!=="cli"&&!!n,i=await le(),a=3;for(let r=1;r<=a;r++){i.start(r===1?"Uploading theme...":`Retrying upload (attempt ${r}/${a})...`);let l=[],c=0,u=!1;if(s){let f=await pn(n,e,t,{onFileComplete:()=>{c++}});u=f.success,u?c=f.uploaded:l=dn(f.errors)}else{let f=A(`hs cms upload "${e}" "${t}"`,{cwd:fs(e,"..")}),g=[f.stdout,f.stderr].filter(Boolean).join(`
|
|
312
|
+
`);c=ca(g),u=f.success,u||(l=un(g))}if(u)return i.stop(`All files uploaded! (${c} files)`),await ae("Upload complete!"),!0;if(c>0?i.stop(`${c} files uploaded, but some errors occurred`):i.stop("Upload failed"),l.length===0){if(D("Upload failed with unknown error."),c>0&&(W(`Most files uploaded successfully. The theme may already be usable in HubSpot.
|
|
313
|
+
You can check your HubSpot Design Manager to verify.`),await ee({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(r<a){if(!await ee({message:"Try uploading again?"}))break;continue}break}let p=!1;for(let f of l)f.fixable?ss(e,f)?(P(`Auto-fixed: ${f.message}`),p=!0):W(`Could not auto-fix: ${f.message}`):D(f.message);if(!(p&&r<a)){if(c>0&&(W(`${c} files uploaded successfully despite errors.
|
|
314
|
+
The theme may work \u2014 check HubSpot Design Manager.`),await ee({message:"Continue anyway?",initialValue:!0})))return!0;if(!p){if(i.start("Cleaning up stuck modules..."),s)try{await Jn(n,`${t}/modules`)}catch{}else A(`hs cms delete "${t}/modules"`,{cwd:fs(e,"..")});i.stop("Cleaned up modules, retrying...")}}}return D("Upload failed after multiple attempts."),!1}h();import{execSync as Un}from"child_process";import{rmSync as da}from"fs";import{basename as gs}from"path";Q();async function hs(e){let{portalId:t,sourceDir:o,themePath:n,wasCloned:s}=e;await re("You're all set!");let a=wt(t)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await Ee(`Your React page has been converted and uploaded to HubSpot.
|
|
294
315
|
The theme and modules are now in your account, but you still
|
|
295
|
-
need to ${
|
|
316
|
+
need to ${C.bold("create a new landing page")} that uses them.
|
|
296
317
|
|
|
297
318
|
Next steps:
|
|
298
319
|
|
|
299
|
-
${
|
|
300
|
-
${
|
|
301
|
-
${
|
|
302
|
-
${
|
|
303
|
-
${
|
|
304
|
-
${
|
|
305
|
-
${
|
|
306
|
-
`),"utf-8")}function
|
|
307
|
-
`)){let i=s.split("|");if(i.length<4)continue;let
|
|
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+`
|
|
320
|
+
${C.bold("1.")} Go to HubSpot ${C.muted("\u2192")} Content ${C.muted("\u2192")} Landing Pages ${C.muted("\u2192")} Create
|
|
321
|
+
${C.bold("2.")} Choose your uploaded theme from the theme picker
|
|
322
|
+
${C.bold("3.")} Select the landing page template that was just created
|
|
323
|
+
${C.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
|
|
324
|
+
${C.bold("5.")} Click each section to edit text, images, and colors
|
|
325
|
+
${C.bold("6.")} Upload images via File Manager ${C.muted("(Settings \u2192 Files)")}
|
|
326
|
+
${C.bold("7.")} Preview and publish!`,"What's next"),await ee({message:"Open HubSpot Landing Pages in your browser?"})){let c=t?`https://${a}/page-ui/${t}/management/pages/landing`:`https://${a}`;try{let u=process.platform;u==="darwin"?Un(`open "${c}"`):u==="win32"?Un(`cmd /c start "${c}"`):Un(`xdg-open "${c}"`),P("Opening HubSpot Landing Pages...")}catch{B(`Open this URL in your browser: ${C.info(c)}`)}}let l=[];if(s&&b(o)&&l.push({path:o,label:`Cloned source (${gs(o)})`}),b(n)&&l.push({path:n,label:`Theme directory (${gs(n)})`}),l.length>0&&await ee({message:"Clean up local working directories?"}))for(let u of l)try{da(u.path,{recursive:!0,force:!0}),P(`Removed ${u.label}`)}catch{W(`Could not remove ${u.label} \u2014 delete manually if needed.`)}await ae(`Thanks for using hub${C.vibes("Vibes")}! ${C.vibes("~")}`)}Z();async function ys(){Te();let e=await qt(),t=await Xt();z({lastSourcePath:t.sourceDir});let o=await tn();z({lastThemePath:o.themePath}),await cn({aiEngine:e.aiEngine,model:e.model,sourceDir:t.sourceDir,themePath:o.themePath}),await lt(o.themePath),await hs({portalId:e.portalId,sourceDir:t.sourceDir,themePath:o.themePath,wasCloned:t.wasCloned})}h();async function bs(){Te(),await qt()}h();Z();async function Ss(){Te();let e=N();e.aiEngine||(D("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let t=await Xt(),o=await tn();await cn({aiEngine:e.aiEngine,sourceDir:t.sourceDir,themePath:o.themePath})}h();Z();async function vs(){Te();let e=N();if(e.lastThemePath)if(await ee({message:`Upload from ${e.lastThemePath}?`}))await lt(e.lastThemePath);else{let o=await ve({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await lt(o)}else{let t=await ve({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:o=>o.trim()?void 0:"Path is required"});await lt(t)}}h();Z();async function ws(){Te(),await re("Environment Diagnostics");let e=0,t=bt();t.found?Kt(t.version)?P(`Node.js v${t.version}`):(W(`Node.js v${t.version} \u2014 too old (need 18+)`),B(" Update at https://nodejs.org"),e++):(D("Node.js \u2014 not installed"),B(" Install from https://nodejs.org"),e++);let o=St();o.found?P(`Git ${o.version}`):(D("Git \u2014 not installed"),B(" Install from https://git-scm.com"),e++);let n=$e();if(!n.found)W("HubSpot CLI \u2014 not installed (only needed for deployment)"),B(" Install: npm install -g @hubspot/cli");else if(!_o(n.version))W(`HubSpot CLI v${n.version} \u2014 too old (need v8+)`),B(" Update: npm install -g @hubspot/cli@latest"),e++;else{P(`HubSpot CLI v${n.version}`);let f=ke();f.authenticated?P(`HubSpot portal${f.portalName?`: ${f.portalName}`:""} (ID: ${f.portalId})`):(W("HubSpot \u2014 not authenticated"),B(" Run: hs init"))}let s=vt();s.found?P(`Claude Code ${s.version} at ${s.path}`):B(C.muted("Claude Code \u2014 not installed"));let i=xt();i.found?P(`Gemini CLI ${i.version} at ${i.path}`):B(C.muted("Gemini CLI \u2014 not installed"));let a=Ct();a.found?P(`OpenAI Codex ${a.version} at ${a.path}`):B(C.muted("OpenAI Codex \u2014 not installed"));let r=N(),l=!!(r.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(r.openaiApiKey||process.env.OPENAI_API_KEY),u=!!(r.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?P("Anthropic API key configured"):B(C.muted("Anthropic API key \u2014 not set")),c?P("OpenAI API key configured"):B(C.muted("OpenAI API key \u2014 not set")),u?P("Google AI API key configured"):B(C.muted("Google AI API key \u2014 not set"));let p={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"};r.aiEngine&&P(`AI engine: ${p[r.aiEngine]||r.aiEngine}`),r.lastThemePath&&B(C.muted(`Last theme: ${r.lastThemePath}`)),!s.found&&!i.found&&!a.found&&!l&&!c&&!u&&(W("No AI engine available"),B(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),B(" Or install: Claude Code \u2014 https://claude.ai/code"),B(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),B(" Codex CLI \u2014 https://github.com/openai/codex"),e++),console.log(),e===0?await ae("Everything looks good!"):await ae(C.warn(`${e} issue${e>1?"s":""} found \u2014 see above`))}h();import{join as En}from"path";import{existsSync as Jl}from"fs";import{execSync as bo}from"child_process";import Nn from"chalk";h();import{createServer as Nl}from"http";import{readFileSync as ho,existsSync as yo}from"fs";import{join as kn,extname as mr}from"path";import{createHash as _l}from"crypto";import{WebSocketServer as Rl}from"ws";h();import{readFileSync as fe,readdirSync as Ue,existsSync as J,writeFileSync as ne,mkdirSync as Ge,rmSync as Et,renameSync as Bn}from"fs";import{join as x,dirname as fa}from"path";import{homedir as ga}from"os";h();import{existsSync as Je,writeFileSync as ua,mkdirSync as ma}from"fs";import{join as _e}from"path";var fn=null;function xe(){return fn!==null||(fn=A("git --version").success),fn}function Wn(e){if(!xe())return!1;if(Je(_e(e,".git")))return xs(e),!0;let t=A("git init",{cwd:e});return t.success?(pa(e),xs(e),A("git add -A",{cwd:e}),A('git commit -m "Initial theme"',{cwd:e}),!0):(console.warn(`[project-git] git init failed in ${e}: ${t.stderr}`),!1)}function xs(e){let t=_e(e,".vibespot");Je(t)||ma(t,{recursive:!0})}function pa(e){let t=_e(e,".gitignore");ua(t,[".vibespot/","node_modules/",""].join(`
|
|
327
|
+
`),"utf-8")}function Kn(e,t){if(!xe()||!Je(_e(e,".git"))||(A("git add -A",{cwd:e}),A("git diff --cached --quiet",{cwd:e}).success))return null;let n=t.length>72?t.slice(0,69)+"...":t,s=A(`git commit -m "${n.replace(/"/g,'\\"')}"`,{cwd:e});if(!s.success)return console.warn(`[project-git] commit failed: ${s.stderr}`),null;let i=A("git rev-parse --short HEAD",{cwd:e});return i.success?i.stdout:null}function Cs(e,t,o,n){if(!xe()||!Je(_e(e,".git")))return null;for(let p of n){let f=_e(e,p);Je(f)&&A(`git add "${p}"`,{cwd:e})}if(A("git diff --cached --quiet",{cwd:e}).success)return null;let i=`[${t}] `,a=72-i.length,r=o.length>a?o.slice(0,a-3)+"...":o,l=i+r,c=A(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:e});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let u=A("git rev-parse --short HEAD",{cwd:e});return u.success?u.stdout:null}function As(e,t=50){if(!xe())return[];if(!Je(_e(e,".git")))return[];let o=A(`git log --pretty=format:"%h|%H|%s|%at" -n ${t}`,{cwd:e});if(!o.success||!o.stdout.trim())return[];let n=[];for(let s of o.stdout.split(`
|
|
328
|
+
`)){let i=s.split("|");if(i.length<4)continue;let a=parseInt(i[3],10)*1e3;n.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:a,date:new Date(a).toISOString()})}return n}function Is(e,t,o=50){if(!xe())return[];if(!Je(_e(e,".git")))return[];let n=t.replace(/[[\]\\]/g,"\\$&"),s=A(`git log --grep="\\[${n}\\]" --pretty=format:"%h|%H|%s|%at" -n ${o}`,{cwd:e});if(!s.success||!s.stdout.trim())return[];let i=[];for(let a of s.stdout.split(`
|
|
329
|
+
`)){let r=a.split("|");if(r.length<4)continue;let l=parseInt(r[3],10)*1e3;i.push({hash:r[0],fullHash:r[1],message:r[2],timestamp:l,date:new Date(l).toISOString()})}return i}function Ts(e,t){if(!xe())return{success:!1,error:"Git not available"};if(!Je(_e(e,".git")))return{success:!1,error:"Not a git repo"};let o=A(`git cat-file -t ${t}`,{cwd:e});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${t} not found`};let n=A(`git log --format="%s" -1 ${t}`,{cwd:e}),s=n.success?n.stdout:t,i=A(`git checkout ${t} -- .`,{cwd:e});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let a=`Rollback to: ${s}`.slice(0,72);return A(`git commit -m "${a.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}function $s(e,t,o,n){if(!xe())return{success:!1,error:"Git not available"};if(!Je(_e(e,".git")))return{success:!1,error:"Not a git repo"};let s=A(`git cat-file -t ${o}`,{cwd:e});if(!s.success||s.stdout.trim()!=="commit")return{success:!1,error:`Commit ${o} not found`};let i=A(`git log --format="%s" -1 ${o}`,{cwd:e}),a=i.success?i.stdout:o,r=0;for(let u of n)A(`git checkout ${o} -- "${u}"`,{cwd:e}).success&&r++;if(r===0)return{success:!1,error:"No files could be restored from that commit"};A("git add -A",{cwd:e});let c=`${`[${t}] `}Rollback to: ${a}`.slice(0,72);return A(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:e}),{success:!0}}var q=x(ga(),".vibespot","sessions"),Yn=x(q,"_index.json"),ct=null;function gn(){if(ct)return ct;try{return J(Yn)?(ct=JSON.parse(fe(Yn,"utf-8")),ct):Vn()}catch{return Vn()}}function hn(e){ct=e;try{Ge(q,{recursive:!0}),ne(Yn,JSON.stringify(e),"utf-8")}catch{}}function Vn(){if(!J(q))return[];let e=[];for(let t of Ue(q).filter(o=>o.endsWith(".json")&&o!=="_index.json"))try{let o=JSON.parse(fe(x(q,t),"utf-8")),n=o.templates||[];e.push({id:o.id,themeName:o.themeName,updatedAt:o.updatedAt,moduleCount:n.reduce((s,i)=>s+(i.modules?.length||0),0),templateCount:n.length})}catch{}return ct=e,hn(e),e}function ha(e){let t=gn(),o=e.templates||[],n={id:e.id,themeName:e.themeName,updatedAt:e.updatedAt,moduleCount:o.reduce((i,a)=>i+(a.modules?.length||0),0),templateCount:o.length},s=t.findIndex(i=>i.id===e.id);s>=0?t[s]=n:t.push(n),hn(t)}function ya(e){let t=gn().filter(o=>o.id!==e);hn(t)}function ba(e){let t=gn().filter(o=>o.themeName!==e);hn(t)}var m=null;function Nt(e,t){let o={id:Ea(),themePath:e,themeName:t,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return m=o,Wn(e),o}function Es(e){if(e.templates&&e.templates.length>0)return;if(!e.modules||e.modules.length===0){e.templates=[],e.activeTemplateId="";return}let t=`lp-${e.themeName}`,o={id:t,label:`${e.themeName} Landing Page`,pageType:"landing_page",templateFile:`templates/lp-${e.themeName}.html`,modules:[...e.modules],moduleOrder:[...e.moduleOrder],sharedCss:e.sharedCss||"",sharedJs:e.sharedJs||"",template:e.template||"",messages:[...e.messages]};e.templates=[o],e.activeTemplateId=t}function Fe(){return!m||!m.activeTemplateId||!m.templates?.length?null:m.templates.find(e=>e.id===m.activeTemplateId)||null}function zn(e){if(!m)return!1;let t=m.templates.find(o=>o.id===e);return t?(m.activeTemplateId=e,_t(t),m.updatedAt=Date.now(),!0):!1}function Ns(e,t){if(!m)throw new Error("No active session");let o=t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),s=`${e==="blog_post"?"bp":e==="website_page"?"wp":e==="module_only"?"mo":"lp"}-${o}`,i={id:s,label:t,pageType:e,templateFile:e==="module_only"?"":`templates/${s}.html`,modules:[],moduleOrder:[],sharedCss:"",sharedJs:"",template:"",messages:[]};return m.templates.push(i),m.activeTemplateId=s,_t(i),m.updatedAt=Date.now(),i}function _s(e,t){if(!m)return null;let o=m.templates.find(l=>l.id===e);if(!o)return null;let n=t||`${o.label} (Copy)`,s=n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),a=`${o.pageType==="blog_post"?"bp":o.pageType==="website_page"?"wp":o.pageType==="module_only"?"mo":"lp"}-${s}`,r={id:a,label:n,pageType:o.pageType,templateFile:o.pageType==="module_only"?"":`templates/${a}.html`,modules:o.modules.map(l=>({...l})),moduleOrder:[...o.moduleOrder],sharedCss:o.sharedCss,sharedJs:o.sharedJs,template:o.template,messages:[]};return m.templates.push(r),m.activeTemplateId=a,_t(r),m.updatedAt=Date.now(),r}function Rs(e,t){if(!m)return!1;let o=m.templates.find(n=>n.id===e);return o?(o.label=t,m.updatedAt=Date.now(),!0):!1}function Ps(e){if(!m)return!1;let t=m.templates.findIndex(o=>o.id===e);return t<0?!1:(m.templates.splice(t,1),m.activeTemplateId===e&&(m.templates.length>0?zn(m.templates[0].id):(m.activeTemplateId="",m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",m.messages=[])),m.updatedAt=Date.now(),!0)}function dt(){if(!m)return[];let e=new Map;for(let t of m.templates)for(let o of t.modules){let n=e.get(o.moduleName);n?n.usedIn.push(t.label):e.set(o.moduleName,{module:o,usedIn:[t.label]})}return Array.from(e.values())}function _t(e){m&&(m.modules=e.modules,m.moduleOrder=e.moduleOrder,m.sharedCss=e.sharedCss,m.sharedJs=e.sharedJs,m.template=e.template,m.messages=e.messages)}function Ve(){if(!m)return;let e=Fe();e&&(e.modules=m.modules,e.moduleOrder=m.moduleOrder,e.sharedCss=m.sharedCss,e.sharedJs=m.sharedJs,e.template=m.template,e.messages=m.messages)}function $(){return m}function ze(e,t){m&&(m.messages.push({role:e,content:t,timestamp:Date.now()}),m.updatedAt=Date.now(),Ve(),wa())}function Os(e){m&&(m.assets||(m.assets=[]),m.assets.push(e),m.updatedAt=Date.now(),j())}function yn(e){if(m){if(e.sharedCss!==void 0&&(m.sharedCss=e.sharedCss),e.sharedJs!==void 0&&(m.sharedJs=e.sharedJs),e.template!==void 0&&(m.template=e.template),e.modules)for(let t of e.modules){let o=m.modules.findIndex(n=>n.moduleName===t.moduleName);o>=0?m.modules[o]=t:(m.modules.push(t),m.moduleOrder.push(t.moduleName))}m.updatedAt=Date.now(),Ve()}}function Ms(e){m&&(m.moduleOrder=e,m.updatedAt=Date.now(),Ve())}function js(e){m&&(m.modules=m.modules.filter(t=>t.moduleName!==e),m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),Ve())}function Ds(e){m&&(m.moduleOrder=m.moduleOrder.filter(t=>t!==e),m.updatedAt=Date.now(),Ve())}function Js(e,t,o){if(!m)return;let n=m.modules.find(s=>s.moduleName===e);if(n)try{let s=JSON.parse(n.fieldsJson);Us(s,t,o),n.fieldsJson=JSON.stringify(s,null,2),m.updatedAt=Date.now(),Ve()}catch{}}function be(){if(!m)return[];let e=[];for(let t of m.moduleOrder){let o=m.modules.find(n=>n.moduleName===t);o&&e.push(o)}for(let t of m.modules)m.moduleOrder.includes(t.moduleName)||e.push(t);return e}function Sa(e,t){let o=ie(e);if(!o||t==="home.html"||t.endsWith("-listing.html"))return null;let n=t.replace(/\.html$/,""),s="landing_page";n.startsWith("bp-")?s="blog_post":n.startsWith("wp-")?s="website_page":n.startsWith("mo-")&&(s="module_only");let i=n,a=o.match(/<!--[\s\S]*?label:\s*"?([^"\n]+)"?\s*[\s\S]*?-->/);a&&(i=a[1].trim());let r=/dnd_module\s+path=["']\.\.\/modules\/(.+?)\.module["']/g,l=[],c;for(;(c=r.exec(o))!==null;)l.push(c[1]);return{id:n,label:i,pageType:s,moduleNames:l,templateContent:o,filename:t}}function va(e,t,o,n,s){if(!J(e))return[];let i=[],a=Ue(e).filter(r=>r.endsWith(".html")&&r!=="home.html");for(let r of a){let l=x(e,r),c=Sa(l,r);if(!c||c.moduleNames.length===0&&i.length>0)continue;let u=[],p=[];for(let f of c.moduleNames){let g=t.get(f);g&&(u.push(g),p.push(f))}i.push({id:c.id,label:c.label,pageType:c.pageType,templateFile:`templates/${c.filename}`,modules:u,moduleOrder:p,sharedCss:o,sharedJs:n,template:c.templateContent,messages:i.length===0?[...s]:[]})}return i}function Rt(e){if(!m)return;let t=xa(e);t.length>0&&m.messages.length===0&&(m.messages=t),Wn(e);let o=x(e,"modules");if(!J(o))return;let n=Ue(o,{withFileTypes:!0});for(let g of n){if(!g.isDirectory()||!g.name.endsWith(".module"))continue;let y=x(o,g.name),S=g.name.replace(/\.module$/,""),w={moduleName:S,fieldsJson:ie(x(y,"fields.json")),metaJson:ie(x(y,"meta.json")),moduleHtml:ie(x(y,"module.html")),moduleCss:ie(x(y,"module.css")),moduleJs:ie(x(y,"module.js"))||void 0};w.fieldsJson&&w.moduleHtml&&(m.modules.push(w),m.moduleOrder.push(S))}let s=x(e,"css"),i=x(e,"js"),a="",r="";if(J(s)){let g=Ue(s).filter(y=>y.endsWith("-theme.css"));g.length>0&&(a=ie(x(s,g[0])),m.sharedCss=a)}if(J(i)){let g=Ue(i).filter(y=>y.endsWith("-animations.js"));g.length>0&&(r=ie(x(i,g[0])),m.sharedJs=r)}let l=x(e,".vibespot","styleguide.md"),c=x(e,".vibespot","brandvoice.md");(J(l)||J(c))&&(m.brandAssets||(m.brandAssets={}),J(l)&&(m.brandAssets.styleguide=ie(l)),J(c)&&(m.brandAssets.brandvoice=ie(c)));let u=x(e,"templates"),p=new Map(m.modules.map(g=>[g.moduleName,g])),f=va(u,p,a,r,m.messages);if(f.length>0){m.templates=f,m.activeTemplateId=f[0].id;let g=f[0].moduleOrder;if(g.length>0){let y=new Set(m.moduleOrder),S=g.filter(w=>y.has(w));for(let w of m.moduleOrder)S.includes(w)||S.push(w);m.moduleOrder=S}_t(f[0])}else m.templates||(m.templates=[]),m.activeTemplateId||(m.activeTemplateId=""),Es(m)}function j(){if(!m)return;Ge(q,{recursive:!0});let e=x(q,`${m.id}.json`);ne(e,JSON.stringify(m,null,2),"utf-8"),ha(m)}function bn(e){let t=x(q,e+".json");if(!J(t))return null;try{let o=JSON.parse(fe(t,"utf-8"));return o.templates||(o.templates=[]),o.activeTemplateId||(o.activeTemplateId=""),Es(o),m=o,o}catch{return null}}function ut(){return J(q)?gn():[]}function Fs(e,t=!1){let o=x(q,e+".json"),n="";if(t)try{let s=JSON.parse(fe(o,"utf-8"));n=s.themeName||"",s.themePath&&J(s.themePath)&&Et(s.themePath,{recursive:!0,force:!0})}catch{}else try{n=JSON.parse(fe(o,"utf-8")).themeName||""}catch{}try{J(o)&&Et(o)}catch{}if(n&&J(q)){for(let s of Ue(q).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(fe(x(q,s),"utf-8")).themeName===n&&Et(x(q,s))}catch{}ba(n)}else ya(e);m?.id===e&&(m=null)}function Hs(e,t){let o=x(q,e+".json");if(!J(o))return{ok:!1,error:"Session not found"};let n;try{n=JSON.parse(fe(o,"utf-8"))}catch{return{ok:!1,error:"Failed to read session"}}let s=n.themeName;if(s===t)return{ok:!0};let i=n.themePath,a=x(fa(i),t);if(J(i)){if(J(a))return{ok:!1,error:"A project with that name already exists"};try{Bn(i,a)}catch(f){return{ok:!1,error:`Failed to rename folder: ${f instanceof Error?f.message:String(f)}`}}let r=x(a,"css",`${s}-theme.css`),l=x(a,"css",`${t}-theme.css`);if(J(r))try{Bn(r,l)}catch{}let c=x(a,"js",`${s}-animations.js`),u=x(a,"js",`${t}-animations.js`);if(J(c))try{Bn(c,u)}catch{}let p=x(a,"theme.json");if(J(p))try{let f=JSON.parse(fe(p,"utf-8"));f.label=t,f.name=t,ne(p,JSON.stringify(f,null,2),"utf-8")}catch{}}if(J(q))for(let r of Ue(q).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(fe(x(q,r),"utf-8"));l.themeName===s&&(l.themeName=t,l.themePath=a,l.updatedAt=Date.now(),ne(x(q,r),JSON.stringify(l,null,2),"utf-8"))}catch{}return m&&m.themeName===s&&(m.themeName=t,m.themePath=a,m.updatedAt=Date.now()),Vn(),{ok:!0}}function We(){if(!m)return;let e=m.themePath,t=new Map;if(m.templates.length>0)for(let r of m.templates)for(let l of r.modules)t.set(l.moduleName,l);for(let r of m.modules)t.set(r.moduleName,r);let o=x(e,"modules");Ge(o,{recursive:!0});for(let r of t.values())Ge(x(o,`${r.moduleName}.module`),{recursive:!0});for(let r of t.values()){let l=x(o,`${r.moduleName}.module`);ne(x(l,"fields.json"),r.fieldsJson,"utf-8"),ne(x(l,"meta.json"),r.metaJson,"utf-8"),ne(x(l,"module.html"),r.moduleHtml,"utf-8"),ne(x(l,"module.css"),r.moduleCss,"utf-8"),r.moduleJs&&ne(x(l,"module.js"),r.moduleJs,"utf-8")}if(m.sharedCss){let r=x(e,"css");Ge(r,{recursive:!0}),ne(x(r,`${m.themeName}-theme.css`),m.sharedCss,"utf-8")}if(m.sharedJs){let r=x(e,"js");Ge(r,{recursive:!0}),ne(x(r,`${m.themeName}-animations.js`),m.sharedJs,"utf-8")}let n=x(e,"templates");Ge(n,{recursive:!0});let s=x(n,"home.html");(m.templates.length>0||m.modules.length>0)&&J(s)&&Et(s,{force:!0});let a=new Set;if(m.templates.length>0)for(let r of m.templates){if(r.pageType==="module_only"||r.modules.length===0)continue;let l=r.template||Ia(r),c=ks(l,r.label,r.pageType),u=`${r.id}.html`;ne(x(n,u),c,"utf-8"),a.add(u),r.pageType==="blog_post"&&(Ta(n,r),a.add(`${r.id}-listing.html`))}else if(m.modules.length>0){let r=m.template||ka(),l=ks(r,`${m.themeName} Landing Page`),c=`lp-${m.themeName}.html`;ne(x(n,c),l,"utf-8"),a.add(c)}try{for(let r of Ue(n))r.startsWith("lp-")&&r.endsWith(".html")&&!a.has(r)&&Et(x(n,r),{force:!0})}catch{}Ca(),Aa()}function wa(){if(m)try{let e=x(m.themePath,".vibespot");Ge(e,{recursive:!0});let t={sessionId:m.id,themeName:m.themeName,messages:m.messages,updatedAt:Date.now()};ne(x(e,"chat.json"),JSON.stringify(t,null,2),"utf-8")}catch{}}function xa(e){let t=x(e,".vibespot","chat.json");if(!J(t))return[];try{let o=JSON.parse(fe(t,"utf-8"));return Array.isArray(o.messages)?o.messages:[]}catch{return[]}}function Ls(){m&&(m.modules=[],m.moduleOrder=[],m.sharedCss="",m.sharedJs="",m.template="",Rt(m.themePath),m.updatedAt=Date.now(),Ve())}function Gs(){if(!m)return;let e=Fe();if(!e)return;let t=m.themePath,o=x(t,"modules");e.modules=[];for(let n of e.moduleOrder){let s=x(o,`${n}.module`);if(!J(s))continue;let i={moduleName:n,fieldsJson:ie(x(s,"fields.json")),metaJson:ie(x(s,"meta.json")),moduleHtml:ie(x(s,"module.html")),moduleCss:ie(x(s,"module.css")),moduleJs:ie(x(s,"module.js"))||void 0};i.fieldsJson&&i.moduleHtml&&e.modules.push(i)}if(e.templateFile){let n=x(t,e.templateFile);J(n)&&(e.template=ie(n))}_t(e),m.updatedAt=Date.now()}function Ca(){if(!m)return;let e=x(m.themePath,"templates","layouts","base.html");if(J(e))try{let t=fe(e,"utf-8");if(t.includes("template_js"))return;let o='{{ require_js(get_asset_url("../../js/main.js")) }}';t.includes(o)?t=t.replace(o,o+`
|
|
309
330
|
{% if template_js %}
|
|
310
331
|
{{ require_js(get_asset_url(template_js)) }}
|
|
311
332
|
{% endif %}`):t=t.replace("{{ standard_footer_includes }}",`{% if template_js %}
|
|
312
333
|
{{ require_js(get_asset_url(template_js)) }}
|
|
313
334
|
{% endif %}
|
|
314
|
-
{{ standard_footer_includes }}`),
|
|
335
|
+
{{ standard_footer_includes }}`),ne(e,t,"utf-8")}catch{}}function Aa(){if(!m)return;let e=x(m.themePath,"theme.json");if(J(e))try{let t=JSON.parse(fe(e,"utf-8"));t.label=m.themeName,t.name=m.themeName,ne(e,JSON.stringify(t,null,2),"utf-8")}catch{}}function ks(e,t,o="landing_page"){return e.includes("templateType")?e:`<!--
|
|
315
336
|
templateType: ${o==="blog_post"?"blog_post":"page"}
|
|
316
337
|
isAvailableForNewContent: true
|
|
317
338
|
label: "${t}"
|
|
318
339
|
-->
|
|
319
|
-
`+e}function
|
|
340
|
+
`+e}function Ia(e){if(e.modules.length===0)return"";let t=m.themeName,n=$a(e).map(i=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
|
|
320
341
|
{% dnd_module path="../modules/${i.moduleName}.module" %}
|
|
321
342
|
{% end_dnd_module %}
|
|
322
343
|
{% end_dnd_section %}`).join(`
|
|
@@ -347,7 +368,7 @@ ${n}
|
|
|
347
368
|
|
|
348
369
|
{% block footer %}
|
|
349
370
|
{% endblock footer %}
|
|
350
|
-
`}function
|
|
371
|
+
`}function Ta(e,t){let o=`<!--
|
|
351
372
|
templateType: blog_listing
|
|
352
373
|
isAvailableForNewContent: true
|
|
353
374
|
label: "${t.label} - Listing"
|
|
@@ -372,7 +393,7 @@ ${n}
|
|
|
372
393
|
{% endif %}
|
|
373
394
|
</div>
|
|
374
395
|
{% endblock body %}
|
|
375
|
-
`;
|
|
396
|
+
`;ne(x(e,`${t.id}-listing.html`),o,"utf-8")}function $a(e){let t=[];for(let o of e.moduleOrder){let n=e.modules.find(s=>s.moduleName===o);n&&t.push(n)}for(let o of e.modules)e.moduleOrder.includes(o.moduleName)||t.push(o);return t}function ka(){if(!m||m.modules.length===0)return"";let e=m.themeName,o=be().map(n=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
|
|
376
397
|
{% dnd_module path="../modules/${n.moduleName}.module" %}
|
|
377
398
|
{% end_dnd_module %}
|
|
378
399
|
{% end_dnd_section %}`).join(`
|
|
@@ -403,7 +424,7 @@ ${o}
|
|
|
403
424
|
|
|
404
425
|
{% block footer %}
|
|
405
426
|
{% endblock footer %}
|
|
406
|
-
`}function
|
|
427
|
+
`}function Ea(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function ie(e){try{return fe(e,"utf-8")}catch{return""}}function Us(e,t,o){let n=t.split("."),s=n[0],i=e.find(a=>a.name===s);i&&(n.length===1?i.default=o:i.children&&Us(i.children,n.slice(1).join("."),o))}h();h();function Sn(e){let t={};for(let o of e)o.type==="group"&&o.occurrence&&Array.isArray(o.default)?t[o.name]=o.default:o.type==="group"&&o.children?t[o.name]=Sn(o.children):t[o.name]=o.default??"";return t}function Xn(e,t){let o=e;return o=Ja(o),o=Ys(o,t),o=Vs(o,t),o=zs(o,t),o=Ha(o),o}function Qn(e){let t=[e.sharedCss||"",...e.moduleCssArray].filter(Boolean).map(s=>`<style>${s}</style>`).join(`
|
|
407
428
|
`),o=[e.sharedJs||"",...e.moduleJsArray].filter(Boolean).map(s=>`<script>${s}</script>`).join(`
|
|
408
429
|
`),n=e.renderedModules.join(`
|
|
409
430
|
`);return`<!DOCTYPE html>
|
|
@@ -450,7 +471,7 @@ document.querySelectorAll('img').forEach(function(img){
|
|
|
450
471
|
});
|
|
451
472
|
</script>
|
|
452
473
|
</body>
|
|
453
|
-
</html>`}var
|
|
474
|
+
</html>`}var Na=/\{%[-\s]*require_(css|js)\b.*?%\}/gs,_a=/\{%[-\s]*end_require_(css|js)\s*%\}/gs,Ra=/\{\{[-\s]*require_(css|js)\(.*?\)\s*\}\}/gs,Ws=/\{\{[-\s]*get_asset_url\(["'](?:[^"'\/]+\/)?assets\/(.*?)["']\)\s*\}\}/gs,Ks=/\{\{[-\s]*get_asset_url\(.*?\)\s*\}\}/gs,Pa=/\{%[-\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\b.*?%\}/gs,Oa=/\{%[-\s]*module\b.*?%\}/gs,Ma=/\{%[-\s]*(extends|block|endblock|set)\b.*?%\}/gs,ja=/\{#.*?#\}/gs,Da=/\{\{[-\s]*content\.\w+.*?\}\}/gs,qn=/\{%[-\s]*if\s+(.*?)\s*-?%\}([\s\S]*?)\{%[-\s]*endif\s*-?%\}/g;function Ja(e){return e=e.replace(Na,""),e=e.replace(_a,""),e=e.replace(Ra,""),Ws.lastIndex=0,e=e.replace(Ws,(t,o)=>`/theme-assets/${o}`),Ks.lastIndex=0,e=e.replace(Ks,""),e=e.replace(Pa,""),e=e.replace(Oa,""),e=e.replace(Ma,""),e=e.replace(ja,""),e=e.replace(Da,""),e}function Ys(e,t){let o=e,n=0;for(;n<30;){n++;let s=Fa(o);if(!s)break;let{varName:i,iterExpr:a,body:r,start:l,end:c}=s,u=La(a,t),p="";Array.isArray(u)&&(p=u.map((f,g)=>{let y={...t,[i]:f,loop:{index:g+1,index0:g,first:g===0,last:g===u.length-1,length:u.length}},S=Ys(r,y);return S=Vs(S,y),S=zs(S,y),S}).join("")),o=o.slice(0,l)+p+o.slice(c)}return o}function Fa(e){let t=/\{%[-\s]*for\s+(\w+)\s+in\s+([\w.]+(?:\([^)]*\))?(?:\|[\w(),"' ]+)*)\s*-?%\}/g,o=/\{%[-\s]*(for\s|endfor)\s*.*?-?%\}/g,n=t.exec(e);if(!n)return null;let s=n[1],i=n[2],a=n.index+n[0].length;o.lastIndex=a;let r=1,l;for(;(l=o.exec(e))!==null;)if(l[1].startsWith("for"))r++;else if(r--,r===0){let c=e.slice(a,l.index);return{varName:s,iterExpr:i,body:c,start:n.index,end:l.index+l[0].length}}return null}function Vs(e,t){let o=e,n=0;for(;qn.test(o)&&n<50;)n++,o=o.replace(qn,(s,i,a)=>{let r=a.split(/\{%[-\s]*else\s*-?%\}/),l=r[0],c=r[1]||"",u=l.split(/\{%[-\s]*elif\s+(.*?)\s*-?%\}/);if(u.length>1){if(mt(i,t))return u[0];for(let p=1;p<u.length;p+=2){let f=u[p],g=u[p+1]||"";if(mt(f,t))return g}return c}return mt(i,t)?l:c}),qn.lastIndex=0;return o}function zs(e,t){return e.replace(/\{\{[-\s]*(.*?)[-\s]*\}\}/g,(o,n)=>{let i=n.trim().split("|"),a=i[0].trim(),r=qe(t,a);for(let c=1;c<i.length;c++)r=Xs(r,i[c].trim());if(r==null)return"";if(typeof r=="object")return JSON.stringify(r);let l=String(r);return l=l.replace(/\\n/g," ").replace(/\n/g," "),l})}function Ha(e){return e=e.replace(/\{%.*?%\}/gs,""),e=e.replace(/\{\{.*?\}\}/gs,""),e}function La(e,t){let o=e.match(/^range\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);if(o){let s=Bs(o[1],t),i=Bs(o[2],t),a=[];for(let r=s;r<i;r++)a.push(r);return a}let n=e.match(/^(.+?)\|split\(['"](.+?)['"]\)$/);if(n){let s=qe(t,n[1].trim());return typeof s=="string"?s.split(n[2]):[]}return qe(t,e)}function Bs(e,t){let n=e.trim().split("|"),s=n[0].trim();if(!isNaN(Number(s)))return Number(s);let i=qe(t,s);for(let a=1;a<n.length;a++)i=Xs(i,n[a].trim());return Number(i)||0}function qe(e,t){let o=t.split("."),n=e;for(let s of o){if(n==null||typeof n!="object")return;n=n[s]}return n}function mt(e,t){let o=e.trim();if(o.startsWith("not "))return!mt(o.slice(4),t);if(o.includes(" and "))return o.split(" and ").every(i=>mt(i,t));if(o.includes(" or "))return o.split(" or ").some(i=>mt(i,t));let n=o.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);if(n){let i=qe(t,n[1].trim()),a=n[2],r=n[3].trim();switch(typeof r=="string"&&r.startsWith('"')&&r.endsWith('"')||typeof r=="string"&&r.startsWith("'")&&r.endsWith("'")?r=r.slice(1,-1):isNaN(Number(r))?r=qe(t,r):r=Number(r),a){case"==":return i==r;case"!=":return i!=r;case">":return Number(i)>Number(r);case"<":return Number(i)<Number(r);case">=":return Number(i)>=Number(r);case"<=":return Number(i)<=Number(r)}}let s=qe(t,o);return qs(s)}function qs(e){return!(e==null||e===""||e===0||e===!1||Array.isArray(e)&&e.length===0)}function Xs(e,t){let o=e==null?"":String(e),n=t.match(/^(\w+)\((.*)\)$/),s=n?n[1]:t,i=n?n[2].replace(/^["']|["']$/g,""):void 0;switch(s){case"escape":case"e":return o.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");case"lower":return o.toLowerCase();case"upper":return o.toUpperCase();case"capitalize":return o.charAt(0).toUpperCase()+o.slice(1);case"trim":return o.trim();case"truncate":if(i){let a=parseInt(i,10);return o.length>a?o.slice(0,a)+"...":o}return o;case"default":return qs(e)?e:i??"";case"length":return Array.isArray(e)?e.length:o.length;case"join":return Array.isArray(e)?e.join(i??", "):o;case"int":case"float":return Number(o)||0;case"abs":return Math.abs(Number(o));case"round":return Math.round(Number(o));default:return e}}function Zs(){let e=$();if(!e)return Qs();let t=be();if(t.length===0)return Qs();let o=[],n=[],s=[];for(let i of t){if(i.moduleHtml.includes("dnd_area")||i.moduleHtml.includes("extends "))continue;let a;try{let c=JSON.parse(i.fieldsJson);a={module:Sn(c)}}catch{a={module:{}}}let r=Xn(i.moduleHtml,a),l=i.moduleName.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");o.push(`<div class="vibespot-module" id="${l}" data-module="${i.moduleName}">${r}</div>`),i.moduleCss&&n.push(i.moduleCss),i.moduleJs&&s.push(i.moduleJs)}return Qn({renderedModules:o,sharedCss:e.sharedCss,moduleCssArray:n,sharedJs:e.sharedJs,moduleJsArray:s})}function Qs(){return`<!DOCTYPE html>
|
|
454
475
|
<html lang="en">
|
|
455
476
|
<head>
|
|
456
477
|
<meta charset="utf-8">
|
|
@@ -501,7 +522,7 @@ document.querySelectorAll('img').forEach(function(img){
|
|
|
501
522
|
<div class="welcome__sub">Build Something Great</div>
|
|
502
523
|
</div>
|
|
503
524
|
</body>
|
|
504
|
-
</html>`}function
|
|
525
|
+
</html>`}function ei(e){let t=$();if(!t)return"";let o;for(let i of t.templates)if(o=i.modules.find(a=>a.moduleName===e),o)break;if(o||(o=t.modules.find(i=>i.moduleName===e)),!o)return"";let n;try{let i=JSON.parse(o.fieldsJson);n={module:Sn(i)}}catch{n={module:{}}}let s=Xn(o.moduleHtml,n);return Qn({renderedModules:[`<div class="vibespot-module" data-module="${o.moduleName}">${s}</div>`],sharedCss:t.sharedCss,moduleCssArray:o.moduleCss?[o.moduleCss]:[],sharedJs:t.sharedJs,moduleJsArray:o.moduleJs?[o.moduleJs]:[]})}h();Z();import{execSync as ao}from"child_process";h();h();var V={info(e,t,o){let n=o?`[${e}] ${t} ${JSON.stringify(o)}`:`[${e}] ${t}`;console.log(n)},warn(e,t,o){let n=o?`[${e}] ${t} ${JSON.stringify(o)}`:`[${e}] ${t}`;console.warn(n)},error(e,t,o){let n=o instanceof Error?o.message:o?String(o):"",s=n?`[${e}] ${t}: ${n}`:`[${e}] ${t}`;console.error(s)}};function eo(e){try{return JSON.parse(e)}catch{}let t=e,o=-1;for(let n=0;n<20;n++)try{return JSON.parse(t)}catch(s){if(!(s instanceof SyntaxError))return null;let i=/position (\d+)/.exec(s.message);if(!i)return null;let a=parseInt(i[1],10);if(a<=o)return null;o=a;let r=Math.max(0,a-5),c=t.slice(r,a+1).lastIndexOf('"');if(c===-1)return null;let u=r+c;if(u>0&&t[u-1]==="\\")return null;t=t.slice(0,u)+'\\"'+t.slice(u+1)}return null}function Ga(e){let t=e.indexOf('"modules"');if(t===-1)return null;let o=e.indexOf("[",t);if(o===-1)return null;let n=-1,s=0,i=!1,a=!1;for(let u=o+1;u<e.length;u++){let p=e[u];if(a){a=!1;continue}if(p==="\\"){a=!0;continue}if(p==='"'){i=!i;continue}i||(p==="{"&&s++,p==="}"&&(s--,s===0&&(n=u)))}if(n===-1)return null;let l=e.slice(0,n+1)+"]}",c=l.trimStart().startsWith("{")?l:"{"+l;return eo(c)}function Zn(e){return{moduleName:String(e.moduleName||""),fieldsJson:typeof e.fieldsJson=="string"?e.fieldsJson:JSON.stringify(e.fieldsJson,null,2),metaJson:typeof e.metaJson=="string"?e.metaJson:JSON.stringify(e.metaJson,null,2),moduleHtml:String(e.moduleHtml||""),moduleCss:String(e.moduleCss||""),moduleJs:e.moduleJs?String(e.moduleJs):void 0}}function ti(e,t){let o=!1,n,s=/```vibespot-modules\s*\n?([\s\S]*?)```/g;for(;(n=s.exec(e))!==null;)try{V.info("parse","Found vibespot-modules block",{length:n[1].length});let i=eo(n[1]);if(!i||typeof i!="object")throw V.warn("parse","tryParseJSON returned non-object",{result:typeof i}),new Error("Invalid JSON after repair");let a=i;a.modules&&Array.isArray(a.modules)&&(yn({modules:a.modules.map(r=>Zn(r)),sharedCss:a.sharedCss!==void 0?String(a.sharedCss):void 0,sharedJs:a.sharedJs!==void 0?String(a.sharedJs):void 0}),o=!0)}catch(i){V.warn("parse","Failed to parse vibespot-modules block",{error:i instanceof Error?i.message:String(i)})}if(!o){let i=/```(?:json)?\s*\n([\s\S]*?)```/g;for(;(n=i.exec(e))!==null;)if(n[1].includes('"modules"'))try{let a=eo(n[1]);if(!a||typeof a!="object")throw new Error("Invalid JSON after repair");let r=a;r.modules&&Array.isArray(r.modules)&&(yn({modules:r.modules.map(l=>Zn(l)),sharedCss:r.sharedCss!==void 0?String(r.sharedCss):void 0,sharedJs:r.sharedJs!==void 0?String(r.sharedJs):void 0}),o=!0)}catch(a){V.warn("parse","Failed to parse JSON module block",{error:a instanceof Error?a.message:String(a)})}}if(!o&&(e.match(/```/g)||[]).length%2!==0&&e.includes('"modules"')){V.info("parse","Detected truncated response (odd fence count), attempting salvage");let a=e.lastIndexOf("```"),r=e.slice(a+3);r=r.replace(/^[\w-]*\s*\n?/,"");let l=Ga(r);if(l){let c=l;c.modules&&Array.isArray(c.modules)&&c.modules.length>0&&(V.info("parse","Salvaged modules from truncated response",{count:c.modules.length}),yn({modules:c.modules.map(u=>Zn(u)),sharedCss:c.sharedCss!==void 0?String(c.sharedCss):void 0,sharedJs:c.sharedJs!==void 0?String(c.sharedJs):void 0}),o=!0,t&&t("Response was truncated \u2014 some modules may be incomplete. Try sending your request again for the full set."))}}if(!o){V.info("parse","No modules applied",{responseLength:e.length,hasVibespot:e.includes("vibespot-modules"),hasModules:e.includes('"modules"'),fenceCount:(e.match(/```/g)||[]).length});let i=e.includes("vibespot-modules")||e.includes('"modules"'),a=/\bmodule|modul/i.test(e)&&(/\bcreated?\b|\berstellt\b|\bgenerat/i.test(e)||/\|.*\|.*\|/m.test(e));if(i||a){let r=i?"Module changes could not be applied \u2014 the AI response contained invalid JSON. Try sending your request again.":"The AI described modules but did not include the required structured data. Try sending your request again.";V.warn("parse",r),t&&t(r)}}}h();import{spawn as Ua}from"child_process";Z();h();function pt(){let e=$();return e?{pageType:Fe()?.pageType,brandAssets:e.brandAssets}:{}}function ft(e,t,o=!1,n,s){let i=`You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.
|
|
505
526
|
|
|
506
527
|
## Your Role
|
|
507
528
|
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.
|
|
@@ -541,6 +562,7 @@ NEVER respond with only a text summary. The vibespot-modules JSON block is manda
|
|
|
541
562
|
- All assets must be self-contained \u2014 no external HTTP requests in CSS or HTML
|
|
542
563
|
- Use "type": "text" (NEVER "textarea" \u2014 it's deprecated)
|
|
543
564
|
- NEVER use "name": "name" (reserved) \u2014 use "item_name" instead
|
|
565
|
+
- NEVER put literal \\n newline sequences in field default values \u2014 use plain text without line breaks
|
|
544
566
|
- Wrap style fields in a "styles" group with "tab": "STYLE"
|
|
545
567
|
- All CSS classes must use a unique prefix "${t}-" to avoid theme conflicts
|
|
546
568
|
- Use BEM naming: ${t}-module__element--modifier
|
|
@@ -564,30 +586,40 @@ NEVER respond with only a text summary. The vibespot-modules JSON block is manda
|
|
|
564
586
|
- If the user's intent is ambiguous (design reference vs page asset), ask them to clarify
|
|
565
587
|
|
|
566
588
|
## Navigation & Anchor Links
|
|
567
|
-
-
|
|
568
|
-
|
|
569
|
-
- The id
|
|
589
|
+
- For anchor links, add an id attribute directly on the module's root element in module.html:
|
|
590
|
+
<section id="pricing" class="..."> (NOT on an external wrapper \u2014 HubSpot's dnd system strips those)
|
|
591
|
+
- The id should be the moduleName lowercased with spaces replaced by hyphens (e.g. "Pricing Cards" \u2192 id="pricing-cards")
|
|
592
|
+
- For navigation/menu modules, use anchor links that match these ids: e.g. href="#features"
|
|
570
593
|
- Always include smooth scrolling behavior in navigation link clicks
|
|
571
594
|
- For nav modules, make menu items editable via a repeater group with "label" (text) and "anchor" (text) fields
|
|
572
595
|
|
|
573
596
|
## When modifying existing modules
|
|
574
|
-
|
|
575
|
-
|
|
597
|
+
The current template's modules are listed in page order in the user message. This sequence forms the page narrative.
|
|
598
|
+
|
|
599
|
+
- **Modify**: When the user references an existing module by name or describes changes to existing content, update that module's code. Keep the moduleName unchanged.
|
|
600
|
+
- **Add**: When the user asks for a new section, create a new module and insert it at the narratively correct position. Consider the page flow: navigation \u2192 hero \u2192 content sections \u2192 social proof \u2192 CTA \u2192 footer.
|
|
601
|
+
- **Rearrange**: When the user asks to reorder sections, include a "moduleOrder" array in the vibespot-modules JSON with the new sequence of module names.
|
|
602
|
+
- **Remove**: When the user asks to remove a section, omit it from the output.
|
|
603
|
+
- **Preserve**: Always include ALL modules you want to keep (modified + unchanged) in your output. Modules omitted from the output will be removed from the page.
|
|
604
|
+
- **Design consistency**: Match the existing theme's design language \u2014 reuse the same CSS custom properties, class naming prefix, spacing scale, and typography.`,a=n?Yo(n):"",r=a?`
|
|
576
605
|
|
|
577
606
|
## Page Type Context
|
|
578
|
-
${
|
|
607
|
+
${a}`:"",l="";if(s?.styleguide&&(l+=`
|
|
579
608
|
|
|
580
609
|
## Brand Style Guide
|
|
581
610
|
${s.styleguide}`),s?.brandvoice&&(l+=`
|
|
582
611
|
|
|
583
612
|
## Brand Voice
|
|
584
|
-
${s.brandvoice}`),s?.humanify!==!1)
|
|
613
|
+
${s.brandvoice}`),s?.humanify!==!1){let c=Bo();c&&(l+=`
|
|
585
614
|
|
|
586
615
|
## Anti-AI Copy Rules (Humanify)
|
|
587
|
-
${c}`)}return o?i+
|
|
616
|
+
${c}`)}return o?i+r+l+`
|
|
588
617
|
|
|
589
618
|
## HubSpot CMS Rules
|
|
590
|
-
${
|
|
619
|
+
${at()}
|
|
620
|
+
|
|
621
|
+
## Conversion Guide Reference
|
|
622
|
+
${e}`:i+r+l+`
|
|
591
623
|
|
|
592
624
|
## Design Quality
|
|
593
625
|
- Use modern, clean design with proper spacing and typography
|
|
@@ -612,37 +644,43 @@ When using scroll-animate classes (opacity: 0 \u2192 visible), you MUST include
|
|
|
612
644
|
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.
|
|
613
645
|
|
|
614
646
|
## Design Guide
|
|
615
|
-
${
|
|
647
|
+
${Wo()}
|
|
616
648
|
|
|
617
649
|
## Content & Copywriting Guide
|
|
618
|
-
${
|
|
650
|
+
${Ko()}
|
|
619
651
|
|
|
620
652
|
## HubSpot CMS Rules
|
|
621
|
-
${
|
|
653
|
+
${at()}
|
|
622
654
|
|
|
623
655
|
## Conversion Guide Reference
|
|
624
|
-
${e}`}function
|
|
656
|
+
${e}`}function Pt(){let e=$(),t=[],o=e.modules,n=o.length;if(n>0){t.push(`
|
|
625
657
|
|
|
658
|
+
## Page Narrative (module sequence)
|
|
659
|
+
`),t.push(`This template has ${n} module${n===1?"":"s"} in this order:
|
|
660
|
+
`);for(let r=0;r<n;r++)t.push(`${r+1}. ${o[r].moduleName}
|
|
661
|
+
`);t.push(`
|
|
662
|
+
When the user asks to modify this page, decide whether to MODIFY existing modules, ADD new ones at the right narrative position, REARRANGE the sequence, or REMOVE sections. Always include ALL modules you want to keep in your output.
|
|
663
|
+
`),t.push(`
|
|
626
664
|
## Current Module State
|
|
627
|
-
`);for(let
|
|
628
|
-
### ${
|
|
665
|
+
`);for(let r=0;r<n;r++){let l=o[r];t.push(`
|
|
666
|
+
### ${r+1}/${n}: ${l.moduleName}.module
|
|
629
667
|
`),t.push(`**fields.json:**
|
|
630
668
|
\`\`\`json
|
|
631
|
-
${
|
|
669
|
+
${l.fieldsJson}
|
|
632
670
|
\`\`\`
|
|
633
671
|
`),t.push(`**module.html:**
|
|
634
672
|
\`\`\`html
|
|
635
|
-
${
|
|
673
|
+
${l.moduleHtml}
|
|
636
674
|
\`\`\`
|
|
637
675
|
`),t.push(`**module.css:**
|
|
638
676
|
\`\`\`css
|
|
639
|
-
${
|
|
677
|
+
${l.moduleCss}
|
|
640
678
|
\`\`\`
|
|
641
|
-
`),
|
|
679
|
+
`),l.moduleJs&&t.push(`**module.js:**
|
|
642
680
|
\`\`\`js
|
|
643
|
-
${
|
|
681
|
+
${l.moduleJs}
|
|
644
682
|
\`\`\`
|
|
645
|
-
`)
|
|
683
|
+
`)}e.sharedCss&&t.push(`
|
|
646
684
|
### Shared CSS
|
|
647
685
|
\`\`\`css
|
|
648
686
|
${e.sharedCss}
|
|
@@ -652,59 +690,59 @@ ${e.sharedCss}
|
|
|
652
690
|
\`\`\`js
|
|
653
691
|
${e.sharedJs}
|
|
654
692
|
\`\`\`
|
|
655
|
-
`)}let
|
|
693
|
+
`)}let s=dt(),i=new Set(e.modules.map(r=>r.moduleName)),a=s.filter(r=>!i.has(r.module.moduleName));if(a.length>0){t.push(`
|
|
656
694
|
|
|
657
695
|
## Available modules in this theme (reusable)
|
|
658
|
-
`);for(let
|
|
696
|
+
`);for(let r of a)t.push(`- ${r.module.moduleName} (used in: ${r.usedIn.join(", ")})
|
|
659
697
|
`);t.push(`
|
|
660
698
|
The user can ask to reuse any of these modules by name.
|
|
661
|
-
`)}return t.join("")}function
|
|
699
|
+
`)}return t.join("")}function to(e,t){let o=$(),n=o.messages.slice(-20);n.length>0&&n[n.length-1].role==="user"&&n[n.length-1].content===e&&(n=n.slice(0,-1));let s=n.map(u=>({role:u.role,content:u.content})),i=Pt(),a="";if(o.assets?.length){let u=o.assets.filter(p=>p.type==="image"&&p.usage==="asset");u.length>0&&(a=`
|
|
662
700
|
|
|
663
701
|
## Available Theme Assets
|
|
664
702
|
These images are in the theme's assets/ folder. Reference them with get_asset_url("${o.themeName}/assets/filename"):
|
|
665
|
-
${
|
|
666
|
-
`)}`)}let r=e;
|
|
703
|
+
${u.map(p=>`- ${p.filename} (${p.originalName}) \u2192 get_asset_url("${o.themeName}/assets/${p.filename}")`).join(`
|
|
704
|
+
`)}`)}let r=e;i&&(r+=`
|
|
667
705
|
|
|
668
706
|
---
|
|
669
|
-
${
|
|
707
|
+
${i}`),a&&(r+=a);let l=t&&t.length>0;if(l)for(let u of t)u.type==="document"&&u.extractedText&&(r+=`
|
|
670
708
|
|
|
671
709
|
---
|
|
672
|
-
[Attached document: ${
|
|
673
|
-
${
|
|
710
|
+
[Attached document: ${u.originalName}]
|
|
711
|
+
${u.extractedText}`),u.type==="image"&&u.usage==="asset"&&u.assetPath&&(r+=`
|
|
674
712
|
|
|
675
|
-
[Uploaded image: ${
|
|
713
|
+
[Uploaded image: ${u.originalName} \u2192 available as get_asset_url("${u.assetPath}")]`);let c=l?t.filter(u=>u.type==="image"&&u.base64):[];if(c.length>0){let u=[];for(let p of c)u.push({type:"image",source:{type:"base64",media_type:p.mimeType,data:p.base64}});u.push({type:"text",text:r}),s.push({role:"user",content:u})}else s.push({role:"user",content:r});return s}var no=null;async function Wa(){return no||(no=(await import("@anthropic-ai/sdk")).default),no}function ni(e){if(!e?.length)return"";let t=[];for(let o of e)o.type==="image"&&o.usage==="asset"&&o.assetPath&&t.push(`
|
|
676
714
|
[Uploaded image: ${o.originalName} \u2192 use get_asset_url("${o.assetPath}")]`),o.type==="document"&&o.extractedText&&t.push(`
|
|
677
715
|
|
|
678
716
|
---
|
|
679
717
|
[Attached document: ${o.originalName}]
|
|
680
|
-
${o.extractedText}`);return t.join("")}var
|
|
681
|
-
`);
|
|
718
|
+
${o.extractedText}`);return t.join("")}var ce=["Analyzing your request...","Reading the conversion guide...","Planning module structure...","Generating HTML templates...","Writing CSS styles...","Creating field definitions...","Building module metadata...","Assembling theme assets...","Polishing the output...","Almost there \u2014 hang tight..."],oo=[10,20,40,60,120];async function oi(e,t,o,n,s,i,a,r){let l=await Wa(),c=new l({apiKey:t}),u=de(),f=$().modules.length>0,g=to(e,r),y=pt(),S=ft(u,o,f,y.pageType,y.brandAssets);V.info("anthropic","API call",{model:n,systemPromptLength:S.length,messageCount:g.length,messageRoles:g.map(w=>w.role),lastMessageLength:typeof g[g.length-1]?.content=="string"?g[g.length-1].content.length:"multimodal",conversionGuideLength:u.length});for(let w=0;;w++)try{let k="",E=0,R=i||(()=>{});R(ce[0]);let X=setInterval(()=>{E++,R(ce[Math.min(E,ce.length-1)])},6e3);try{let L=c.messages.stream({model:n,max_tokens:48e3,system:S,messages:g});for await(let O of L)if(O.type==="content_block_delta"&&O.delta.type==="text_delta"){let G=O.delta.text;k+=G,s(G)}}finally{clearInterval(X)}a&&a(k);return}catch(k){let E=k.status,R=k.error?.type;if(!(E===429||R==="rate_limit_error"||k instanceof Error&&k.message.includes("429"))||w>=oo.length)throw k;let L=oo[w];V.warn("ai-engine",`Rate limited (429), attempt ${w+1}/${oo.length} \u2014 waiting ${L}s`),i&&i(`Rate limited by Anthropic API \u2014 retrying in ${L}s...`),await new Promise(O=>setTimeout(O,L*1e3)),i&&i("Retrying...")}}async function si(e,t,o,n,s,i,a,r){let l=de(),c=$().modules.length>0,u=to(e,r),p=pt(),f=u.map(L=>typeof L.content=="string"?L:{role:L.role,content:L.content.map(O=>O.type==="text"?{type:"text",text:O.text}:{type:"image_url",image_url:{url:`data:${O.source.media_type};base64,${O.source.data}`}})}),g=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:n,max_tokens:48e3,stream:!0,messages:[{role:"system",content:ft(l,o,c,p.pageType,p.brandAssets)},...f]})});if(!g.ok){let L=await g.text();throw new Error(`OpenAI API error (${g.status}): ${L}`)}let y=0,S=i||(()=>{});S(ce[0]);let w=setInterval(()=>{y++,S(ce[Math.min(y,ce.length-1)])},6e3),k="",E=g.body.getReader(),R=new TextDecoder,X="";try{for(;;){let{done:L,value:O}=await E.read();if(L)break;X+=R.decode(O,{stream:!0});let G=X.split(`
|
|
719
|
+
`);X=G.pop()||"";for(let oe of G){if(!oe.startsWith("data: "))continue;let H=oe.slice(6).trim();if(H==="[DONE]")break;try{let se=JSON.parse(H).choices?.[0]?.delta?.content;se&&(k+=se,s(se))}catch{}}}}finally{clearInterval(w)}a&&a(k)}async function ii(e,t,o,n,s,i,a){let r=de(),l=$(),c=l.modules.length>0,u=Pt(),p=pt(),f=[];for(let H of l.messages.slice(-20))f.push({role:H.role==="assistant"?"model":"user",parts:[{text:H.content}]});let g=u?`${e}
|
|
682
720
|
|
|
683
721
|
---
|
|
684
|
-
${u}`:e;if(
|
|
722
|
+
${u}`:e;if(a?.length)for(let H of a)H.type==="document"&&H.extractedText&&(g+=`
|
|
685
723
|
|
|
686
724
|
---
|
|
687
|
-
[Attached document: ${
|
|
688
|
-
${
|
|
725
|
+
[Attached document: ${H.originalName}]
|
|
726
|
+
${H.extractedText}`),H.type==="image"&&H.usage==="asset"&&H.assetPath&&(g+=`
|
|
689
727
|
|
|
690
|
-
[Uploaded image: ${
|
|
691
|
-
`);
|
|
728
|
+
[Uploaded image: ${H.originalName} \u2192 available as get_asset_url("${H.assetPath}")]`);let y=[];if(a?.length)for(let H of a)H.type==="image"&&H.base64&&y.push({inlineData:{mimeType:H.mimeType,data:H.base64}});y.push({text:g}),f.push({role:"user",parts:y});let w=`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse&key=${t}`,k=await fetch(w,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({systemInstruction:{parts:[{text:ft(r,o,c,p.pageType,p.brandAssets)}]},contents:f,generationConfig:{maxOutputTokens:48e3}})});if(!k.ok){let H=await k.text();throw new Error(`Gemini API error (${k.status}): ${H}`)}let E=0,R=s||(()=>{});R(ce[0]);let X=setInterval(()=>{E++,R(ce[Math.min(E,ce.length-1)])},6e3),L="",O=k.body.getReader(),G=new TextDecoder,oe="";try{for(;;){let{done:H,value:Jt}=await O.read();if(H)break;oe+=G.decode(Jt,{stream:!0});let se=oe.split(`
|
|
729
|
+
`);oe=se.pop()||"";for(let Se of se){if(!Se.startsWith("data: "))continue;let He=Se.slice(6).trim();try{let _n=JSON.parse(He).candidates?.[0]?.content?.parts?.[0]?.text;_n&&(L+=_n,n(_n))}catch{}}}}finally{clearInterval(X)}i&&i(L)}function ri(e,t,o,n){return new Promise((s,i)=>{let a={...process.env};delete a.CLAUDECODE;let r=Ua(e,t,{stdio:["pipe","pipe","pipe"],env:a,shell:!0}),l="",c="";r.stdout.on("data",u=>{let p=u.toString();l+=p,n&&n(p)}),r.stderr.on("data",u=>{c+=u.toString()}),r.on("error",u=>i(new Error(`${e} failed to start: ${u.message}`))),r.on("close",u=>{u!==0?i(new Error(`${e} exited with code ${u}.
|
|
692
730
|
`+(c?`Stderr: ${c.slice(0,500)}
|
|
693
|
-
`:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):s(l)}),
|
|
731
|
+
`:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):s(l)}),r.stdin.on("error",()=>{}),r.stdin.write(o),r.stdin.end(),setTimeout(()=>{r.kill(),i(new Error(`${e} timed out after 10 minutes`))},6e5)})}async function ai(e,t,o,n,s,i){let a=de(),r=N(),l=$().modules.length>0,c=pt(),u=ft(a,t,l,c.pageType,c.brandAssets);u+=`
|
|
694
732
|
|
|
695
733
|
## User Request
|
|
696
|
-
`+e,u+=
|
|
734
|
+
`+e,u+=Pt(),u+=ni(i);let p=["--print"];r.claudeCodeModel&&p.push("--model",r.claudeCodeModel);let f=0,g=n||(()=>{});g(ce[0]);let y=setInterval(()=>{f++;let S=ce[Math.min(f,ce.length-1)];g(S)},6e3);try{let S=await ri("claude",p,u,w=>{o(w)});s&&s(S)}finally{clearInterval(y)}}async function so(e,t,o,n,s,i,a){let r=de(),l=$().modules.length>0,c=pt(),u=ft(r,o,l,c.pageType,c.brandAssets);u+=`
|
|
697
735
|
|
|
698
736
|
## User Request
|
|
699
|
-
`+t,u+=
|
|
700
|
-
Process error: ${l.message}`,s.completedAt=Date.now()});let
|
|
701
|
-
Process timed out`,s.completedAt=Date.now())},
|
|
702
|
-
Process error: ${c.message}`,s.completedAt=Date.now()});let l=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(
|
|
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,`
|
|
737
|
+
`+t,u+=Pt(),u+=ni(a);let p,f;e==="gemini"?(p="gemini",f=[]):(p="codex",f=["exec","--full-auto"]);let g=0,y=s||(()=>{});y(ce[0]);let S=setInterval(()=>{g++;let w=ce[Math.min(g,ce.length-1)];y(w)},6e3);try{let w=await ri(p,f,u,k=>{n(k)});i&&i(w)}finally{clearInterval(S)}}h();import{createWriteStream as Ka,mkdirSync as li,existsSync as io,readFileSync as ro}from"fs";import{join as Xe,extname as Ba}from"path";import{randomUUID as Ya}from"crypto";import Va from"busboy";h();function d(e,t,o){e.writeHead(t,{"Content-Type":"application/json"}),e.end(JSON.stringify(o))}function _(e,t){let o=[];e.on("data",n=>o.push(n)),e.on("end",()=>t(Buffer.concat(o).toString("utf-8")))}var za=10*1024*1024,ci=new Set(["image/png","image/jpeg","image/jpg","image/svg+xml","image/webp","image/gif"]),qa=new Set(["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/markdown","text/plain"]),Xa=new Set([...ci,...qa]);function Qa(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_").replace(/_{2,}/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function Za(e,t){if(!io(Xe(e,t)))return t;let o=Ba(t),n=t.slice(0,-o.length||void 0),s=1;for(;io(Xe(e,`${n}-${s}${o}`));)s++;return`${n}-${s}${o}`}async function el(e){let t=(await import("pdf-parse")).default,o=ro(e);return(await t(o)).text}async function tl(e){return(await(await import("mammoth")).extractRawText({path:e})).value}function nl(e){return ro(e,"utf-8")}function di(e,t){let o=$();if(!o){d(t,400,{error:"No active session"});return}if(!(e.headers["content-type"]||"").includes("multipart/form-data")){d(t,400,{error:"Expected multipart/form-data"});return}let s=[],i=[],a=0,r=[],l=Va({headers:e.headers,limits:{fileSize:za,files:10}});l.on("file",(c,u,p)=>{let{filename:f,mimeType:g}=p;if(a++,!Xa.has(g)){i.push(`Unsupported file type: ${f} (${g})`),u.resume();return}let y=ci.has(g),S=Qa(f),w=Ya(),k,E;y?(k=Xe(o.themePath,"assets"),li(k,{recursive:!0}),E=Za(k,S)):(k=Xe(o.themePath,".vibespot","uploads"),li(k,{recursive:!0}),E=`${w}-${S}`);let R=Xe(k,E),X=Ka(R),L=0,O=!1;u.on("data",G=>{L+=G.length}),u.on("limit",()=>{O=!0,i.push(`File too large (>10MB): ${f}`)}),u.pipe(X),r.push(new Promise(G=>{X.on("finish",()=>{if(!O){let oe={id:w,filename:E,originalName:f,type:y?"image":"document",usage:y?"asset":"context",mimeType:g,size:L,addedAt:new Date().toISOString()};s.push(oe),Os(oe)}G()}),X.on("error",()=>{i.push(`Failed to write: ${f}`),G()})}))}),l.on("finish",async()=>{await Promise.all(r);for(let c of s)if(c.type==="document"){let u=Xe(o.themePath,".vibespot","uploads",c.filename);try{c.mimeType==="application/pdf"?c.extractedText=await el(u):c.mimeType==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"?c.extractedText=await tl(u):c.extractedText=nl(u),V.info("upload",`Extracted text from ${c.originalName} (${c.extractedText.length} chars)`)}catch(p){V.warn("upload",`Failed to extract text from ${c.originalName}: ${p}`),c.extractedText=`[Could not extract text from ${c.originalName}]`}}if(a===0){d(t,400,{error:"No files uploaded"});return}d(t,200,{files:s.map(c=>({id:c.id,filename:c.filename,originalName:c.originalName,type:c.type,usage:c.usage,size:c.size})),errors:i.length>0?i:void 0})}),l.on("error",c=>{V.error("upload",`Busboy error: ${c}`),d(t,500,{error:"Upload failed"})}),e.pipe(l)}function ui(e){let t=$();return t?.assets?e.map(o=>{let n=t.assets.find(i=>i.id===o);if(!n)return null;let s={id:n.id,filename:n.filename,originalName:n.originalName,type:n.type,usage:n.usage,mimeType:n.mimeType};if(n.type==="image"){let i=Xe(t.themePath,"assets",n.filename);io(i)&&(s.base64=ro(i).toString("base64")),s.assetPath=`${t.themeName}/assets/${n.filename}`}else n.type==="document"&&(s.extractedText=n.extractedText);return s}).filter(o=>o!==null):[]}var lo=null;function mi(e){lo=e}var Ot=null;function Mt(){return Ot!==null}function gt(e){if(Ot){let t=$();if(!t||t.id!==Ot){V.warn("ai-handler","Session changed during generation \u2014 discarding AI output");return}}ze("assistant",e),ti(e,lo||void 0),j()}async function co(e,t,o,n){let s=$();if(!s)throw new Error("No active session");Ot=s.id;let a=n?.length?ui(n):void 0;try{let r=N(),l=r.aiEngine||ol();switch(l){case"anthropic-api":case"api":{let c=he("anthropic-api",r);if(!c)throw new Error("Anthropic API key not configured. Open Settings to add one.");await oi(e,c,s.themeName,r.anthropicApiModel||"claude-sonnet-4-6",t,o,gt,a);break}case"openai-api":{let c=he("openai-api",r);if(!c)throw new Error("OpenAI API key not configured. Open Settings to add one.");await si(e,c,s.themeName,r.openaiApiModel||"gpt-4o",t,o,gt,a);break}case"gemini-api":{let c=he("gemini-api",r);if(!c)throw new Error("Gemini API key not configured. Open Settings to add one.");await ii(e,c,s.themeName,t,o,gt,a);break}case"claude-code":await ai(e,s.themeName,t,o,gt,a);break;case"gemini-cli":await so("gemini",e,s.themeName,t,o,gt,a);break;case"codex-cli":await so("codex",e,s.themeName,t,o,gt,a);break;default:throw new Error(`Unknown AI engine: ${l}. Open Settings to configure one.`)}}finally{Ot=null,lo=null}}function ol(){let e=N();if(e.anthropicApiKey||process.env.ANTHROPIC_API_KEY)return"anthropic-api";if(e.openaiApiKey||process.env.OPENAI_API_KEY)return"openai-api";if(e.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY)return"gemini-api";try{return ao("claude --version",{stdio:"pipe"}),"claude-code"}catch{}try{return ao("gemini --version",{stdio:"pipe"}),"gemini-cli"}catch{}try{return ao("codex --version",{stdio:"pipe"}),"codex-cli"}catch{}throw new Error("No AI engine available. Open Settings to configure one.")}Z();h();import{spawn as pi}from"child_process";var Qe=new Map;function Ce(e,t,o){let n=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,s={id:n,command:e,description:t,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null};Qe.set(n,s);let i=e.split(" "),a=pi(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0});a.stdout?.on("data",l=>{s.output+=l.toString()}),a.stderr?.on("data",l=>{s.output+=l.toString()}),a.on("close",l=>{s.status=l===0?"completed":"failed",s.exitCode=l,s.completedAt=Date.now()}),a.on("error",l=>{s.status="failed",s.output+=`
|
|
738
|
+
Process error: ${l.message}`,s.completedAt=Date.now()});let r=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(a.kill(),s.status="failed",s.output+=`
|
|
739
|
+
Process timed out`,s.completedAt=Date.now())},r),n}function vn(e){return Qe.get(e)}function sl(){let e=Date.now()-18e5;for(let[t,o]of Qe)o.completedAt&&o.completedAt<e&&Qe.delete(t)}setInterval(sl,600*1e3);function wn(e,t,o){let n=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,s={id:n,command:e,description:t,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null,listeners:new Set};Qe.set(n,s);let i=e.split(" "),a=pi(i[0],i.slice(1),{cwd:o?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...o?.env},shell:!0}),r=c=>{for(let u of s.listeners)try{u(c)}catch{}};a.stdout?.on("data",c=>{let u=c.toString();s.output+=u,r(u)}),a.stderr?.on("data",c=>{let u=c.toString();s.output+=u,r(u)}),a.on("close",c=>{s.status=c===0?"completed":"failed",s.exitCode=c,s.completedAt=Date.now()}),a.on("error",c=>{s.status="failed",s.output+=`
|
|
740
|
+
Process error: ${c.message}`,s.completedAt=Date.now()});let l=o?.timeout||3e5;return setTimeout(()=>{s.status==="running"&&(a.kill(),s.status="failed",s.output+=`
|
|
741
|
+
Process timed out`,s.completedAt=Date.now())},l),n}function fi(e,t){let o=Qe.get(e);if(!o||!("listeners"in o))return;let n=o;if(n.output)try{t(n.output)}catch{}n.listeners.add(t)}function gi(e,t){let o=Qe.get(e);!o||!("listeners"in o)||o.listeners.delete(t)}h();import{existsSync as ht,readdirSync as hi,rmSync as il}from"fs";import{join as yt,basename as rl}from"path";import{homedir as al}from"os";import{execSync as yi}from"child_process";Z();en();Ye();Z();Q();var Ae=yt(al(),"vibespot-themes"),xn=null,ll=5e3;function Cn(){if(xn&&Date.now()-xn.ts<ll)return xn.data;let e=[];if(ht(Ae))try{for(let t of hi(Ae,{withFileTypes:!0}))if(t.isDirectory()){let o=yt(Ae,t.name,"theme.json");if(ht(o)){let n=0,s=yt(Ae,t.name,"modules");if(ht(s))try{n=hi(s,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}e.push({name:t.name,moduleCount:n})}}}catch{}return xn={data:e,ts:Date.now()},e}function bi(e){let t=$(),o=Bt(),n=!1;try{yi("hs --version",{encoding:"utf-8",stdio:"pipe"}),n=!0}catch{}let s=ut().sort((a,r)=>r.updatedAt-a.updatedAt).slice(0,10),i=Cn();d(e,200,{hasActiveSession:!!t,activeSession:t?{id:t.id,themeName:t.themeName,moduleCount:t.modules.length}:null,hsInstalled:n,aiAvailable:o.availableEngines.length>0,availableEngines:o.availableEngines,activeEngine:o.activeEngine,sessions:s,localThemes:i})}function Si(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme name is required"});return}let s=n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,""),i=yt(Ae,s);ge(Ae),ht(i)&&il(i,{recursive:!0,force:!0}),Zt(i,s),Nt(i,s),j(),d(t,200,{ok:!0,themeName:s,themePath:i})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function vi(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme name is required"});return}let s=n.replace(/^\/+|\/+$/g,"");if(!s){d(t,400,{error:"Theme name is required"});return}let i=ue(),a=N(),r=s.includes("/")||s.includes("@")?s.replace(/[@/]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""):s,l=yt(Ae,r);ge(Ae),a.hubspotUploadMode==="cli"||!i?(yi(`hs cms fetch "${s}" "${l}"`,{encoding:"utf-8",stdio:"pipe"}),Nt(l,r),Rt(l),j(),d(t,200,{ok:!0,themeName:r,themePath:l,moduleCount:$()?.modules.length||0})):Tt(i,s,l).then(()=>{Nt(l,r),Rt(l),j(),d(t,200,{ok:!0,themeName:r,themePath:l,moduleCount:$()?.modules.length||0})}).catch(c=>{d(t,500,{error:c instanceof Error?c.message:String(c)})})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function wi(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{path:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme path is required"});return}let s=n;if(ht(s)||(s=yt(Ae,n)),!ht(s)){d(t,400,{error:`Theme folder not found: ${n}`});return}let i=rl(s);Nt(s,i),Rt(s),j(),d(t,200,{ok:!0,themeName:i,themePath:s,moduleCount:$()?.modules.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function xi(e,t){_(e,o=>{try{if(Mt()){d(t,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{sessionId:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Session ID is required"});return}let s=bn(n);if(!s){d(t,404,{error:"Session not found"});return}d(t,200,{ok:!0,themeName:s.themeName,themePath:s.themePath,moduleCount:s.modules.length,messageCount:s.messages.length})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ci(e,t){_(e,o=>{try{let{apiKey:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"API key is required"});return}z({anthropicApiKey:n}),d(t,200,{ok:!0})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ai(e){let t=ue();if(!t){d(e,200,{themes:[],error:"No HubSpot account connected"});return}(async()=>{let o=await jo(t);if(o.length===0){d(e,200,{themes:[]});return}let n=[],s=o.map(async r=>{let l=r.path||r.name;try{let c=await zt(t,`${l}/theme.json`);c&&!c.folder&&n.push({name:r.name,path:l})}catch{}});await Promise.all(s),n.sort((r,l)=>r.name.localeCompare(l.name));let i=Cn(),a=new Set(i.map(r=>r.name));d(e,200,{themes:n.map(r=>({...r,existsLocally:a.has(r.name)}))})})().catch(o=>{d(e,200,{themes:[],error:o instanceof Error?o.message:String(o)})})}h();import{existsSync as cl,readFileSync as dl,appendFileSync as ul}from"fs";import{join as Ii}from"path";import{homedir as Ti}from"os";Z();Ye();Q();var jt={data:{},ts:0},ml=600*1e3,$i={"claude-code":[{id:"sonnet",label:"Claude Sonnet (default)"},{id:"opus",label:"Claude Opus"},{id:"haiku",label:"Claude Haiku"}],"codex-cli":[{id:"o4-mini",label:"o4 Mini (default)"},{id:"o3",label:"o3"},{id:"gpt-4o",label:"GPT-4o"}]};async function pl(e){let t=await fetch("https://api.anthropic.com/v1/models",{headers:{"x-api-key":e,"anthropic-version":"2023-06-01"}});return t.ok?(await t.json()).data.filter(n=>!n.id.startsWith("claude-3-")&&!n.id.startsWith("claude-2")).map(n=>({id:n.id,label:n.display_name})):[]}async function fl(e){let t=await fetch("https://api.openai.com/v1/models",{headers:{Authorization:`Bearer ${e}`}});if(!t.ok)return[];let o=await t.json(),n=/^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;return o.data.filter(s=>n.test(s.id)).sort((s,i)=>s.id.localeCompare(i.id)).map(s=>({id:s.id,label:s.id}))}async function gl(e){let t=await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${e}`);return t.ok?(await t.json()).models.filter(n=>n.name.includes("gemini-2")).map(n=>({id:n.name.replace("models/",""),label:n.displayName})):[]}async function hl(){if(Date.now()-jt.ts<ml&&Object.keys(jt.data).length>0)return jt.data;let e=N(),t={...$i},o=[],n=he("anthropic-api",e);n&&o.push(pl(n).then(a=>{a.length&&(t["anthropic-api"]=a)}).catch(()=>{}));let s=he("openai-api",e);s&&o.push(fl(s).then(a=>{a.length&&(t["openai-api"]=a)}).catch(()=>{}));let i=he("gemini-api",e);return i&&o.push(gl(i).then(a=>{a.length&&(t["gemini-api"]=a,t["gemini-cli"]=a)}).catch(()=>{})),await Promise.all(o),jt.data=t,jt.ts=Date.now(),t}function ki(e){let t=Bt(),o=N(),n={aiEngine:o.aiEngine||null,claudeCodeModel:o.claudeCodeModel||null,anthropicApiModel:o.anthropicApiModel||null,openaiApiModel:o.openaiApiModel||null,hubspotUploadMode:o.hubspotUploadMode||"api",hubspotAccounts:(o.hubspotAccounts||[]).map(r=>({portalId:r.portalId,portalName:r.portalName,dataCenter:r.dataCenter})),activeHubSpotAccount:o.activeHubSpotAccount||null,enabledCLITools:o.enabledCLITools||[]},s=ut().length,i=Cn().length,a=ot();hl().then(r=>{d(e,200,{version:a,environment:t,config:n,models:r,sessionCount:s,localThemeCount:i})}).catch(()=>{d(e,200,{version:a,environment:t,config:n,models:$i,sessionCount:s,localThemeCount:i})})}function Ei(e,t){_(e,o=>{try{let{engine:n,model:s}=JSON.parse(o);if(!["claude-code","anthropic-api","openai-api","gemini-cli","gemini-api","codex-cli"].includes(n)){d(t,400,{error:`Invalid engine: ${n}`});return}let a={aiEngine:n};if(s)switch(n){case"claude-code":a.claudeCodeModel=s;break;case"anthropic-api":a.anthropicApiModel=s;break;case"openai-api":a.openaiApiModel=s;break}z(a),d(t,200,{ok:!0,engine:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ni(e,t){_(e,o=>{try{let{provider:n,apiKey:s}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"provider is required"});return}if(!s){let l={};switch(n){case"anthropic":l.anthropicApiKey="";break;case"openai":l.openaiApiKey="";break;case"gemini":l.geminiApiKey="";break;default:d(t,400,{error:`Unknown provider: ${n}`});return}z(l),d(t,200,{ok:!0,provider:n,deleted:!0});return}let i={};switch(n){case"anthropic":i.anthropicApiKey=s;break;case"openai":i.openaiApiKey=s;break;case"gemini":i.geminiApiKey=s;break;default:d(t,400,{error:`Unknown provider: ${n}`});return}z(i);let a=null;if(!N().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[n];c&&(z({aiEngine:c}),a=c)}d(t,200,{ok:!0,provider:n,autoSelectedEngine:a})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function _i(e,t){_(e,o=>{try{let{tool:n}=JSON.parse(o),s={hubspot:{cmd:"npm install -g @hubspot/cli",desc:"Installing HubSpot CLI"},claude:{cmd:"npm install -g @anthropic-ai/claude-code",desc:"Installing Claude Code"},gemini:{cmd:"npm install -g @google/gemini-cli",desc:"Installing Gemini CLI"},codex:{cmd:process.platform==="darwin"?"brew install --cask codex":"npm install -g @openai/codex",desc:"Installing OpenAI Codex"},gh:{cmd:process.platform==="darwin"?"brew install gh":"npm install -g @cli/gh",desc:"Installing GitHub CLI"}},i=s[n];if(!i){d(t,400,{error:`Unknown tool: ${n}. Valid: ${Object.keys(s).join(", ")}`});return}let a=Ce(i.cmd,i.desc,{timeout:12e4});d(t,200,{ok:!0,jobId:a})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ri(e,t){_(e,o=>{try{let n=JSON.parse(o||"{}"),s=N(),i=s.hubspotUploadMode||"api";if(n.personalAccessKey)if(i==="api"){Vt(n.personalAccessKey).then(a=>{Ht(n.personalAccessKey,a.portalId,a.portalName,a.dataCenter),d(t,200,{ok:!0,portalName:a.portalName,portalId:a.portalId,dataCenter:a.dataCenter})}).catch(a=>{d(t,400,{error:a instanceof Error?a.message:String(a)})});return}else{if(!$e().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Ce(`hs auth --pak="${n.personalAccessKey}"`,"Authenticating with HubSpot",{timeout:3e4});d(t,200,{ok:!0,jobId:r});return}if(i==="api"){let a=s.hubspotAccounts||[];if(a.length>0&&!n.force){let r=a.find(l=>l.portalId===s.activeHubSpotAccount)||a[0];d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}else{if(!$e().found){d(t,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=ke();if(r.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}d(t,200,{needsKey:!0,instructions:"Create a personal access key in HubSpot",url:"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key",steps:["Click the link above to open HubSpot","Select your account","Create a Personal Access Key with CMS permissions","Copy the key and paste it below"]})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Pi(e,t){_(e,o=>{try{let n=JSON.parse(o||"{}");if(!jn().found){d(t,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=Dn();if(i.authenticated&&!n.force){d(t,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(n.token){let r=Ce(`echo "${n.token}" | gh auth login --with-token`,"Authenticating with GitHub",{timeout:3e4});d(t,200,{ok:!0,jobId:r});return}let a=Ce("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});d(t,200,{ok:!0,jobId:a,browserAuthRequired:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Oi(e,t){_(e,o=>{try{let{portalId:n,action:s}=JSON.parse(o);if((N().hubspotUploadMode||"api")==="api"){if(s==="remove"&&n){To(n),d(t,200,{ok:!0});return}if(n){$o(n),d(t,200,{ok:!0});return}}else{if(!$e().found){d(t,400,{error:"HubSpot CLI not installed"});return}if(s==="remove"&&n){let l=Ce(`hs accounts remove ${n}`,`Removing HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:l});return}if(n){let l=Ce(`hs accounts use ${n}`,`Switching to HubSpot account ${n}`,{timeout:15e3});d(t,200,{ok:!0,jobId:l});return}}d(t,400,{error:"portalId required"})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Mi(e){let t=Ce("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});d(e,200,{ok:!0,jobId:t})}function ji(e,t){_(e,o=>{try{let{cli:n,apiKey:s}=JSON.parse(o||"{}");switch(n){case"claude":{let i=Ce("CLAUDECODE= claude --print -p 'reply OK'","Authenticating Claude Code (check your browser if prompted)",{timeout:12e4});d(t,200,{ok:!0,jobId:i,hint:"If Claude Code opens a browser window, complete the sign-in there."});break}case"gemini":{let i=Ce("gemini -p 'reply OK'","Authenticating Gemini CLI (check your browser if prompted)",{timeout:12e4});d(t,200,{ok:!0,jobId:i,hint:"If Gemini opens a browser window, complete the sign-in there."});break}case"codex":{if(s&&s.trim()){let i=s.trim();if(process.env.OPENAI_API_KEY=i,z({openaiApiKey:i}),process.platform!=="win32"){let a=`export OPENAI_API_KEY="${i}"`,r=process.env.SHELL?.includes("zsh")?Ii(Ti(),".zshrc"):Ii(Ti(),".bashrc");try{(cl(r)?dl(r,"utf-8"):"").includes("OPENAI_API_KEY")||ul(r,`
|
|
704
742
|
# Added by vibeSpot
|
|
705
|
-
${
|
|
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(`
|
|
707
|
-
`),
|
|
743
|
+
${a}
|
|
744
|
+
`)}catch{}}d(t,200,{ok:!0,message:"API key saved"})}else{let i=Ce("codex login","Authenticating Codex CLI (check your browser if prompted)",{timeout:12e4});d(t,200,{ok:!0,jobId:i,hint:"Complete the sign-in in your browser."})}break}default:d(t,400,{error:`Unknown CLI: ${n}`})}}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Di(e,t){_(e,o=>{try{let{mode:n}=JSON.parse(o);if(n!=="api"&&n!=="cli"){d(t,400,{error:`Invalid mode: ${n}. Must be "api" or "cli".`});return}z({hubspotUploadMode:n}),d(t,200,{ok:!0,mode:n})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Ji(e,t){_(e,o=>{try{let{toolId:n,enabled:s}=JSON.parse(o);if(!n||typeof s!="boolean"){d(t,400,{error:"toolId (string) and enabled (boolean) required"});return}ko(n,s),d(t,200,{ok:!0,toolId:n,enabled:s})}catch(n){d(t,400,{error:n instanceof Error?n.message:String(n)})}})}function Fi(e,t){let o=e.replace("/api/settings/job/","");if(!o){d(t,400,{error:"Job ID required"});return}let n=vn(o);if(!n){d(t,404,{error:"Job not found"});return}d(t,200,{id:n.id,status:n.status,description:n.description,output:n.output,exitCode:n.exitCode,startedAt:n.startedAt,completedAt:n.completedAt})}h();import{existsSync as yl,rmSync as bl}from"fs";import{join as Sl}from"path";function Hi(e,t,o){if(e==="GET"){let n=$(),s=ut().sort((i,a)=>a.updatedAt-i.updatedAt);d(o,200,{activeTheme:n?{id:n.id,themeName:n.themeName}:null,sessions:s});return}if(e==="DELETE"){_(t,n=>{try{let{sessionId:s,deleteFiles:i}=JSON.parse(n);Fs(s,i),d(o,200,{ok:!0})}catch(s){d(o,500,{error:s instanceof Error?s.message:String(s)})}});return}d(o,405,{error:"Method not allowed"})}function Li(e,t){_(e,o=>{try{let{sessionId:n}=JSON.parse(o),s=bn(n);if(!s){d(t,404,{error:"Session not found"});return}d(t,200,{ok:!0,themeName:s.themeName,themePath:s.themePath})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Gi(e,t){_(e,o=>{try{let{themeName:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"Theme name is required"});return}let s=Sl(Ae,n);if(!yl(s)){d(t,404,{error:"Theme not found on disk"});return}bl(s,{recursive:!0,force:!0}),d(t,200,{ok:!0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Ui(e,t){_(e,o=>{try{let{sessionId:n,newName:s}=JSON.parse(o);if(!n||!s||typeof s!="string"){d(t,400,{error:"sessionId and newName are required"});return}let i=s.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-|-$/g,"").replace(/-{2,}/g,"-");if(!i){d(t,400,{error:"Invalid name"});return}let a=Hs(n,i);a.ok?d(t,200,{ok:!0,newName:i}):d(t,400,{error:a.error})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}h();import{existsSync as $n,readFileSync as Tl,rmSync as go}from"fs";import{join as Pe,basename as $l}from"path";import{execSync as kl}from"child_process";Z();Q();function Ki(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}let o=dt();d(e,200,{themeName:t.themeName,themePath:t.themePath,templates:t.templates.map(n=>({id:n.id,label:n.label,pageType:n.pageType,moduleCount:n.modules.length,messageCount:n.messages.length})),activeTemplateId:t.activeTemplateId,moduleLibrary:o.map(n=>({moduleName:n.module.moduleName,usedIn:n.usedIn})),brandAssets:{hasStyleguide:!!t.brandAssets?.styleguide,hasBrandvoice:!!t.brandAssets?.brandvoice,humanify:t.brandAssets?.humanify!==!1}})}function Bi(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}let o=t.themePath;if(!$n(o)){d(e,404,{error:"Theme directory not found"});return}let n=t.themeName||"theme",s=Pe(o,".."),i=$l(o);try{let a=`${n}.zip`,r=Pe(s,a);$n(r)&&go(r),kl(`zip -r "${a}" "${i}" -x "${i}/.git/*" "${i}/.vibespot/*" "${i}/node_modules/*"`,{cwd:s,timeout:3e4});let l=Tl(r);go(r),e.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${a}"`,"Content-Length":l.length}),e.end(l)}catch(a){V.error("download-zip","Failed to create zip archive",a),d(e,500,{error:"Failed to create zip archive"})}}function Yi(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){d(o,200,{templates:n.templates.map(s=>({id:s.id,label:s.label,pageType:s.pageType,moduleCount:s.modules.length})),activeTemplateId:n.activeTemplateId});return}if(e==="POST"){_(t,s=>{try{let{pageType:i,label:a}=JSON.parse(s);if(!i||!a){d(o,400,{error:"pageType and label are required"});return}if(!["landing_page","blog_post","website_page","module_only"].includes(i)){d(o,400,{error:`Invalid pageType: ${i}`});return}let l=Ns(i,a);j(),d(o,200,{ok:!0,template:{id:l.id,label:l.label,pageType:l.pageType}})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}if(e==="DELETE"){_(t,s=>{try{let{templateId:i}=JSON.parse(s);if(!i){d(o,400,{error:"templateId is required"});return}if(!Ps(i)){d(o,404,{error:"Template not found"});return}j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}d(o,405,{error:"Method not allowed"})}function Vi(e,t){_(e,o=>{try{let{templateId:n}=JSON.parse(o);if(!n){d(t,400,{error:"templateId is required"});return}if(!zn(n)){d(t,404,{error:"Template not found"});return}j();let i=$();d(t,200,{ok:!0,modules:be().map(a=>a.moduleName),messageCount:i?.messages.length||0})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function zi(e,t){_(e,o=>{try{let{templateId:n,newLabel:s}=JSON.parse(o);if(!n||!s||typeof s!="string"){d(t,400,{error:"templateId and newLabel are required"});return}if(!Rs(n,s.trim())){d(t,404,{error:"Template not found"});return}j(),d(t,200,{ok:!0,newLabel:s.trim()})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function qi(e,t){_(e,o=>{try{let{templateId:n,label:s}=JSON.parse(o);if(!n){d(t,400,{error:"templateId is required"});return}let i=_s(n,s);if(!i){d(t,404,{error:"Template not found"});return}j(),d(t,200,{ok:!0,template:{id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function Xi(e){let t=dt();d(e,200,{modules:t.map(o=>({moduleName:o.module.moduleName,usedIn:o.usedIn,fieldsJson:o.module.fieldsJson}))})}function Qi(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}_(t,s=>{try{let{moduleName:i}=JSON.parse(s);if(!i){d(o,400,{error:"moduleName is required"});return}let r=dt().find(u=>u.module.moduleName===i);if(!r){d(o,404,{error:`Module "${i}" not found in library`});return}let l={...r.module};n.modules.find(u=>u.moduleName===l.moduleName)||(n.modules.push(l),n.moduleOrder.push(l.moduleName),n.updatedAt=Date.now()),j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}})}function Zi(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){d(o,200,{styleguide:n.brandAssets?.styleguide||null,brandvoice:n.brandAssets?.brandvoice||null});return}if(e==="POST"){_(t,s=>{try{let{type:i,content:a}=JSON.parse(s);if(!i){d(o,400,{error:"type is required"});return}if(n.brandAssets||(n.brandAssets={}),i==="humanify"){n.brandAssets.humanify=a==="on",n.updatedAt=Date.now(),j(),d(o,200,{ok:!0});return}if(!a){d(o,400,{error:"content is required"});return}if(i!=="styleguide"&&i!=="brandvoice"){d(o,400,{error:`Invalid type: ${i}. Must be "styleguide" or "brandvoice"`});return}n.brandAssets[i]=a,n.updatedAt=Date.now();let r=Pe(n.themePath,".vibespot");ge(r),M(Pe(r,`${i}.md`),a),j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}if(e==="DELETE"){_(t,s=>{try{let{type:i}=JSON.parse(s);if(i!=="styleguide"&&i!=="brandvoice"){d(o,400,{error:`Invalid type: ${i}`});return}n.brandAssets&&delete n.brandAssets[i],n.updatedAt=Date.now();let a=Pe(n.themePath,".vibespot",`${i}.md`);$n(a)&&go(a),j(),d(o,200,{ok:!0})}catch(i){d(o,500,{error:i instanceof Error?i.message:String(i)})}});return}d(o,405,{error:"Method not allowed"})}function er(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}_(e,n=>{(async()=>{try{let{sourcePath:s}=n?JSON.parse(n):{},i=s||o.themePath,{extractDesignContext:a}=await Promise.resolve().then(()=>(fo(),po)),r=await a(i);o.brandAssets||(o.brandAssets={}),o.brandAssets.styleguide=r,o.updatedAt=Date.now();let l=Pe(o.themePath,".vibespot");ge(l),M(Pe(l,"styleguide.md"),r),j(),d(t,200,{ok:!0,styleguide:r})}catch(s){d(t,500,{error:s instanceof Error?s.message:String(s)})}})()})}function tr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}_(e,n=>{(async()=>{try{let{source:s,themeName:i,localPath:a}=JSON.parse(n),r;if(s==="hubspot"){if(!i){d(t,400,{error:"themeName is required for HubSpot import"});return}let p=ue();if(!p){d(t,400,{error:"No HubSpot account connected"});return}let f=i.replace(/^\/+|\/+$/g,"");if(!f){d(t,400,{error:"Invalid theme name"});return}let g=f.replace(/[@/]/g,"_").replace(/_+/g,"_"),{homedir:y}=await import("os"),S=Pe(y(),"vibespot-themes",".references",g);ge(S);let{fetchTheme:w}=await Promise.resolve().then(()=>(en(),Go));await w(p,f,S),r=S}else if(s==="local"){if(!a){d(t,400,{error:"localPath is required for local import"});return}if(!$n(a)){d(t,400,{error:`Path not found: ${a}`});return}r=a}else{d(t,400,{error:"source must be 'hubspot' or 'local'"});return}let{extractDesignContext:l}=await Promise.resolve().then(()=>(fo(),po)),c=await l(r);o.brandAssets||(o.brandAssets={}),o.brandAssets.styleguide=c,o.updatedAt=Date.now();let u=Pe(o.themePath,".vibespot");ge(u),M(Pe(u,"styleguide.md"),c),j(),d(t,200,{ok:!0,styleguide:c,source:r})}catch(s){d(t,500,{error:s instanceof Error?s.message:String(s)})}})()})}h();import{join as El}from"path";function nr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}d(t,200,{id:o.id,themeName:o.themeName,themePath:o.themePath,messageCount:o.messages.length,moduleCount:o.modules.length,moduleOrder:o.moduleOrder})}function or(e,t,o){let n=$();if(!n){d(o,404,{error:"No active session"});return}if(e==="GET"){let s=be();d(o,200,{modules:s.map(i=>({moduleName:i.moduleName,fieldsJson:i.fieldsJson,moduleHtml:i.moduleHtml,moduleCss:i.moduleCss,moduleJs:i.moduleJs||null})),sharedCss:n.sharedCss,sharedJs:n.sharedJs});return}if(e==="DELETE"){_(t,s=>{let{moduleName:i,deleteEntirely:a}=JSON.parse(s);a?js(i):Ds(i),j(),d(o,200,{ok:!0})});return}d(o,405,{error:"Method not allowed"})}function sr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}_(e,n=>{try{let s=JSON.parse(n);if(s.shared){if(s.shared==="css")o.sharedCss=s.content;else if(s.shared==="js")o.sharedJs=s.content;else{d(t,400,{error:"Invalid shared type"});return}let c=Fe();c&&(s.shared==="css"?c.sharedCss=s.content:c.sharedJs=s.content),o.updatedAt=Date.now(),j(),We(),d(t,200,{ok:!0});return}let{moduleName:i,fileType:a,content:r}=s;if(!i||!a){d(t,400,{error:"moduleName and fileType required"});return}let l=o.modules.find(c=>c.moduleName===i);if(!l){d(t,404,{error:`Module "${i}" not found`});return}switch(a){case"html":l.moduleHtml=r;break;case"css":l.moduleCss=r;break;case"js":l.moduleJs=r||void 0;break;case"fields":try{JSON.parse(r)}catch{d(t,400,{error:"Invalid JSON in fields.json"});return}l.fieldsJson=r;break;default:d(t,400,{error:`Invalid fileType: ${a}`});return}o.updatedAt=Date.now(),j(),We(),d(t,200,{ok:!0})}catch(s){d(t,400,{error:String(s)})}})}function ir(e,t){_(e,o=>{let{order:n}=JSON.parse(o);Array.isArray(n)?(Ms(n),j(),d(t,200,{ok:!0})):d(t,400,{error:"order must be an array"})})}async function rr(e){let t=$();if(!t){d(e,404,{error:"No active session"});return}try{We();let o=mn(t.themePath),n=wn(`hs cms upload "${t.themePath}" "${t.themeName}"`,"Uploading to HubSpot",{cwd:El(t.themePath,".."),timeout:18e4});d(e,200,{ok:!0,jobId:n,fixes:o})}catch(o){d(e,500,{error:String(o)})}}function ar(e,t){_(e,o=>{try{let{moduleName:n,fieldPath:s,value:i}=JSON.parse(o);Js(n,s,i),j(),d(t,200,{ok:!0})}catch(n){d(t,400,{error:String(n)})}})}function lr(e,t){_(e,o=>{try{let{url:n}=JSON.parse(o);if(!n||typeof n!="string"){d(t,400,{error:"url is required"});return}let s=Ho(n),i=s.components.map(r=>`- ${r.name}: ${r.description}`).join(`
|
|
745
|
+
`),a={sourceDir:s.sourceDir,componentCount:s.components.length,components:s.components.map(r=>({name:r.name,description:r.description})),hasTailwind:s.hasTailwind,cssVarCount:s.cssVarCount,fonts:s.fonts,interactions:s.interactions,conversionPrompt:`Import and convert the React landing page from ${n} to native HubSpot modules.
|
|
708
746
|
|
|
709
747
|
Source analysis found ${s.components.length} components:
|
|
710
748
|
${i}
|
|
@@ -713,11 +751,11 @@ Design system: ${s.hasTailwind?"Tailwind CSS":"Custom CSS"}, ${s.cssVarCount} CS
|
|
|
713
751
|
Fonts: ${s.fonts.length>0?s.fonts.join(", "):"System fonts"}
|
|
714
752
|
Interactions: ${s.interactions.join(", ")}
|
|
715
753
|
|
|
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,
|
|
754
|
+
Read the React source files from ${s.sourceDir} and convert each component to a HubSpot module. Preserve the design, layout, colors, and content. Generate fields.json so marketers can edit all text, images, colors, and links in the HubSpot page editor.`};d(t,200,a)}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}function cr(e,t){let o=$();if(!o){d(t,404,{error:"No active session"});return}if(!xe()){d(t,200,{available:!1,commits:[]});return}let s=new URL(e.url||"/","http://localhost").searchParams.get("templateId"),i=s?Is(o.themePath,s,50):As(o.themePath,50);d(t,200,{available:!0,commits:i,filtered:!!s})}function dr(e,t){_(e,o=>{try{let n=$();if(!n){d(t,404,{error:"No active session"});return}let{hash:s,templateId:i}=JSON.parse(o);if(!s||typeof s!="string"){d(t,400,{error:"Commit hash is required"});return}if(ze("assistant",`Rolled back to version ${s.slice(0,7)}.`),i){let a=n.templates.find(c=>c.id===i);if(!a){d(t,404,{error:"Template not found"});return}let r=a.moduleOrder.map(c=>`modules/${c}.module`);a.templateFile&&r.push(a.templateFile);let l=$s(n.themePath,i,s,r);if(!l.success){d(t,500,{error:l.error||"Rollback failed"});return}Gs()}else{let a=Ts(n.themePath,s);if(!a.success){d(t,500,{error:a.error||"Rollback failed"});return}Ls()}j(),d(t,200,{ok:!0,modules:be().map(a=>a.moduleName)})}catch(n){d(t,500,{error:n instanceof Error?n.message:String(n)})}})}var pr={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".ico":"image/x-icon",".woff2":"font/woff2"};function fr(e){let{port:t,uiDir:o}=e,n=Nl((i,a)=>Pl(i,a,o)),s=new Rl({server:n});return s.on("connection",i=>Ml(i)),new Promise((i,a)=>{n.on("error",r=>{r.code==="EADDRINUSE"?n.listen(t+1,()=>{i({port:t+1,close:()=>{n.close(),s.close()}})}):a(r)}),n.listen(t,()=>{i({port:t,close:()=>{n.close(),s.close()}})})})}function Pl(e,t,o){let n=new URL(e.url||"/",`http://${e.headers.host}`),s=e.method||"GET";if(n.pathname.startsWith("/api/")){Ol(s,n.pathname,e,t);return}if(n.pathname==="/preview"){let i=Zs();t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(i);return}if(n.pathname==="/module-preview"){let i=n.searchParams.get("module")||"",a=ei(i);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(a||"<!-- module not found -->");return}if(n.pathname.startsWith("/theme-assets/")){jl(n.pathname.slice(14),t);return}Dl(n.pathname,o,e,t)}function Ol(e,t,o,n){if(n.setHeader("Access-Control-Allow-Origin","*"),n.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),n.setHeader("Access-Control-Allow-Headers","Content-Type"),e==="OPTIONS"){n.writeHead(204),n.end();return}switch(t){case"/api/session":nr(e,n);break;case"/api/modules":or(e,o,n);break;case"/api/modules/reorder":ir(o,n);break;case"/api/modules/code":sr(o,n);break;case"/api/upload":rr(n);break;case"/api/upload-files":e==="POST"?di(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/field":ar(o,n);break;case"/api/import":lr(o,n);break;case"/api/setup":bi(n);break;case"/api/setup/create":Si(o,n);break;case"/api/setup/fetch":vi(o,n);break;case"/api/setup/open":wi(o,n);break;case"/api/setup/resume":xi(o,n);break;case"/api/setup/apikey":Ci(o,n);break;case"/api/setup/remote-themes":e==="GET"?Ai(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/status":e==="GET"?ki(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/engine":e==="POST"?Ei(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/apikey":e==="POST"?Ni(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/install":e==="POST"?_i(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":e==="POST"?Ri(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":e==="POST"?Pi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":e==="POST"?Oi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":e==="POST"?Mi(n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":e==="POST"?ji(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/hs-mode":e==="POST"?Di(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/settings/cli-toggle":e==="POST"?Ji(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes":Hi(e,o,n);break;case"/api/themes/switch":e==="POST"?Li(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":e==="POST"?Gi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/themes/rename":e==="POST"?Ui(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/history":e==="GET"?cr(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/rollback":e==="POST"?dr(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/dashboard":e==="GET"?Ki(n):d(n,405,{error:"Method not allowed"});break;case"/api/templates":Yi(e,o,n);break;case"/api/templates/activate":e==="POST"?Vi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/templates/rename":e==="POST"?zi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/templates/clone":e==="POST"?qi(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/module-library":e==="GET"?Xi(n):d(n,405,{error:"Method not allowed"});break;case"/api/brand-assets":Zi(e,o,n);break;case"/api/brand-assets/extract":e==="POST"?er(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/brand-assets/import-reference":e==="POST"?tr(o,n):d(n,405,{error:"Method not allowed"});break;case"/api/download-zip":e==="GET"?Bi(n):d(n,405,{error:"Method not allowed"});break;default:t.startsWith("/api/settings/job/")&&e==="GET"?Fi(t,n):t.match(/^\/api\/templates\/[^/]+\/add-module$/)&&e==="POST"?Qi(t,o,n):d(n,404,{error:"Not found"})}}function Ml(e){e.on("message",async o=>{let n;try{n=JSON.parse(o.toString())}catch{e.send(JSON.stringify({type:"error",message:"Invalid JSON"}));return}switch(n.type){case"chat":{let s=String(n.message||"");if(!s.trim())return;ze("user",s),j(),mi(a=>{e.send(JSON.stringify({type:"parse_warning",message:a}))});let i=Array.isArray(n.fileIds)?n.fileIds:void 0;try{await co(s,r=>{e.send(JSON.stringify({type:"stream",content:r}))},r=>{e.send(JSON.stringify({type:"stream_status",content:r}))},i);let a=$();if(a){We();let r=Fe(),l=null;if(r){let c=r.moduleOrder.map(u=>`modules/${u}.module`);r.templateFile&&c.push(r.templateFile),r.sharedCss&&c.push(`css/${a.themeName}-theme.css`),r.sharedJs&&c.push(`js/${a.themeName}-animations.js`),l=Cs(a.themePath,r.id,s,c)}else l=Kn(a.themePath,s);l&&e.send(JSON.stringify({type:"version_created",hash:l}))}e.send(JSON.stringify({type:"generation_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:be().map(r=>r.moduleName)}))}catch(a){e.send(JSON.stringify({type:"error",message:a instanceof Error?a.message:String(a)}))}break}case"start_upload":{let s=$();if(!s){e.send(JSON.stringify({type:"error",message:"No active session"}));break}try{We();let i=mn(s.themePath);if(i.length>0&&e.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i})),(N().hubspotUploadMode||"api")==="api"){let l=ue();if(!l){e.send(JSON.stringify({type:"upload_failed",output:"No HubSpot account configured. Open Settings \u2192 HubSpot to add one.",errors:[{file:"",message:"No HubSpot account configured",fixable:!1}]}));break}e.send(JSON.stringify({type:"upload_started",jobId:"api-upload"}));let c=await pn(l,s.themePath,s.themeName,{onFileStart:u=>{e.send(JSON.stringify({type:"upload_output",chunk:`Uploading ${u}
|
|
717
755
|
`}))},onFileComplete:u=>{e.send(JSON.stringify({type:"upload_output",chunk:` \u2713 ${u}
|
|
718
756
|
`}))},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=
|
|
720
|
-
`),errors:u}))}}else{let l=
|
|
757
|
+
`}))},onProgress:(u,p)=>{e.send(JSON.stringify({type:"upload_progress",completed:u,total:p}))}});if(c.success){let u=Ke();e.send(JSON.stringify({type:"upload_complete",output:`Uploaded ${c.uploaded} files`,portalId:u?.portalId||"",dataCenter:u?.dataCenter||"na1",themeName:s.themeName}))}else{let u=dn(c.errors);e.send(JSON.stringify({type:"upload_failed",output:c.errors.map(p=>`${p.file}: ${p.message}`).join(`
|
|
758
|
+
`),errors:u}))}}else{let l=wn(`hs cms upload "${s.themePath}" "${s.themeName}"`,"Uploading to HubSpot",{cwd:kn(s.themePath,".."),timeout:18e4});e.send(JSON.stringify({type:"upload_started",jobId:l}));let c=p=>{e.send(JSON.stringify({type:"upload_output",chunk:p}))};fi(l,c);let u=setInterval(()=>{let p=vn(l);if(!(!p||p.status==="running"))if(clearInterval(u),gi(l,c),p.status==="completed"){let f=ke(),g=f.portalId?wt(f.portalId):"na1";e.send(JSON.stringify({type:"upload_complete",output:p.output,portalId:f.portalId||"",dataCenter:g,themeName:s.themeName}))}else{let f=un(p.output);e.send(JSON.stringify({type:"upload_failed",output:p.output,errors:f,exitCode:p.exitCode}))}},500)}}catch(i){e.send(JSON.stringify({type:"error",message:i instanceof Error?i.message:String(i)}))}break}case"upload_fix_with_ai":{let s=String(n.errorContext||"");if(!s.trim()){e.send(JSON.stringify({type:"error",message:"No error context provided"}));break}let i=`The HubSpot upload ("hs cms upload") failed. Below is the upload log output containing the errors.
|
|
721
759
|
|
|
722
760
|
IMPORTANT: Be verbose in your response. For each error:
|
|
723
761
|
1. State exactly which file has the problem and what the error is
|
|
@@ -730,9 +768,9 @@ CRITICAL: After fixing the reported errors, scan ALL other module files in the t
|
|
|
730
768
|
After fixing all errors, summarize the changes you made.
|
|
731
769
|
|
|
732
770
|
Upload log:
|
|
733
|
-
${s}`;
|
|
734
|
-
`));let o=
|
|
735
|
-
`));try{process.platform==="darwin"?
|
|
736
|
-
Saving session...`)),
|
|
737
|
-
`)),
|
|
771
|
+
${s}`;ze("user",i),j(),e.send(JSON.stringify({type:"upload_fix_started"}));try{await co(i,r=>{e.send(JSON.stringify({type:"stream",content:r})),e.send(JSON.stringify({type:"upload_fix_stream",content:r}))});let a=$();if(a){We();let r=Kn(a.themePath,"AI fix: upload errors");r&&e.send(JSON.stringify({type:"version_created",hash:r}))}e.send(JSON.stringify({type:"upload_fix_complete"})),e.send(JSON.stringify({type:"modules_updated",modules:be().map(r=>r.moduleName)}))}catch(a){e.send(JSON.stringify({type:"upload_failed",output:a instanceof Error?a.message:String(a),errors:[{file:"AI fix",message:a instanceof Error?a.message:String(a),fixable:!1}]}))}break}case"ping":e.send(JSON.stringify({type:"pong"}));break;default:e.send(JSON.stringify({type:"error",message:`Unknown type: ${n.type}`}))}});let t=$();if(t){let o=N(),n={"claude-code":"Claude Code","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-cli":"Gemini CLI","gemini-api":"Gemini API","codex-cli":"Codex CLI",api:"Anthropic API"},s=Fe();e.send(JSON.stringify({type:"init",sessionId:t.id,themeName:t.themeName,modules:be().map(i=>i.moduleName),messageCount:t.messages.length,messages:t.messages,gitAvailable:xe(),engine:o.aiEngine?n[o.aiEngine]||o.aiEngine:"",templateId:s?.id||null,pageType:s?.pageType||null,templates:(t.templates||[]).map(i=>({id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}))}))}else e.send(JSON.stringify({type:"needs_setup"}))}function jl(e,t){let o=$();if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("No session");return}let n=kn(o.themePath,"assets",e);if(!yo(n)){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Asset not found");return}let s=mr(n),i=pr[s]||"application/octet-stream",a=ho(n);t.writeHead(200,{"Content-Type":i,"Cache-Control":"no-cache"}),t.end(a)}var ur=new Map;function Dl(e,t,o,n){let i=kn(t,e==="/"?"/index.html":e);if(!yo(i)){let c=kn(t,"index.html");if(yo(c)){let u=ho(c);n.writeHead(200,{"Content-Type":"text/html","Cache-Control":"no-cache"}),n.end(u)}else n.writeHead(404,{"Content-Type":"text/plain"}),n.end("Not found");return}let a=mr(i),r=pr[a]||"application/octet-stream",l=a===".html";try{let c=ur.get(i);if(!c){let p=ho(i),f='"'+_l("md5").update(p).digest("hex").slice(0,16)+'"';c={buffer:p,etag:f,contentType:r},ur.set(i,c)}if(o.headers["if-none-match"]===c.etag){n.writeHead(304),n.end();return}n.writeHead(200,{"Content-Type":c.contentType,"Cache-Control":l?"no-cache":"public, max-age=3600",ETag:c.etag}),n.end(c.buffer)}catch{n.writeHead(500,{"Content-Type":"text/plain"}),n.end("Internal Server Error")}}var Fl=4200;async function gr(){let e=Nn.hex("#e8613a"),t=Nn.dim;console.log(""),console.log(e(" v vibeSpot")),console.log(t(` Starting...
|
|
772
|
+
`));let o=Hl();o||(console.error(Nn.red(" Could not find UI assets. Is the package installed correctly?")),process.exit(1));try{let{port:n,close:s}=await fr({port:Fl,uiDir:o}),i=`http://localhost:${n}`;console.log(e(` v ${i}`)),console.log(t(` Press Ctrl+C to stop
|
|
773
|
+
`));try{process.platform==="darwin"?bo(`open "${i}"`,{stdio:"ignore"}):process.platform==="win32"?bo(`cmd /c start "" "${i}"`,{stdio:"ignore"}):bo(`xdg-open "${i}"`,{stdio:"ignore"})}catch{}await new Promise(a=>{process.on("SIGINT",()=>{console.log(t(`
|
|
774
|
+
Saving session...`)),j(),s(),console.log(t(` Goodbye!
|
|
775
|
+
`)),a(),setTimeout(()=>process.exit(0),500)})})}catch(n){console.error(Nn.red(` Failed to start: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}function Hl(){let e=[En(import.meta.dirname,"../../ui"),En(import.meta.dirname,"../ui"),En(process.cwd(),"ui")];for(let t of e)if(Jl(En(t,"index.html")))return t;return null}Q();function hr(){let e=new Ll;return e.name("vibespot").description("AI-powered HubSpot CMS landing page builder").version(ot()).action(gr),e.command("wizard").description("Classic CLI wizard \u2014 step-by-step conversion flow").action(ys),e.command("init").description("Check and install required tools").action(bs),e.command("convert").description("Convert a React project to HubSpot modules").action(Ss),e.command("upload").description("Upload theme to HubSpot").action(vs),e.command("doctor").description("Diagnose environment issues").action(ws),e}var Gl=hr();Gl.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
|
|
738
776
|
//# sourceMappingURL=index.js.map
|