vibespot 1.0.1 → 1.0.2
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/README.md +1 -0
- package/dist/index.js +371 -317
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/chat.js +60 -0
- package/ui/dashboard.js +110 -62
- package/ui/index.html +41 -21
- package/ui/styles.css +55 -34
package/dist/index.js
CHANGED
|
@@ -1,101 +1,5 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
\`\`\`
|
|
4
|
-
${l}
|
|
5
|
-
\`\`\`
|
|
6
|
-
`;return n+c.length>cd?!1:(e.push(c),n+=c.length,!0)}let o=Kt(Fe(t,"theme.json"));o&&s("theme.json",o);let i=Fe(t,"css");if(Gn(i)){for(let r of Un(i).filter(l=>l.endsWith(".css")))if(!s(`css/${r}`,Kt(Fe(i,r))))break}let a=Fe(t,"modules");if(Gn(a))for(let r of Un(a).filter(l=>l.endsWith(".module"))){let l=Fe(a,r),c=Kt(Fe(l,"module.css"));if(c&&!s(`modules/${r}/module.css`,c))break}if(Gn(a))for(let r of Un(a).filter(l=>l.endsWith(".module"))){let l=Fe(a,r),c=Kt(Fe(l,"module.html"));if(c&&!s(`modules/${r}/module.html`,c))break}if(Gn(a))for(let r of Un(a).filter(l=>l.endsWith(".module"))){let l=Fe(a,r),c=Kt(Fe(l,"fields.json"));if(c&&!s(`modules/${r}/fields.json`,c))break}return e.join("")}function dd(){if(!Wn)try{Wn=w(qt("extraction-prompt.md"))}catch{Wn=""}return Wn}function Ds(t,e,n){return new Promise((s,o)=>{let i={...process.env};delete i.CLAUDECODE;let a=ad(t,e,{stdio:["pipe","pipe","pipe"],env:i,shell:!0}),r="",l="";a.stdout.on("data",c=>{r+=c.toString()}),a.stderr.on("data",c=>{l+=c.toString()}),a.on("error",c=>o(new Error(`${t} failed to start: ${c.message}`))),a.on("close",c=>{c===0||r.trim()?s(r.trim()):o(new Error(`${t} exited with code ${c}: ${l.trim()}`))}),a.stdin.write(n),a.stdin.end()})}async function ud(t,e){e?.({status:"Collecting theme files..."});let n=Wr(t);if(!n.trim())throw new Error("No CSS, HTML, or fields.json files found in theme.");let s=dd();if(!s)throw new Error("Extraction prompt not found (assets/extraction-prompt.md).");let o=`Analyze this HubSpot CMS theme and extract the design system:
|
|
7
|
-
${n}`;e?.({status:"Analyzing design patterns..."});let i=_(),a=i.aiEngine||"anthropic-api",r="";switch(a){case"anthropic-api":case"api":{let l=ge("anthropic-api");if(!l)throw new Error("Anthropic API key not configured. Open Settings to add one.");let c=await ld();r=(await new c({apiKey:l}).messages.create({model:i.anthropicApiModel||"claude-sonnet-4-6",max_tokens:8e3,system:s,messages:[{role:"user",content:o}]})).content.filter(p=>p.type==="text").map(p=>p.text).join("");break}case"openai-api":{let l=ge("openai-api");if(!l)throw new Error("OpenAI API key not configured. Open Settings to add one.");let c=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`},body:JSON.stringify({model:i.openaiApiModel||"gpt-4o",max_tokens:8e3,messages:[{role:"system",content:s},{role:"user",content:o}]})});if(!c.ok)throw new Error(`OpenAI API error: ${c.status} ${await c.text()}`);r=(await c.json()).choices?.[0]?.message?.content||"";break}case"gemini-api":{let l=ge("gemini-api");if(!l)throw new Error("Gemini API key not configured. Open Settings to add one.");let c=i.geminiApiModel||"gemini-2.5-flash",d=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${c}:generateContent?key=${l}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({system_instruction:{parts:[{text:s}]},contents:[{role:"user",parts:[{text:o}]}],generationConfig:{maxOutputTokens:8e3}})});if(!d.ok)throw new Error(`Gemini API error: ${d.status} ${await d.text()}`);r=(await d.json()).candidates?.[0]?.content?.parts?.map(p=>p.text).join("")||"";break}case"claude-code":{let l=`${s}
|
|
8
|
-
|
|
9
|
-
## User Request
|
|
10
|
-
${o}`,c=["--print"];i.claudeCodeModel&&c.push("--model",i.claudeCodeModel),r=await Ds("claude",c,l);break}case"gemini-cli":{let l=`${s}
|
|
11
|
-
|
|
12
|
-
## User Request
|
|
13
|
-
${o}`;r=await Ds("gemini",[],l);break}case"codex-cli":{let l=`${s}
|
|
14
|
-
|
|
15
|
-
## User Request
|
|
16
|
-
${o}`;r=await Ds("codex",[],l);break}default:throw new Error(`Unknown AI engine: ${a}. Open Settings to configure one.`)}if(!r.trim())throw new Error("AI returned empty response.");return e?.({status:"Design extraction complete."}),r}var Js,cd,Wn,Ls=lt(()=>{"use strict";g();Q();te();Js=null;cd=8e4;Wn=""});g();g();import{Command as Td}from"commander";g();g();g();import ct from"chalk";var Te={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},Ys=!!process.env.NO_COLOR;function De(t){return Ys?ct:ct.hex(t)}var I={accent:De(Te.accent),accentBright:De(Te.accentBright),success:De(Te.success),info:De(Te.info),warn:De(Te.warn),error:De(Te.error),muted:De(Te.muted),vibes:De(Te.vibes),heading:Ys?ct.bold:ct.bold.hex(Te.accent),command:De(Te.accentBright),dim:ct.dim,bold:ct.bold};Q();function Ee(){let t=I.vibes,e=I.accent,n=I.muted,s=[`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584\u2584")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2584\u2584\u2584\u2584\u2584 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584 \u2580\u2580\u2588\u2588\u2580\u2580")}`,`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B ")}${e("\u2580\u2580\u2580\u2584 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t(" \u2588\u2584\u2584\u2588\u2580 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${e(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t(" \u2580\u2580\u2580 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2580\u2580\u2580\u2580\u2580")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2580\u2580\u2580\u2580 \u2588\u2588 \u2580\u2580\u2580\u2580 \u2588\u2588 ")}`];console.log();for(let o of s)console.log(` ${o}`);console.log(),console.log(` ${n("AI-powered HubSpot Landing Pages")} ${I.dim(`v${ut()}`)}`),console.log()}g();g();import{join as en}from"path";import{homedir as tn}from"os";import{readFileSync as so,existsSync as nn,readdirSync as Ca}from"fs";g();import{execSync as Xs}from"child_process";function T(t,e={}){try{return{stdout:Xs(t,{encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:12e4,...e}).trim(),stderr:"",success:!0}}catch(n){let s=n,o=(s.stdout??"").toString().trim(),i=(s.stderr??"").toString().trim();return{stdout:o,stderr:i,success:!1}}}function Qs(t,e={}){try{return Xs(t,{stdio:"inherit",timeout:3e5,...e}),!0}catch{return!1}}te();var et=process.platform==="win32"?"where":"which";function kt(){let t=T("node --version");return{name:"Node.js",found:t.success,version:t.stdout.replace(/^v/,""),path:T(`${et} node`).stdout}}function $t(){let t=T("git --version");return{name:"Git",found:t.success,version:t.stdout.replace("git version ",""),path:T(`${et} git`).stdout}}function Me(){let t=T("hs --version");return{name:"HubSpot CLI",found:t.success,version:t.stdout,path:T(`${et} hs`).stdout}}function Tt(){let t=T("claude --version");if(!t.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=en(tn(),".claude"),n=!1,s="Not signed in \u2014 run `claude` to authenticate";try{if(nn(e)){let o=Ca(e);(o.some(a=>a.includes("credentials")||a.includes("auth")||a.includes("token")||a===".credentials.json")||o.length>2)&&(n=!0,s="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:t.stdout,path:T(`${et} claude`).stdout,authenticated:n,authDetail:s}}function Et(t){try{let e=en(tn(),".hscli","config.yml");if(!nn(e))return"na1";let n=so(e,"utf-8"),s=n.indexOf(`accountId: ${t}`);if(s===-1)return"na1";let o=n.indexOf("personalAccessKey:",s);if(o===-1)return"na1";let a=n.slice(o,o+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!a)return"na1";if(a[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function Ne(){let t=T("hs accounts list");if(!t.success||!t.stdout)return{authenticated:!1,portalName:"",portalId:"",accounts:[]};let e=[],n="",s="",o=t.stdout.match(/Account:\s*(.+?)\s*\((\d+)\)/);o&&(n=o[1].trim(),s=o[2].trim());let i=t.stdout.split(`
|
|
17
|
-
`);for(let a of i){let r=a.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(r&&!/Account ID/i.test(a)&&!/^-+$/.test(a.trim())&&!/^Name\s/i.test(a.trim())){let l=r[1].trim(),c=r[2].trim(),d=r[3]?.trim()||"unknown";e.push({name:l,portalId:c,authType:d,isDefault:c===s})}}return o?{authenticated:!0,portalName:n,portalId:s,accounts:e}:e.length>0?{authenticated:!0,portalName:e[0].name,portalId:e[0].portalId,accounts:e}:{authenticated:t.stdout.length>0,portalName:"",portalId:"",accounts:[]}}function Mt(){let t=T("gemini --version");if(!t.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=en(tn(),".config","gcloud","application_default_credentials.json"),n=nn(e),s=!!(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||process.env.GOOGLE_AI_API_KEY),o=n||s;return{name:"Gemini CLI",found:!0,version:t.stdout,path:T(`${et} gemini`).stdout,authenticated:o,authDetail:o?"Authenticated":"Run `gemini` to sign in with Google"}}function Nt(){let t=T("codex --version");if(!t.success)return{name:"OpenAI Codex CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=!!process.env.OPENAI_API_KEY,n=!1;try{let i=en(tn(),".codex","auth.json");nn(i)&&(n=so(i,"utf-8").length>10)}catch{}let s=e||n,o=n?"Authenticated (OAuth)":e?"Authenticated (API key)":"Not authenticated";return{name:"OpenAI Codex CLI",found:!0,version:t.stdout,path:T(`${et} codex`).stdout,authenticated:s,authDetail:o}}function Qn(){let t=T("gh --version");return{name:"GitHub CLI",found:t.success,version:t.stdout.split(`
|
|
18
|
-
`)[0]?.replace("gh version ","").split(" ")[0]||"",path:T(`${et} gh`).stdout}}function Zn(){let t=T("gh auth status 2>&1");if(!t.success&&!t.stdout)return{authenticated:!1,username:""};let e=t.stdout||t.stderr||"",n=e.match(/Logged in to github\.com.*account\s+(\S+)/);if(n)return{authenticated:!0,username:n[1]};let s=e.match(/account\s+(\S+)/);return s&&e.includes("Logged in")?{authenticated:!0,username:s[1]}:{authenticated:e.includes("Logged in"),username:""}}function oo(){return!!process.env.ANTHROPIC_API_KEY}function sn(t){return parseInt(t.split(".")[0],10)>=18}function io(t){let e=parseInt(t.split(".")[0],10);return!isNaN(e)&&e>=8}function Aa(){let t=_(),e=t.hubspotUploadMode||"api",n=t.hubspotAccounts||[],s=n.map(i=>({name:i.portalName,portalId:i.portalId,authType:"personalaccesskey",isDefault:i.portalId===(t.activeHubSpotAccount||n[0]?.portalId)})),o=Ze();return{authenticated:!!o,portalName:o?.portalName||"",portalId:o?.portalId||"",dataCenter:o?o.dataCenter:"na1",accounts:s,uploadMode:e}}var Xn={name:"",found:!1,version:"",path:"",authenticated:!1,authDetail:"Disabled"};function on(){let t=_(),e=kt(),n=$t(),s=t.hubspotUploadMode||"api",o;if(s==="cli"){let b=Me(),A=b.found?Ne():{authenticated:!1,portalName:"",portalId:"",accounts:[]},k=A.portalId?Et(A.portalId):"na1";o={...b,...A,dataCenter:k,uploadMode:"cli"}}else o={name:"HubSpot API",found:!0,version:"v3",path:"",...Aa()};let i=Qn(),a=i.found?Zn():{authenticated:!1,username:""},r=t.enabledCLITools||[],l=Zt("claude-code")?Tt():{...Xn,name:"Claude Code"},c=Zt("gemini-cli")?Mt():{...Xn,name:"Gemini CLI"},d=Zt("codex-cli")?Nt():{...Xn,name:"OpenAI Codex CLI"};function u(b,...A){if(b)return{configured:!0,masked:qn(b),source:"config"};for(let k of A)if(process.env[k])return{configured:!0,masked:qn(process.env[k]),source:"env"};return{configured:!1,masked:"",source:null}}let p=u(t.anthropicApiKey,"ANTHROPIC_API_KEY"),f=u(t.openaiApiKey,"OPENAI_API_KEY"),h=u(t.geminiApiKey,"GEMINI_API_KEY","GOOGLE_AI_API_KEY"),y=[];return l.found&&l.authenticated&&y.push("claude-code"),p.configured&&y.push("anthropic-api"),f.configured&&y.push("openai-api"),c.found&&c.authenticated&&y.push("gemini-cli"),h.configured&&y.push("gemini-api"),d.found&&d.authenticated&&y.push("codex-cli"),{tools:{node:e,git:n,hubspot:o,github:{...i,...a},claudeCode:l,geminiCli:c,codexCli:d},apiKeys:{anthropic:p,openai:f,gemini:h},activeEngine:t.aiEngine||null,availableEngines:y,enabledCLITools:r}}te();tt();g();import*as B from"@clack/prompts";function ts(t){B.isCancel(t)&&(B.cancel(I.muted("Operation cancelled.")),process.exit(0))}async function le(t){B.intro(I.heading(t))}async function ce(t){B.outro(I.success(t))}async function _e(t,e){B.note(t,e?I.heading(e):void 0)}async function Ae(t){let e=await B.text({message:I.accent(t.message),placeholder:t.placeholder,defaultValue:t.defaultValue,validate:t.validate});return ts(e),e}async function ne(t){let e=await B.confirm({message:I.accent(t.message),initialValue:t.initialValue??!0});return ts(e),e}async function pt(t){let e=await B.select({message:I.accent(t.message),options:t.options});return ts(e),e}async function de(){let t=B.spinner();return{start:e=>t.start(I.muted(e)),stop:e=>t.stop(I.success(e)),message:e=>t.message(I.muted(e))}}function q(t){B.log.info(t)}function F(t){B.log.success(I.success(t))}function V(t){B.log.warn(I.warn(t))}function U(t){B.log.error(I.error(t))}async function cn(){await le("Checking your environment");let t=kt();t.found||(U("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),sn(t.version)||(U(`Node.js ${t.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),F(`Node.js v${t.version}`);let e=$t();e.found||(U("Git not found. Install it from https://git-scm.com"),process.exit(1)),F(`Git ${e.version}`);let n=_(),s=n.hubspotUploadMode!=="cli",o="",i="";if(s){let y=he(),b=Ze();if(y)o=b?.portalId||"",i=b?.portalName||"",F(`HubSpot${i?`: ${i}`:""}${o?` (${o})`:""} \u2014 API mode`);else{V("No HubSpot account connected"),await _e(`You need a Personal Access Key to deploy themes.
|
|
19
|
-
Create one at: https://app.hubspot.com/l/personal-access-key
|
|
20
|
-
Make sure the Content scope is enabled.`,"HubSpot connection required");let A=await Ae({message:"Paste your Personal Access Key:",placeholder:"pat-na1-...",validate:$=>$.trim()?void 0:"Key is required"}),k=await de();k.start("Validating key...");try{let $=await an(A);Qt(A,$.portalId,$.portalName,$.dataCenter),y=A,o=$.portalId,i=$.portalName,k.stop(`Connected to ${$.portalName} (${$.portalId})`)}catch($){k.stop("Validation failed"),U(`Invalid key: ${$ instanceof Error?$.message:String($)}`),process.exit(1)}}}else{let y=Me();if(y.found)F(`HubSpot CLI v${y.version}`);else{V("HubSpot CLI not found"),await ne({message:"Install HubSpot CLI globally?"})||(U("HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli"),process.exit(1));let k=await de();k.start("Installing HubSpot CLI..."),T("npm install -g @hubspot/cli").success||(k.stop("Failed"),U("Try: npm install -g @hubspot/cli"),process.exit(1)),y=Me(),k.stop(`HubSpot CLI v${y.version} installed`)}let b=Ne();if(b.authenticated)F(`HubSpot portal${b.portalName?`: ${b.portalName}`:""} (ID: ${b.portalId})`);else{V("HubSpot not authenticated"),await ne({message:"Run `hs init` now?"})||(U("Run `hs init` manually."),process.exit(1));let k=await de();k.start("Waiting for HubSpot authentication..."),Qs("hs init")||(k.stop("Authentication failed"),process.exit(1)),b=Ne(),k.stop(`Connected to portal${b.portalName?`: ${b.portalName}`:""} (ID: ${b.portalId})`)}o=b.portalId,i=b.portalName}let a=Tt(),r=Mt(),l=Nt(),c=oo(),d={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"},u,p=n.aiEngine,f=[];if(a.found&&f.push({value:"claude-code",label:"Claude Code",hint:p==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),r.found&&f.push({value:"gemini-cli",label:"Gemini CLI",hint:p==="gemini-cli"?"last used":"uses your existing Gemini setup"}),l.found&&f.push({value:"codex-cli",label:"OpenAI Codex",hint:p==="codex-cli"?"last used":"uses your existing OpenAI setup"}),c&&f.push({value:"api",label:"Anthropic API",hint:p==="api"?"last used":"uses your API key"}),p&&f.sort((y,b)=>y.value===p?-1:b.value===p?1:0),f.length===1)u=f[0].value,F(`AI engine: ${d[u]} (auto-detected)`);else if(f.length>1)u=await pt({message:"Choose your AI engine:",options:f});else if(await _e(`You need an AI coding assistant to power the conversion.
|
|
21
|
-
|
|
22
|
-
${I.bold("Option 1:")} Install Claude Code ${I.muted("(recommended)")}
|
|
23
|
-
https://claude.ai/code
|
|
24
|
-
|
|
25
|
-
${I.bold("Option 2:")} Install Gemini CLI
|
|
26
|
-
https://github.com/google-gemini/gemini-cli
|
|
27
|
-
|
|
28
|
-
${I.bold("Option 3:")} Install OpenAI Codex
|
|
29
|
-
https://github.com/openai/codex
|
|
30
|
-
|
|
31
|
-
${I.bold("Option 4:")} Set an Anthropic API key
|
|
32
|
-
export ANTHROPIC_API_KEY=sk-ant-...
|
|
33
|
-
(get one at https://console.anthropic.com)`,"AI engine required"),u=await pt({message:"Which will you set up?",options:[{value:"claude-code",label:"Claude Code",hint:"I'll install it now"},{value:"gemini-cli",label:"Gemini CLI",hint:"I'll install it now"},{value:"codex-cli",label:"OpenAI Codex",hint:"I'll install it now"},{value:"api",label:"Anthropic API",hint:"I'll enter my key"}]}),u==="api"){let y=await Ae({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:b=>b.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=y,z({anthropicApiKey:y})}let h;return u==="claude-code"&&(h=await pt({message:"Which model?",options:[{value:"sonnet",label:"Sonnet",hint:"fast, recommended"},{value:"opus",label:"Opus",hint:"most capable"},{value:"haiku",label:"Haiku",hint:"fastest, cheapest"}]})),z({aiEngine:u}),await ce("Environment ready!"),{aiEngine:u,model:h,portalId:o,portalName:i}}g();import{readdirSync as ns,statSync as _a}from"fs";import{join as X,basename as ss,extname as Pa}from"path";Q();function mo(t){let e=[],n=[X(t,"src/components/landing"),X(t,"src/components/sections"),X(t,"src/components"),X(t,"src/pages"),X(t,"app/components"),X(t,"components")];for(let s of n)if(S(s))try{let o=ns(s);for(let i of o){let a=X(s,i);if(!_a(a).isFile())continue;let l=Pa(i);if(![".tsx",".jsx"].includes(l))continue;let c=ss(i,l);if(c.startsWith("ui")||c==="index")continue;let d=w(a),u=Ra(c,d);e.push({name:c,path:a,description:u})}}catch{}return e}function Ra(t,e){let n=[];return/carousel|slider|swiper|embla/i.test(e)&&n.push("carousel"),/accordion|collapsible|expand/i.test(e)&&n.push("accordion"),/form|submit|input.*email/i.test(e)&&n.push("form"),/nav|navigation|menu/i.test(e)&&n.push("navigation"),/hero|headline|tagline/i.test(e)&&n.push("hero"),/footer|copyright/i.test(e)&&n.push("footer"),/testimonial|quote|review/i.test(e)&&n.push("testimonials"),/pricing|plan|tier/i.test(e)&&n.push("pricing"),/faq|question.*answer/i.test(e)&&n.push("FAQ"),/feature|benefit|advantage/i.test(e)&&n.push("features"),/contact|get.in.touch/i.test(e)&&n.push("contact"),/cta|call.to.action/i.test(e)&&n.push("CTA"),/team|member|bio/i.test(e)&&n.push("team"),n.length===0?t.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim():n.join(", ")}function po(t){let e=[X(t,"src/index.css"),X(t,"src/globals.css"),X(t,"src/app/globals.css"),X(t,"app/globals.css")],n=0,s=[];for(let o of e){if(!S(o))continue;let i=w(o),a=i.match(/--[\w-]+:/g);a&&(n+=a.length);let r=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(r)for(let c of r){let d=c.match(/['"]([^'"]+)['"]/)?.[1];d&&!s.includes(d)&&s.push(d)}let l=i.match(/@import\s+url\([^)]*fonts\.googleapis\.com[^)]*family=([^&)]+)/g);if(l)for(let c of l){let d=c.match(/family=([^&)]+)/)?.[1]?.replace(/\+/g," ");d&&!s.includes(d)&&s.push(d)}}return{varCount:n,fonts:s}}function fo(t){let e=[],n=X(t,"src/hooks");if(S(n))try{let o=ns(n);for(let i of o)/scroll/i.test(i)&&e.push("Scroll animations"),/intersection/i.test(i)&&e.push("Scroll animations")}catch{}let s=X(t,"src/components/landing");if(S(s))try{let o=ns(s);for(let i of o){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let a=w(X(s,i));/carousel|embla|swiper/i.test(a)&&!e.includes("Carousel")&&e.push("Carousel"),/accordion|collapsible/i.test(a)&&!e.includes("Accordion")&&e.push("Accordion"),/typing|typewriter/i.test(a)&&!e.includes("Typing animation")&&e.push("Typing animation"),/parallax|requestAnimationFrame/i.test(a)&&!e.includes("Parallax")&&e.push("Parallax")}}catch{}return e.length===0&&e.push("Scroll animations"),e}function go(t){let e,n=!1;if(t.startsWith("http")||t.startsWith("git@")){n=!0;let l=ss(t.replace(/\.git$/,""))||"react-source";if(e=X(process.cwd(),"workspace",l),!S(e)){let c=T(`git clone --depth 1 "${t}" "${e}"`);if(!c.success)throw new Error(`Failed to clone ${t}: ${c.stderr}`)}}else if(e=t,!S(e))throw new Error(`Directory not found: ${e}`);let s=mo(e),o=S(X(e,"tailwind.config.ts"))||S(X(e,"tailwind.config.js")),{varCount:i,fonts:a}=po(e),r=fo(e);return{sourceDir:e,wasCloned:n,components:s,hasTailwind:o,cssVarCount:i,fonts:a,interactions:r}}async function dn(){await le("Source Project");let t=await Ae({message:"GitHub URL or local path to your React project:",placeholder:"https://github.com/user/my-lovable-page",validate:h=>{if(!h.trim())return"Please enter a URL or path"}}),e,n=!1;if(t.startsWith("http")||t.startsWith("git@")){n=!0;let h=ss(t.replace(/\.git$/,""))||"react-source";if(e=X(process.cwd(),"workspace",h),S(e))F(`Using existing clone: ${I.dim(e)}`);else{let y=await de();y.start("Cloning repository..."),T(`git clone --depth 1 "${t}" "${e}"`).success||(y.stop("Clone failed"),U(`Failed to clone ${t}. Check the URL and your access permissions.`),process.exit(1)),y.stop(`Cloned to ${I.dim(e)}`)}}else e=t,S(e)||(U(`Directory not found: ${e}`),process.exit(1)),F(`Using local source: ${I.dim(e)}`);let s=await de();s.start("Analyzing project structure...");let o=mo(e),i=S(X(e,"tailwind.config.ts"))||S(X(e,"tailwind.config.js")),{varCount:a,fonts:r}=po(e),l=fo(e);s.stop(`Found ${o.length} landing page components`),o.length===0&&(V("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=o.map((h,y)=>` ${I.dim(`${y+1}.`)} ${I.bold(h.name)} ${I.muted(`\u2014 ${h.description}`)}`).join(`
|
|
34
|
-
`),d=i?`Tailwind + custom CSS (${a} variables)`:`Custom CSS (${a} variables)`,u=r.length>0?r.join(", "):"System fonts",p=l.join(", ");return await _e(`${c}
|
|
35
|
-
|
|
36
|
-
CSS: ${d}
|
|
37
|
-
JS: ${p}
|
|
38
|
-
Font: ${u}`,`${o.length} components detected`),await ne({message:"Does this look right?"})||(U("Please adjust your source directory and try again."),process.exit(0)),await ce("Source analyzed!"),{sourceDir:e,wasCloned:n,components:o,hasTailwind:i,cssVarCount:a,fonts:r,interactions:l}}g();import{join as Ot}from"path";Q();te();g();import{mkdirSync as Ve,writeFileSync as un}from"fs";import{join as Ie}from"path";function mn(t,e){Ve(t,{recursive:!0}),Ve(Ie(t,"templates"),{recursive:!0}),Ve(Ie(t,"modules"),{recursive:!0}),Ve(Ie(t,"css"),{recursive:!0}),Ve(Ie(t,"js"),{recursive:!0}),Ve(Ie(t,"images"),{recursive:!0}),Ve(Ie(t,"assets"),{recursive:!0});let n={label:e,preview_path:"./templates/home.html",screenshot_path:"./images/template-previews/home.png",enable_domain_stylesheets:!1,version:"1.0.0",author:{name:"vibeSpot",url:"https://github.com/borismichel/vibespot"}};un(Ie(t,"theme.json"),JSON.stringify(n,null,2)+`
|
|
39
|
-
`),un(Ie(t,"fields.json"),`[]
|
|
40
|
-
`);let s=`<!--
|
|
41
|
-
templateType: page
|
|
42
|
-
isAvailableForNewContent: false
|
|
43
|
-
label: ${e} (placeholder)
|
|
44
|
-
screenshotPath: ../images/template-previews/home.png
|
|
45
|
-
-->
|
|
46
|
-
{% extends "./layouts/base.html" %}
|
|
47
|
-
|
|
48
|
-
{% block body %}
|
|
49
|
-
{% dnd_area "main_content"
|
|
50
|
-
label="Main Content",
|
|
51
|
-
class="body-container body-container--${e}"
|
|
52
|
-
%}
|
|
53
|
-
{% end_dnd_area %}
|
|
54
|
-
{% endblock body %}
|
|
55
|
-
`;un(Ie(t,"templates","home.html"),s);let o=`<!--
|
|
56
|
-
templateType: none
|
|
57
|
-
isAvailableForNewContent: false
|
|
58
|
-
label: Base Layout
|
|
59
|
-
-->
|
|
60
|
-
<!DOCTYPE html>
|
|
61
|
-
<html lang="{{ html_lang }}" {{ html_lang_dir }}>
|
|
62
|
-
<head>
|
|
63
|
-
<meta charset="utf-8">
|
|
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 %}
|
|
68
|
-
{{ standard_header_includes }}
|
|
69
|
-
</head>
|
|
70
|
-
<body>
|
|
71
|
-
{% block body %}{% endblock body %}
|
|
72
|
-
{% if template_js %}
|
|
73
|
-
{{ require_js(get_asset_url(template_js)) }}
|
|
74
|
-
{% endif %}
|
|
75
|
-
{{ standard_footer_includes }}
|
|
76
|
-
</body>
|
|
77
|
-
</html>
|
|
78
|
-
`;Ve(Ie(t,"templates","layouts"),{recursive:!0}),un(Ie(t,"templates","layouts","base.html"),o)}pn();async function fn(){await le("HubSpot Theme Setup");let t=await pt({message:"Do you have an existing HubSpot theme?",options:[{value:"fetch",label:"Fetch my existing theme from HubSpot",hint:"downloads your current theme"},{value:"create",label:"Start fresh (HubSpot Boilerplate)",hint:"creates a new starter theme"}]}),e,n,s=Ot(process.cwd(),"workspace");if(we(s),t==="fetch"){e=await Ae({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:u=>u.trim()?void 0:"Theme name is required"}),n=Ot(s,e);let l=await de();l.start("Fetching theme from HubSpot...");let c=_(),d=he();if(c.hubspotUploadMode==="cli"||!d)T(`hs cms fetch "${e}" "${n}"`).success||(l.stop("Fetch failed"),U(`Could not fetch theme "${e}". Check the name in HubSpot Design Manager.`),process.exit(1));else try{await Rt(d,e,n)}catch(u){l.stop("Fetch failed"),U(`Could not fetch theme "${e}": ${u instanceof Error?u.message:String(u)}`),process.exit(1)}l.stop(`Theme fetched: ${I.dim(n)}`)}else{e=await Ae({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),n=Ot(s,e);let l=await de();l.start("Creating theme...");try{mn(n,e)}catch(c){l.stop("Creation failed"),U(`Could not create theme "${e}": ${c instanceof Error?c.message:String(c)}`),process.exit(1)}l.stop(`Theme created: ${I.dim(n)}`)}await le("Checking theme compatibility");let o=Ot(n,"templates/layouts/base.html");S(o)||(U(`base.html not found at ${o}. Your theme may have a different structure.`),process.exit(1)),F("base.html found");let i=w(o),a=!1;if(i.includes("template_css"))F("template_css support");else{V("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
|
|
79
|
-
`,i.indexOf("theme-overrides.css"))):i.lastIndexOf("require_css");if(l>0){let c=i.lastIndexOf(`
|
|
80
|
-
`,l);i=i.slice(0,c)+`
|
|
81
|
-
{% if template_css %}
|
|
82
|
-
{{ require_css(get_asset_url(template_css)) }}
|
|
83
|
-
{% endif %}`+i.slice(c),a=!0}}if(i.includes("template_js"))F("template_js support");else{V("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
|
|
84
|
-
`,l),d=i.indexOf(`
|
|
85
|
-
`,c+1),u=`
|
|
86
|
-
{% if template_js %}
|
|
87
|
-
{{ require_js(get_asset_url(template_js)) }}
|
|
88
|
-
{% endif %}`,p=i.indexOf("}}",l)+2+i.slice(i.indexOf("}}",l)+2).indexOf(`
|
|
89
|
-
`)+1;i=i.slice(0,i.indexOf(`
|
|
90
|
-
`,i.indexOf("}}",l)+2))+u+i.slice(i.indexOf(`
|
|
91
|
-
`,i.indexOf("}}",l)+2)),a=!0}}if(a){let l=await de();l.start("Patching base.html..."),H(o,i),l.stop("base.html patched with template_css/template_js support")}let r=Ot(n,".hsignore");if(S(r)){let l=w(r);l.includes("docs/")||(H(r,l+`
|
|
92
|
-
docs/
|
|
93
|
-
`),F("Added docs/ to .hsignore"))}else H(r,`docs/
|
|
94
|
-
*.md
|
|
95
|
-
node_modules/
|
|
96
|
-
.git
|
|
97
|
-
`),F("Created .hsignore");return await ce("Theme ready!"),{themePath:n,themeName:e}}g();import{join as xe}from"path";import{readdirSync as jt,rmSync as Mo}from"fs";g();import{spawn as Da}from"child_process";import{join as W,basename as Ha}from"path";import{readdirSync as Pe,statSync as To,writeFileSync as La}from"fs";g();Q();var bo=new Map;function ft(t){let e=bo.get(t);if(e!==void 0)return e;try{e=w(qt(t))}catch{e=""}return bo.set(t,e),e}function re(){return ft("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function So(){return ft("design-guide.md")}function vo(){return ft("content-guide.md")}function Ke(){return ft("hubspot-rules.md")}function wo(){return ft("humanify-guide.md")}function xo(t){let e=ft("page-types.md");if(!e)return"";let s={landing_page:"## Landing Page",blog_post:"## Blog Post",website_page:"## Website Page",module_only:"## Module Only"}[t];if(!s)return"";let o=e.indexOf(s);if(o<0)return"";let i=e.indexOf(`
|
|
98
|
-
## `,o+s.length);return i>=0?e.slice(o,i).trim():e.slice(o).trim()}function Co(t){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
|
|
1
|
+
var sl=Object.defineProperty;var J=(t,e)=>()=>(t&&(e=t(t=0)),e);var lt=(t,e)=>{for(var n in e)sl(t,n,{get:e[n],enumerable:!0})};import vu from"path";import{fileURLToPath as xu}from"url";var g=J(()=>{"use strict"});import{readFileSync as gs,writeFileSync as ol,mkdirSync as Ao,existsSync as un}from"fs";import{dirname as il,join as We}from"path";function I(t){return gs(t,"utf-8")}function H(t,e){Ao(il(t),{recursive:!0}),ol(t,e,"utf-8")}function S(t){return un(t)}function Ae(t){Ao(t,{recursive:!0})}function mn(t){let e=[We(import.meta.dirname,"../../assets",t),We(import.meta.dirname,"../assets",t),We(process.cwd(),"assets",t)];for(let n of e)if(un(n))return n;throw new Error(`Asset not found: ${t}`)}function St(){if(bt)return bt;let t=[We(import.meta.dirname,"../../package.json"),We(import.meta.dirname,"../package.json"),We(process.cwd(),"package.json")];for(let e of t)if(un(e))try{let n=JSON.parse(gs(e,"utf-8"));if(n.name==="vibespot"&&n.version)return bt=n.version,bt}catch{}return bt="dev",bt}function Io(){if(dn)return dn;let t=[We(import.meta.dirname,"../../CHANGELOG.md"),We(import.meta.dirname,"../CHANGELOG.md"),We(process.cwd(),"CHANGELOG.md")];for(let e of t)if(un(e))try{return dn=gs(e,"utf-8"),dn}catch{}return""}var bt,dn,Z=J(()=>{"use strict";g();bt="";dn=""});import{execSync as ko}from"child_process";function T(t,e={}){try{return{stdout:ko(t,{encoding:"utf-8",stdio:["pipe","pipe","pipe"],timeout:12e4,...e}).trim(),stderr:"",success:!0}}catch(n){let s=n,o=(s.stdout??"").toString().trim(),i=(s.stderr??"").toString().trim();return{stdout:o,stderr:i,success:!1}}}function $o(t,e={}){try{return ko(t,{stdio:"inherit",timeout:3e5,...e}),!0}catch{return!1}}var ct=J(()=>{"use strict";g()});var No={};lt(No,{addHubSpotAccount:()=>Ot,getActiveHubSpotAccount:()=>Xe,getApiKeyForEngine:()=>ge,getConfigDir:()=>ll,getHubSpotPak:()=>he,isCliToolEnabled:()=>jt,loadConfig:()=>M,maskApiKey:()=>fn,removeHubSpotAccount:()=>hs,saveConfig:()=>q,setActiveHubSpotAccount:()=>ys,setCliToolEnabled:()=>bs});import{join as To}from"path";import{homedir as rl}from"os";import{chmodSync as al}from"fs";function M(){if(!S(pn))return{};try{let t=JSON.parse(I(pn));return t.aiEngine==="api"&&(t.aiEngine="anthropic-api"),t}catch{return{}}}function ge(t,e){let n=e||M();switch(t){case"anthropic-api":case"api":return n.anthropicApiKey||process.env.ANTHROPIC_API_KEY;case"openai-api":return n.openaiApiKey||process.env.OPENAI_API_KEY;case"gemini-api":return n.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY;default:return}}function fn(t){return t.length<=12?"***":t.slice(0,7)+"..."+t.slice(-4)}function q(t){let n={...M(),...t};if(H(pn,JSON.stringify(n,null,2)),process.platform!=="win32")try{al(pn,384)}catch{}}function ll(){return Eo}function Xe(){let t=M();if(!t.hubspotAccounts?.length)return null;let e=t.activeHubSpotAccount;if(e){let n=t.hubspotAccounts.find(s=>s.portalId===e);if(n)return n}return t.hubspotAccounts[0]||null}function Ot(t,e,n,s){let i=M().hubspotAccounts||[],a=i.findIndex(l=>l.portalId===e),r={portalId:e,portalName:n,personalAccessKey:t,dataCenter:s,addedAt:new Date().toISOString()};a>=0?i[a]=r:i.push(r),q({hubspotAccounts:i,activeHubSpotAccount:e})}function hs(t){let e=M(),n=(e.hubspotAccounts||[]).filter(o=>o.portalId!==t),s={hubspotAccounts:n};e.activeHubSpotAccount===t&&(s.activeHubSpotAccount=n[0]?.portalId||void 0),q(s)}function ys(t){q({activeHubSpotAccount:t})}function he(){return Xe()?.personalAccessKey||null}function jt(t){return M().enabledCLITools?.includes(t)??!1}function bs(t,e){let n=M(),s=new Set(n.enabledCLITools||[]);e?s.add(t):s.delete(t),q({enabledCLITools:[...s]})}var Eo,pn,ee=J(()=>{"use strict";g();Z();Eo=To(rl(),".vibespot"),pn=To(Eo,"config.json")});import{readFileSync as ul}from"fs";import{basename as ml}from"path";async function Oo(t){let e=Ro.get(t);if(e&&e.expiresAt-Date.now()>gl)return e;let n=await fetch(`${Be}/localdevauth/v1/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({encodedOAuthRefreshToken:t})});if(!n.ok){let i=await n.text().catch(()=>"");throw new Error(n.status===401||n.status===403?"Invalid or expired Personal Access Key":`Token exchange failed (${n.status}): ${i.slice(0,200)}`)}let s=await n.json(),o={accessToken:s.oauthAccessToken,expiresAt:s.expiresAtMillis,hubId:s.hubId,hubName:s.hubName||""};return Ro.set(t,o),o}async function vt(t){let{accessToken:e}=await Oo(t);return{Authorization:`Bearer ${e}`}}function vn(t){return t.replace(/^\/+/,"").split("/").filter(Boolean).map(encodeURIComponent).join("/")}function hl(t){return t.startsWith("pat-eu1-")?"eu1":t.startsWith("pat-na1-")?"na1":t.startsWith("CiRldTE")?"eu1":"na1"}function yl(t){return new Promise(e=>setTimeout(e,t))}async function Ut(t,e){let n=`HTTP ${t.status}`,s,o;try{let i=await t.json();if(i.message&&typeof i.message=="string"&&(n=i.message),i.category&&typeof i.category=="string"&&(s=i.category),i.errors&&Array.isArray(i.errors)&&i.errors.length>0){let a=i.errors[0];o=a.message||JSON.stringify(a)}}catch{try{let i=await t.text();i&&(n=i.slice(0,500))}catch{}}return{status:t.status,message:e?`${n} (${e})`:n,category:s,detail:o}}async function Wt(t,e,n=pl){for(let s=0;s<=n;s++){let o=await fetch(t,e);if(o.status===429||o.status>=500&&s<n){let i=fl*Math.pow(2,s);await yl(i);continue}return o}return fetch(t,e)}async function wn(t){let e=await Oo(t),n=`${Be}/account-info/v3/details`,s=await Wt(n,{headers:await vt(t)});if(!s.ok){let r=await Ut(s);throw new Error(`Failed to get account info: ${r.message}`)}let o=await s.json(),i=String(o.portalId||e.hubId||""),a=e.hubName||o.uiDomain||i;return{portalId:i,portalName:a,dataCenter:hl(t)}}async function jo(t,e,n){let s=ul(n),o=ml(n),i=new FormData,a=new Blob([s]);i.append("file",a,o);let r=`${Be}/cms/v3/source-code/published/content/${vn(e)}`,l=await Wt(r,{method:"PUT",headers:await vt(t),body:i});if(!l.ok){let c=await Ut(l,e);return{success:!1,path:e,error:c}}return{success:!0,path:e}}async function xs(t,e){let n=`${Be}/cms/v3/source-code/published/content/${vn(e)}`,s=await Wt(n,{method:"DELETE",headers:await vt(t)});if(!s.ok&&s.status!==404){let o=await Ut(s,e);throw new Error(`Failed to delete ${e}: ${o.message}`)}}async function Fo(t,e){let n=`${Be}/cms/v3/source-code/published/content/${vn(e)}`,s=await Wt(n,{method:"GET",headers:await vt(t)});if(!s.ok){let i=await Ut(s,e);throw new Error(`Failed to download ${e}: ${i.message}`)}let o=await s.arrayBuffer();return Buffer.from(o)}async function xn(t,e){let n=`${Be}/cms/v3/source-code/published/metadata/${vn(e)}`,s=await Wt(n,{method:"GET",headers:await vt(t)});if(s.status===404)return null;if(!s.ok){let o=await Ut(s,e);throw new Error(`Failed to get metadata for ${e}: ${o.message}`)}return await s.json()}async function Jo(t){let e=await vt(t),n=[`${Be}/cms/v3/source-code/published/metadata`,`${Be}/cms/v3/source-code/published/metadata/`,`${Be}/designmanager/v1/portals/content/listing`];for(let s of n)try{let o=await fetch(s,{method:"GET",headers:e});if(o.ok){let i=await o.json(),a=i.children||i.objects||(Array.isArray(i)?i:null);if(a&&a.length>0)return a.filter(r=>r.folder)}}catch{}return[]}var Be,pl,fl,gl,Ro,ut=J(()=>{"use strict";g();Be="https://api.hubapi.com",pl=3,fl=1e3,gl=300*1e3,Ro=new Map});var Wo={};lt(Wo,{fetchTheme:()=>Bt});import{mkdirSync as Uo,writeFileSync as wl}from"fs";import{join as xl,dirname as Cl}from"path";async function ks(t,e){let n=await xn(t,e);if(!n)return[];if(!n.folder)return[n.path||e];let s=[],o=n.children||[];for(let i of o){let a=typeof i=="string"?i:i.name;if(!a)continue;let r=`${e}/${a}`;if(typeof i=="string")s.push(...await ks(t,r));else{let l=i;l.folder?s.push(...await ks(t,l.path||r)):s.push(l.path||r)}}return s}async function Al(t,e,n){let s=0;async function o(){for(;s<t.length;){let a=s++;await n(t[a])}}let i=Array.from({length:Math.min(e,t.length)},()=>o());await Promise.all(i)}async function Bt(t,e,n,s={}){let o=s.concurrency??5,i=await ks(t,e);if(i.length===0)throw new Error(`Theme "${e}" not found on HubSpot or is empty`);Uo(n,{recursive:!0}),await Al(i,o,async a=>{let r=a.startsWith(e+"/")?a.slice(e.length+1):a,l=xl(n,r);Uo(Cl(l),{recursive:!0});let c=await Fo(t,a);wl(l,c),s.onFile?.(r)})}var $n=J(()=>{"use strict";g();ut()});function xt(t){let e=Bo.get(t);if(e!==void 0)return e;try{e=I(mn(t))}catch{e=""}return Bo.set(t,e),e}function le(){return xt("conversion-guide.md")||"Conversion guide not found. Using built-in rules."}function Ko(){return xt("design-guide.md")}function Vo(){return xt("content-guide.md")}function Ze(){return xt("hubspot-rules.md")}function Yo(){return xt("humanify-guide.md")}function zo(t){let e=xt("page-types.md");if(!e)return"";let s={landing_page:"## Landing Page",blog_post:"## Blog Post",website_page:"## Website Page",module_only:"## Module Only"}[t];if(!s)return"";let o=e.indexOf(s);if(o<0)return"";let i=e.indexOf(`
|
|
2
|
+
## `,o+s.length);return i>=0?e.slice(o,i).trim():e.slice(o).trim()}function qo(t){return`You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.
|
|
99
3
|
|
|
100
4
|
## Rules
|
|
101
5
|
Follow the conversion guide below EXACTLY. Key rules:
|
|
@@ -112,10 +16,10 @@ Follow the conversion guide below EXACTLY. Key rules:
|
|
|
112
16
|
- Convert React hooks to vanilla JS (no React, no npm packages)
|
|
113
17
|
|
|
114
18
|
## HubSpot CMS Rules
|
|
115
|
-
${
|
|
19
|
+
${Ze()}
|
|
116
20
|
|
|
117
21
|
## Conversion Guide
|
|
118
|
-
${t}`}function
|
|
22
|
+
${t}`}function Xo(t,e,n){return`Convert this React component to a HubSpot module named "${e}".
|
|
119
23
|
|
|
120
24
|
Return a JSON object with these keys:
|
|
121
25
|
- fieldsJson: complete fields.json content (as JSON string)
|
|
@@ -130,7 +34,7 @@ ${n}
|
|
|
130
34
|
React component source:
|
|
131
35
|
${t}
|
|
132
36
|
|
|
133
|
-
Return ONLY valid JSON, no markdown fences.`}function
|
|
37
|
+
Return ONLY valid JSON, no markdown fences.`}function Qo(t,e,n){return`Create a shared CSS file for a HubSpot CMS landing page.
|
|
134
38
|
|
|
135
39
|
Extract the design system from the source CSS and Tailwind config below.
|
|
136
40
|
Use the class prefix ".${n}-" for all custom classes.
|
|
@@ -154,7 +58,7 @@ ${t}
|
|
|
154
58
|
Tailwind config:
|
|
155
59
|
${e}
|
|
156
60
|
|
|
157
|
-
Return ONLY the CSS content, no markdown fences.`}function
|
|
61
|
+
Return ONLY the CSS content, no markdown fences.`}function Zo(t,e,n){return`Create a shared vanilla JS file for a HubSpot CMS landing page.
|
|
158
62
|
|
|
159
63
|
Convert the React hooks and interactive components below to plain JavaScript.
|
|
160
64
|
Use the class prefix "${n}-" to match the CSS.
|
|
@@ -172,7 +76,7 @@ ${t}
|
|
|
172
76
|
Interactive component sources:
|
|
173
77
|
${e}
|
|
174
78
|
|
|
175
|
-
Return ONLY the JavaScript content, no markdown fences.`}function
|
|
79
|
+
Return ONLY the JavaScript content, no markdown fences.`}function ei(t,e,n){return`Create a HubSpot page template that assembles these modules:
|
|
176
80
|
|
|
177
81
|
${t.map((s,o)=>`${o+1}. ${s}.module`).join(`
|
|
178
82
|
`)}
|
|
@@ -187,157 +91,21 @@ Template requirements:
|
|
|
187
91
|
- Each module in its own dnd_section with padding zeroed and full_width=true
|
|
188
92
|
- dnd_area label: "${e} Landing Page"
|
|
189
93
|
|
|
190
|
-
Return ONLY the template HTML content, no markdown fences.`}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",p||"(empty)","","=== CLAUDE CODE STDERR ===",f||"(empty)",""].join(`
|
|
194
|
-
`);La(y,$,"utf-8"),o("status",`Log written to ${Ha(y)}`)}catch{}o("scan","Scanning generated files...");let b=this.scanGeneratedFiles(s);if(b.modules.filter(k=>!r.has(k.moduleName+".module")).length===0){let k=p.slice(0,1500)||"(no output)",$=f.slice(0,500);throw new Error(`Claude Code did not create any new module files.
|
|
195
|
-
|
|
196
|
-
This usually means the model described the conversion instead of using Write tool to create files.
|
|
197
|
-
|
|
198
|
-
Possible causes:
|
|
199
|
-
- Model didn't use Write tool (just printed text)
|
|
200
|
-
- Claude Code hit a rate limit or API error
|
|
201
|
-
- The source directory was not accessible
|
|
202
|
-
|
|
203
|
-
Source: ${e.sourceDir}
|
|
204
|
-
Theme: ${s}
|
|
205
|
-
`+($?`
|
|
206
|
-
Stderr:
|
|
207
|
-
${$}
|
|
208
|
-
`:"")+`
|
|
209
|
-
Claude output:
|
|
210
|
-
${k}`)}return b}reportProgress(e,n,s,o,i,a){let r=0,l=this.listDir(W(e,"css"));for(let p of l){if(s.has(p)||!p.endsWith(".css"))continue;let f=`css:${p}`;this.reported.has(f)||(this.reported.add(f),a("created",`Shared CSS (${p})`),r++)}let c=this.listDir(W(e,"js"));for(let p of c){if(o.has(p)||!p.endsWith(".js"))continue;let f=`js:${p}`;this.reported.has(f)||(this.reported.add(f),a("created",`Shared JS (${p})`),r++)}this.expectedModules===0&&(this.expectedModules=this.detectExpectedModules(e,i));let d=this.listModules(e);for(let p of d){if(n.has(p))continue;let f=`module:${p}`;if(!this.reported.has(f)){this.reported.add(f),this.moduleCount++;let h=this.expectedModules>0?`[${this.moduleCount}/${this.expectedModules}]`:`[${this.moduleCount}]`;a("created",`Module ${h}: ${p.replace(".module","")}`),r++}}let u=this.listDir(W(e,"templates"));for(let p of u){if(i.has(p)||!p.endsWith(".html"))continue;let f=`template:${p}`;this.reported.has(f)||(this.reported.add(f),a("created",`Page template (${p})`),r++)}if(r===0)if(this.moduleCount>0){let p=this.expectedModules>0?`/${this.expectedModules}`:"";a("status",`${this.moduleCount}${p} modules created, conversion continuing...`)}else this.reported.size>0?a("status","Shared assets created, building modules..."):a("status","Claude Code is analyzing source files...")}buildFullPrompt(e,n,s){return`You are converting a React landing page to native HubSpot CMS modules.
|
|
211
|
-
|
|
212
|
-
SOURCE DIRECTORY: ${e}
|
|
213
|
-
THEME DIRECTORY: ${n}
|
|
214
|
-
|
|
215
|
-
IMPORTANT \u2014 YOU MUST CREATE REAL FILES:
|
|
216
|
-
You have access to Write, Edit, Read, Glob, Grep, and Bash tools. You MUST use the Write tool to create each file. Do NOT just describe or list what files should be created \u2014 actually call the Write tool for every single file. If you do not call Write, no files will be created and the conversion will fail.
|
|
217
|
-
|
|
218
|
-
STEP-BY-STEP PROCESS:
|
|
219
|
-
1. Use Glob to find all .tsx/.jsx files in ${e}/src/
|
|
220
|
-
2. Use Read to read each component file and understand the page structure
|
|
221
|
-
3. Use Write to create a shared CSS file at ${n}/css/<name>-theme.css
|
|
222
|
-
- Include CSS custom properties, design system variables, utility classes
|
|
223
|
-
- Add theme-override countermeasures (.body-wrapper:has(), scoped !important overrides)
|
|
224
|
-
4. Use Write to create a shared JS file at ${n}/js/<name>-animations.js
|
|
225
|
-
- Convert React hooks to vanilla JS (IntersectionObserver for scroll animations)
|
|
226
|
-
- IIFE wrapper, DOMContentLoaded setup
|
|
227
|
-
5. For EACH visual section of the page, use Write to create ALL FOUR files:
|
|
228
|
-
a. ${n}/modules/<name>.module/fields.json
|
|
229
|
-
- Editable fields for the section content
|
|
230
|
-
- NEVER use "textarea" type (use "text" instead)
|
|
231
|
-
- NEVER use "name" as a field name (use "item_name" instead)
|
|
232
|
-
- Add a "styles" group with "tab": "STYLE" containing color pickers
|
|
233
|
-
b. ${n}/modules/<name>.module/meta.json
|
|
234
|
-
- Must include: host_template_types: ["PAGE"], is_available_for_new_content: true
|
|
235
|
-
c. ${n}/modules/<name>.module/module.html
|
|
236
|
-
- HubL template that renders the section (convert JSX to HubL)
|
|
237
|
-
d. ${n}/modules/<name>.module/module.css
|
|
238
|
-
- REQUIRED \u2014 complete vanilla CSS for this section
|
|
239
|
-
- Must include: layout, spacing, colors, typography, backgrounds, gradients, shadows, borders, hover effects, responsive breakpoints
|
|
240
|
-
- Convert ALL Tailwind classes to BEM-style CSS. Do NOT skip this file.
|
|
241
|
-
6. Use Write to create a page template at ${n}/templates/lp-<name>.html
|
|
242
|
-
- Annotation: templateType: page, isAvailableForNewContent: true
|
|
243
|
-
- Extends "./layouts/base.html"
|
|
244
|
-
- Sets template_css and template_js variables
|
|
245
|
-
- Wraps modules in dnd_area with dnd_section containers
|
|
246
|
-
7. Read ${n}/templates/layouts/base.html and ensure it supports template_css and template_js variables
|
|
247
|
-
|
|
248
|
-
CSS QUALITY: The converted page must visually match the original React page. Every module.css must be self-contained with complete styling for that section.
|
|
249
|
-
|
|
250
|
-
Do NOT run hs upload \u2014 I will handle that separately.
|
|
251
|
-
|
|
252
|
-
HUBSPOT CMS RULES:
|
|
253
|
-
${Ke()}
|
|
254
|
-
|
|
255
|
-
CONVERSION GUIDE:
|
|
256
|
-
${s}`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=W(e,"css");if(S(s)){for(let r of Pe(s))if(r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=w(W(s,r));break}}let o=W(e,"js");if(S(o)){for(let r of Pe(o))if(r.endsWith(".js")&&r!=="main.js"){n.sharedJs=w(W(o,r));break}}let i=W(e,"templates");if(S(i)){for(let r of Pe(i))if(r.startsWith("lp-")&&r.endsWith(".html")){n.template=w(W(i,r));break}if(!n.template){for(let r of Pe(i))if(r.endsWith(".html")&&!Ga.has(r)&&!r.startsWith("system")){let l=w(W(i,r));if(l.includes("dnd_area")){n.template=l;break}}}if(!n.template){for(let r of Pe(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=w(W(i,r));if(l.includes("dnd_area")){n.template=l;break}}}}let a=W(e,"modules");if(S(a))for(let r of Pe(a)){if(!r.endsWith(".module"))continue;let l=W(a,r);if(!To(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=W(l,"fields.json");S(d)&&(c.fieldsJson=w(d));let u=W(l,"meta.json");S(u)&&(c.metaJson=w(u));let p=W(l,"module.html");S(p)&&(c.moduleHtml=w(p));let f=W(l,"module.css");S(f)&&(c.moduleCss=w(f));let h=W(l,"module.js");S(h)&&(c.moduleJs=w(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}listModules(e){let n=W(e,"modules");return S(n)?new Set(Pe(n).filter(s=>s.endsWith(".module"))):new Set}listDir(e){return S(e)?new Set(Pe(e)):new Set}detectExpectedModules(e,n){let s=W(e,"templates");if(!S(s))return 0;for(let o of Pe(s))if(!n.has(o)&&!(!o.endsWith(".html")||o==="base.html"||o.startsWith("system")))try{let i=w(W(s,o));if(i.includes("dnd_area")){let a=i.match(/dnd_module/g);return a?a.length:0}}catch{}return 0}countSourceComponents(e){let n=W(e,"src");return S(n)?this.countComponentsRecursive(n):0}countComponentsRecursive(e){let n=0;for(let s of Pe(e)){let o=W(e,s);try{To(o).isDirectory()&&s!=="node_modules"&&s!==".git"?n+=this.countComponentsRecursive(o):/\.(tsx|jsx)$/.test(s)&&!s.includes(".test.")&&!s.includes(".spec.")&&n++}catch{}}return n}};g();import Ua from"@anthropic-ai/sdk";import{join as K,basename as Wa}from"path";import{readdirSync as Eo}from"fs";Q();var hn=class{client;model="claude-sonnet-4-6";constructor(e){this.client=new Ua({apiKey:e||process.env.ANTHROPIC_API_KEY})}async convert(e){let{sourceDir:n,themePath:s,conversionGuide:o,onProgress:i}=e,a=Co(o),r=Wa(n)||"page",l=r.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,15);i("css","Analyzing design system...");let c=this.findAndReadCSS(n),d=this.findAndReadTailwind(n),u=await this.complete(a,Io(c,d,l)),p=K(s,"css",`${l}-theme.css`);H(p,u),i("css-done",`Created css/${l}-theme.css`),i("js","Creating shared JavaScript...");let f=this.findAndReadHooks(n),h=this.findInteractiveComponents(n),y=await this.complete(a,ko(f,h,l)),b=K(s,"js",`${l}-animations.js`);H(b,y),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let A=this.findComponents(n),k=[];for(let E=0;E<A.length;E++){let J=A[E],ee=J.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${ee}.module (${E+1}/${A.length})...`);let G=w(J.path),L=await this.complete(a,Ao(G,ee,`See css/${l}-theme.css`));try{let O=JSON.parse(L),Y={moduleName:ee,fieldsJson:typeof O.fieldsJson=="string"?O.fieldsJson:JSON.stringify(O.fieldsJson,null,2),metaJson:typeof O.metaJson=="string"?O.metaJson:JSON.stringify(O.metaJson,null,2),moduleHtml:O.moduleHtml||"",moduleCss:O.moduleCss||"",moduleJs:O.moduleJs||void 0},ie=K(s,"modules",`${ee}.module`);we(ie),H(K(ie,"fields.json"),Y.fieldsJson),H(K(ie,"meta.json"),Y.metaJson),H(K(ie,"module.html"),Y.moduleHtml),H(K(ie,"module.css"),Y.moduleCss),Y.moduleJs&&H(K(ie,"module.js"),Y.moduleJs),k.push(Y),i("module-done",`${ee}.module (${this.countFiles(Y)} files)`)}catch{i("module-error",`Failed to parse ${ee} \u2014 skipping`)}}i("template","Creating page template...");let $=k.map(E=>E.moduleName),R=await this.complete(a,$o($,r,l)),M=K(s,"templates",`lp-${l}.html`);return H(M,R),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:u,sharedJs:y,template:R,modules:k}}async complete(e,n){return(await this.client.messages.create({model:this.model,max_tokens:8192,system:e,messages:[{role:"user",content:n}]})).content.find(i=>i.type==="text")?.text||""}findAndReadCSS(e){let n=[K(e,"src/index.css"),K(e,"src/globals.css"),K(e,"src/app/globals.css"),K(e,"app/globals.css")];for(let s of n)if(S(s))return w(s);return""}findAndReadTailwind(e){let n=[K(e,"tailwind.config.ts"),K(e,"tailwind.config.js"),K(e,"tailwind.config.mjs")];for(let s of n)if(S(s))return w(s);return""}findAndReadHooks(e){let n=K(e,"src/hooks");if(!S(n))return"";try{return Eo(n).filter(s=>s.endsWith(".ts")||s.endsWith(".tsx")).map(s=>`// ${s}
|
|
257
|
-
${w(K(n,s))}`).join(`
|
|
258
|
-
|
|
259
|
-
`)}catch{return""}}findInteractiveComponents(e){let n=this.findComponents(e),s=[];for(let o of n){let i=w(o.path);/carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(i)&&s.push(`// ${o.name}
|
|
260
|
-
${i}`)}return s.join(`
|
|
261
|
-
|
|
262
|
-
`)}findComponents(e){let n=[K(e,"src/components/landing"),K(e,"src/components/sections"),K(e,"src/components")];for(let s of n)if(S(s))try{return Eo(s).filter(o=>(o.endsWith(".tsx")||o.endsWith(".jsx"))&&!o.startsWith("ui")&&o!=="index.tsx"&&o!=="index.jsx").map(o=>({name:o.replace(/\.(tsx|jsx)$/,""),path:K(s,o)}))}catch{continue}return[]}countFiles(e){let n=3;return e.moduleCss&&n++,e.moduleJs&&n++,n}};g();import{spawn as Ba}from"child_process";import{join as ye}from"path";import{readdirSync as yn,statSync as Va}from"fs";Q();var bn=class{async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||re(),a=this.buildFullPrompt(n,s,i);return o("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Ba("gemini",["-p",a],{cwd:s,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),d="",u="";c.stdout.on("data",p=>{d+=p.toString()}),c.stderr.on("data",p=>{u+=p.toString()}),c.on("error",p=>l(new Error(`Gemini CLI failed: ${p.message}`))),c.on("close",p=>{p!==0&&u&&!d?l(new Error(`Gemini CLI failed: ${u}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Gemini CLI timed out after 10 minutes"))},6e5)}),o("scan","Scanning generated files..."),this.scanGeneratedFiles(s)}buildFullPrompt(e,n,s){return`Read the conversion guide below, then convert the React landing page at ${e} into native HubSpot CMS modules for the theme at ${n}.
|
|
263
|
-
|
|
264
|
-
INSTRUCTIONS:
|
|
265
|
-
1. Analyze all .tsx/.jsx components in the React source
|
|
266
|
-
2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures
|
|
267
|
-
3. Create a shared JS file in js/ for scroll animations and interactive features
|
|
268
|
-
4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css
|
|
269
|
-
5. Add a styles group with "tab": "STYLE" and color pickers to each module
|
|
270
|
-
6. Create a page template in templates/ that assembles all modules
|
|
271
|
-
7. Make sure base.html supports template_css and template_js variables
|
|
272
|
-
|
|
273
|
-
CONVERSION GUIDE:
|
|
274
|
-
${s}
|
|
275
|
-
|
|
276
|
-
Do NOT run hs upload \u2014 I will handle that separately.
|
|
277
|
-
Create all files directly in the theme directory.`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=ye(e,"css");if(S(s)){for(let r of yn(s))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=w(ye(s,r));break}}let o=ye(e,"js");if(S(o)){for(let r of yn(o))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){n.sharedJs=w(ye(o,r));break}}let i=ye(e,"templates");if(S(i)){for(let r of yn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=w(ye(i,r));if(l.includes("dnd_area")){n.template=l;break}}}let a=ye(e,"modules");if(S(a))for(let r of yn(a)){if(!r.endsWith(".module"))continue;let l=ye(a,r);if(!Va(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=ye(l,"fields.json");S(d)&&(c.fieldsJson=w(d));let u=ye(l,"meta.json");S(u)&&(c.metaJson=w(u));let p=ye(l,"module.html");S(p)&&(c.moduleHtml=w(p));let f=ye(l,"module.css");S(f)&&(c.moduleCss=w(f));let h=ye(l,"module.js");S(h)&&(c.moduleJs=w(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}};g();import{spawn as Ka}from"child_process";import{join as be}from"path";import{readdirSync as Sn,statSync as Ya}from"fs";Q();var vn=class{async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||re(),a=this.buildFullPrompt(n,s,i);return o("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Ka("codex",["exec","--full-auto",a],{cwd:s,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),d="",u="";c.stdout.on("data",p=>{d+=p.toString()}),c.stderr.on("data",p=>{u+=p.toString()}),c.on("error",p=>l(new Error(`Codex CLI failed: ${p.message}`))),c.on("close",p=>{p!==0&&u&&!d?l(new Error(`Codex CLI failed: ${u}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Codex CLI timed out after 10 minutes"))},6e5)}),o("scan","Scanning generated files..."),this.scanGeneratedFiles(s)}buildFullPrompt(e,n,s){return`Read the conversion guide below, then convert the React landing page at ${e} into native HubSpot CMS modules for the theme at ${n}.
|
|
278
|
-
|
|
279
|
-
INSTRUCTIONS:
|
|
280
|
-
1. Analyze all .tsx/.jsx components in the React source
|
|
281
|
-
2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures
|
|
282
|
-
3. Create a shared JS file in js/ for scroll animations and interactive features
|
|
283
|
-
4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css
|
|
284
|
-
5. Add a styles group with "tab": "STYLE" and color pickers to each module
|
|
285
|
-
6. Create a page template in templates/ that assembles all modules
|
|
286
|
-
7. Make sure base.html supports template_css and template_js variables
|
|
287
|
-
|
|
288
|
-
CONVERSION GUIDE:
|
|
289
|
-
${s}
|
|
290
|
-
|
|
291
|
-
Do NOT run hs upload \u2014 I will handle that separately.
|
|
292
|
-
Create all files directly in the theme directory.`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=be(e,"css");if(S(s)){for(let r of Sn(s))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=w(be(s,r));break}}let o=be(e,"js");if(S(o)){for(let r of Sn(o))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){n.sharedJs=w(be(o,r));break}}let i=be(e,"templates");if(S(i)){for(let r of Sn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=w(be(i,r));if(l.includes("dnd_area")){n.template=l;break}}}let a=be(e,"modules");if(S(a))for(let r of Sn(a)){if(!r.endsWith(".module"))continue;let l=be(a,r);if(!Ya(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=be(l,"fields.json");S(d)&&(c.fieldsJson=w(d));let u=be(l,"meta.json");S(u)&&(c.metaJson=w(u));let p=be(l,"module.html");S(p)&&(c.moduleHtml=w(p));let f=be(l,"module.css");S(f)&&(c.moduleCss=w(f));let h=be(l,"module.js");S(h)&&(c.moduleJs=w(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}};Q();function za(t,e){switch(t){case"claude-code":return new gn(e);case"gemini-cli":return new bn;case"codex-cli":return new vn;case"api":return new hn}}async function wn(t){await le("Converting React to HubSpot Modules"),await _e(`AI will now analyze your React code and create
|
|
293
|
-
HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let e=za(t.aiEngine,t.model),n=re(),s=await de();s.start("Starting AI conversion...");let o=Date.now(),i=await e.convert({sourceDir:t.sourceDir,themePath:t.themePath,conversionGuide:n,onProgress:(h,y)=>{h==="created"?F(y):s.message(y)}}),a=((Date.now()-o)/1e3).toFixed(0);s.stop(`AI conversion complete (${a}s)`);let r=qa(t.themePath);for(let h of r)F(`Auto-fixed: ${h}`);let l=Xa(t.themePath,i),c=[];for(let h of l){let y=h.passed?"\u2705":"\u274C",b=h.passed?"":h.critical?" (CRITICAL)":" (cosmetic)";c.push(`${y} ${h.label}${b}`)}let d=l.filter(h=>h.passed).length;c.push(`
|
|
294
|
-
${d}/${l.length} checks passed`),await _e(c.join(`
|
|
295
|
-
`),"Conversion Checklist");let u=l.filter(h=>!h.passed&&h.critical),p=l.filter(h=>!h.passed&&!h.critical);if(u.length>0){if(U(`${u.length} critical issue(s) \u2014 upload will likely fail:
|
|
296
|
-
`+u.map(y=>` - ${y.label}`).join(`
|
|
297
|
-
`)),!await ne({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else p.length>0&&V(`${p.length} non-critical issue(s) \u2014 page will work but may look incomplete:
|
|
298
|
-
`+p.map(h=>` - ${h.label}`).join(`
|
|
299
|
-
`));let f=xe(t.themePath,"..","vibespot-conversion.log");return S(f)&&(await ne({message:"Keep conversion log file for debugging?",initialValue:!1})?F(`Log saved: ${f}`):Mo(f)),await ce("Files ready for upload!"),i}function qa(t){let e=[];Qa(t),Za(t);let n=xe(t,"modules");if(S(n))for(let o of jt(n)){if(!o.endsWith(".module"))continue;let i=xe(n,o,"fields.json");if(!S(i))continue;let a=o.replace(".module",""),r=w(i),l=!1;r.includes('"textarea"')&&(r=r.replace(/"textarea"/g,'"text"'),l=!0,e.push(`${a}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(r)&&(r=r.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,e.push(`${a}: reserved field name "name" \u2192 "item_name"`));try{let d=JSON.parse(r),u=!1;No(d)&&(u=!0,e.push(`${a}: fixed choice field format`)),_o(d)&&(u=!0,e.push(`${a}: fixed link field default value`)),u&&(r=JSON.stringify(d,null,2)+`
|
|
300
|
-
`,l=!0)}catch{e.push(`${a}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&H(i,r);let c=xe(n,o,"module.html");if(S(c)){let d=w(c);d.includes("now()")&&(d=d.replace(/now\(\)/g,"local_dt"),H(c,d),e.push(`${a}: now() \u2192 local_dt`))}}let s=xe(t,"templates");if(S(s))for(let o of jt(s)){if(!o.endsWith(".html"))continue;let i=xe(s,o),a=w(i);(a.includes("hubdb_table")||a.includes("hubdb_table_rows"))&&(Mo(i),e.push(`Removed ${o} (HubDB requires CMS Hub Pro/Enterprise)`))}return e}function No(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;s.type==="choice"&&Array.isArray(s.choices)&&s.choices.some(i=>typeof i=="string")&&(s.choices=s.choices.map(i=>{if(typeof i=="string"){let a=i.charAt(0).toUpperCase()+i.slice(1);return[i,a]}return i}),e=!0),Array.isArray(s.children)&&No(s.children)&&(e=!0)}return e}function _o(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="link"){let o=s.default;if(typeof o=="string"||o===void 0||o===null||typeof o=="object"&&!o.url){let a=typeof o=="string"?o:"";s.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},e=!0}}Array.isArray(s.children)&&_o(s.children)&&(e=!0)}return e}function Xa(t,e){let n=[],s=e.modules.length;n.push({label:`Modules created (${s})`,passed:s>0,critical:!0});let o=!0;for(let u of e.modules)if(u.fieldsJson.includes('"textarea"')||/"name":\s*"name"/.test(u.fieldsJson)){o=!1;break}n.push({label:"fields.json valid (no textarea, no reserved names)",passed:s>0&&o,critical:!0});let i=e.modules.every(u=>u.moduleHtml.length>0);n.push({label:"module.html created for each module",passed:s>0&&i,critical:!0});let a=e.modules.filter(u=>!u.moduleCss).map(u=>u.moduleName),r=a.length===0;n.push({label:r?"module.css created for each module":`module.css missing for: ${a.join(", ")}`,passed:s>0&&r,critical:!1});let l=e.modules.some(u=>u.fieldsJson.includes('"STYLE"'));n.push({label:"Style tab fields (color pickers)",passed:l,critical:!1}),n.push({label:"Shared CSS with design system variables",passed:e.sharedCss.length>50,critical:!1}),n.push({label:"Shared JS for scroll animations",passed:e.sharedJs.length>50,critical:!1}),n.push({label:"Page template with dnd_area",passed:e.template.length>0&&e.template.includes("dnd_area"),critical:!0});let c=xe(t,"templates"),d=!1;if(S(c))for(let u of jt(c)){if(!u.endsWith(".html")||u==="base.html"||u.startsWith("system"))continue;let p=w(xe(c,u));if(p.includes("dnd_area")&&/templateType\s*:\s*page/i.test(p)){d=!0;break}}return n.push({label:"Template annotations (templateType: page)",passed:d,critical:!0}),n}function Qa(t){let e=xe(t,"templates");if(S(e))for(let n of jt(e)){if(!n.endsWith(".html")||n==="base.html"||n.startsWith("system"))continue;let s=xe(e,n),o=w(s);if(!o.includes("dnd_area")&&!o.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(o),a=/isAvailableForNewContent\s*:\s*true/i.test(o);if(i&&a)continue;let r=n.replace(".html","").replace(/[-_]/g," ").replace(/\b\w/g,l=>l.toUpperCase());if(o.includes("<!--")&&o.indexOf("-->")<200){let l=o.indexOf("-->"),c=o.slice(0,l);i||(c+=`
|
|
301
|
-
templateType: page`),a||(c+=`
|
|
302
|
-
isAvailableForNewContent: true`),/label\s*:/i.test(c)||(c+=`
|
|
303
|
-
label: ${r}`),o=c+o.slice(l)}else o=`<!--
|
|
304
|
-
templateType: page
|
|
305
|
-
isAvailableForNewContent: true
|
|
306
|
-
label: ${r}
|
|
307
|
-
-->
|
|
308
|
-
`+o;H(s,o),F(`Template "${n}" \u2014 annotations verified`)}}function Za(t){let e=xe(t,"modules");if(S(e))for(let n of jt(e)){if(!n.endsWith(".module"))continue;let s=xe(e,n,"meta.json");if(S(s))try{let o=JSON.parse(w(s)),i=!1;(!o.host_template_types||!o.host_template_types.includes("PAGE"))&&(o.host_template_types=["PAGE"],i=!0),o.is_available_for_new_content||(o.is_available_for_new_content=!0,i=!0),i&&H(s,JSON.stringify(o,null,2)+`
|
|
309
|
-
`)}catch{}}}g();import{join as Uo,basename as cl}from"path";g();Q();import{join as se}from"path";import{readdirSync as Ue,rmSync as el}from"fs";function xn(t){let e=[];for(let n of t){let s=`${n.message}${n.detail?` \u2014 ${n.detail}`:""}`,o=!1;/textarea|unknown.*field.*type/i.test(s)&&(o=!0),/reserved.*name|missing field name|field null/i.test(s)&&(o=!0),/could not resolve.*now/i.test(s)&&(o=!0),/hubdb|do not have access/i.test(s)&&(o=!0),/invalid default value|link.*invalid|deserializ/i.test(s)&&(o=!0),/color.*invalid/i.test(s)&&(o=!0),e.push({file:n.file||"unknown",message:s,fixable:o})}return e}function Cn(t){let e=[];if(/textarea.*not.*valid|unknown.*field.*type/i.test(t)){let n=t.match(/(?:in|file:?)\s+(\S+fields\.json)/i);e.push({file:n?.[1]||"fields.json",message:'"textarea" is not a valid field type',fixable:!0})}if(/missing field name|field null/i.test(t)){let n=t.match(/(?:in|file:?)\s+(\S+fields\.json)/i);e.push({file:n?.[1]||"fields.json",message:'"name" is a reserved field name',fixable:!0})}if(/could not resolve.*now/i.test(t)&&e.push({file:"module.html",message:"now() is not a valid HubL function",fixable:!0}),/hubdb|do not have access to hubdb/i.test(t)&&e.push({file:"templates",message:"HubDB requires CMS Hub Pro/Enterprise",fixable:!0}),/invalid default value|link.*field.*invalid/i.test(t)){let n=t.match(/field.*?(\w+)\s+has an invalid/i);e.push({file:n?.[1]||"fields.json",message:"Link field has invalid default value",fixable:!0})}if(/failed to deserialize/i.test(t)){let n=t.match(/file '([^']+)'/i);e.push({file:n?.[1]||"fields.json",message:"fields.json deserialization error",fixable:!0})}return/format for the color value is invalid/i.test(t)&&e.push({file:"fields.json",message:"Color field has invalid format (rgba/rgb/named \u2014 must be hex)",fixable:!0}),e}function An(t){let e=[];return Ro(t)&&e.push("textarea \u2192 text"),Oo(t)&&e.push("name \u2192 item_name"),jo(t)&&e.push("now() \u2192 local_dt"),Fo(t)&&e.push("Removed HubDB templates"),Jo(t)&&e.push("Fixed link field defaults"),Do(t)&&e.push("Fixed rgba/invalid color values \u2192 hex"),tl(t)&&e.push("Stripped CDN @import statements"),e}function Po(t,e){return e.message.includes("textarea")?Ro(t):e.message.includes("reserved field name")?Oo(t):e.message.includes("now()")?jo(t):e.message.includes("HubDB")?Fo(t):e.message.includes("invalid default value")||e.message.includes("deserialization")?Jo(t):e.message.includes("invalid format")&&e.message.includes("color")?Do(t):!1}function Ro(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(!S(o))continue;let i=w(o);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),H(o,i),e=!0)}return e}function Oo(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(!S(o))continue;let i=w(o);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),H(o,i),e=!0)}return e}function jo(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"module.html");if(!S(o))continue;let i=w(o);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),H(o,i),e=!0)}return e}function Fo(t){let e=!1,n=se(t,"templates");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".html"))continue;let o=se(n,s),i=w(o);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(el(o),e=!0)}return e}function Jo(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(S(o))try{let i=JSON.parse(w(o));Lo(i)&&(H(o,JSON.stringify(i,null,2)+`
|
|
310
|
-
`),e=!0)}catch{}}return e}function tl(t){let e=!1,n=se(t,"css");if(S(n))for(let o of Ue(n)){if(!o.endsWith(".css"))continue;let i=se(n,o),a=w(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(H(i,r),e=!0)}let s=se(t,"modules");if(S(s))for(let o of Ue(s)){if(!o.endsWith(".module"))continue;let i=se(s,o,"module.css");if(!S(i))continue;let a=w(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(H(i,r),e=!0)}if(S(s))for(let o of Ue(s)){if(!o.endsWith(".module"))continue;let i=se(s,o,"module.html");if(!S(i))continue;let a=w(i),r=a.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");r!==a&&(H(i,r),e=!0)}return e}function Do(t){let e=!1,n=se(t,"modules");if(!S(n))return!1;for(let s of Ue(n)){if(!s.endsWith(".module"))continue;let o=se(n,s,"fields.json");if(S(o))try{let i=JSON.parse(w(o));Ho(i)&&(H(o,JSON.stringify(i,null,2)+`
|
|
311
|
-
`),e=!0)}catch{}}return e}function Ho(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="color"&&s.default&&typeof s.default=="object"){let o=s.default,i=o.color;if(typeof i=="string"&&!nl(i)){let a=sl(i);a&&(o.color=a.hex,a.opacity!==void 0&&(o.opacity=a.opacity),e=!0)}}Array.isArray(s.children)&&Ho(s.children)&&(e=!0)}return e}function nl(t){return/^#[0-9a-fA-F]{6}$/.test(t)}function sl(t){let e=t.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);if(e)return{hex:`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`};let n=t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/i);if(n){let i=Math.min(255,parseInt(n[1])),a=Math.min(255,parseInt(n[2])),r=Math.min(255,parseInt(n[3])),l=`#${i.toString(16).padStart(2,"0")}${a.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}`,c=n[4]!==void 0?Math.round(parseFloat(n[4])*100):void 0;return{hex:l,opacity:c}}let s={white:"#ffffff",black:"#000000",red:"#ff0000",green:"#008000",blue:"#0000ff",yellow:"#ffff00",orange:"#ffa500",purple:"#800080",gray:"#808080",grey:"#808080",transparent:"#000000"},o=t.toLowerCase().trim();return s[o]?{hex:s[o],opacity:o==="transparent"?0:void 0}:null}function Lo(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="link"){let o=s.default;if(typeof o=="string"||o===void 0||o===null||typeof o=="object"&&!o.url){let a=typeof o=="string"?o:"";s.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},e=!0}}Array.isArray(s.children)&&Lo(s.children)&&(e=!0)}return e}te();g();tt();tt();import{readdirSync as ol}from"fs";import{join as il,relative as rl}from"path";var al=new Set([".git","node_modules",".vibespot",".DS_Store"]);function Go(t){let e=[];for(let n of ol(t,{withFileTypes:!0})){if(al.has(n.name)||n.name.startsWith(".")&&n.name!==".gitkeep")continue;let s=il(t,n.name);n.isDirectory()?e.push(...Go(s)):n.isFile()&&e.push(s)}return e}async function ll(t,e,n){let s=0;async function o(){for(;s<t.length;){let a=s++;await n(t[a])}}let i=Array.from({length:Math.min(e,t.length)},()=>o());await Promise.all(i)}async function In(t,e,n,s={}){let o=s.concurrency??5,i=Go(e),a=i.length,r=0,l=0,c=[];return await ll(i,o,async d=>{let u=rl(e,d).replace(/\\/g,"/"),p=`${n}/${u}`;s.onFileStart?.(u);let f=await lo(t,p,d);if(f.success)r++,s.onFileComplete?.(u);else{l++;let h={file:u,status:f.error?.status||0,message:f.error?.message||"Unknown error",category:f.error?.category,detail:f.error?.detail};c.push(h),s.onFileError?.(u,h)}s.onProgress?.(r+l,a)}),{success:l===0,uploaded:r,failed:l,total:a,errors:c}}function dl(t){return(t.match(/^Uploaded file /gm)||[]).length}async function gt(t){await le("Uploading to HubSpot");let e=cl(t)||t,n=_(),s=he(),o=n.hubspotUploadMode!=="cli"&&!!s,i=await de(),a=3;for(let r=1;r<=a;r++){i.start(r===1?"Uploading theme...":`Retrying upload (attempt ${r}/${a})...`);let l=[],c=0,d=!1;if(o){let p=await In(s,t,e,{onFileComplete:()=>{c++}});d=p.success,d?c=p.uploaded:l=xn(p.errors)}else{let p=T(`hs cms upload "${t}" "${e}"`,{cwd:Uo(t,"..")}),f=[p.stdout,p.stderr].filter(Boolean).join(`
|
|
312
|
-
`);c=dl(f),d=p.success,d||(l=Cn(f))}if(d)return i.stop(`All files uploaded! (${c} files)`),await ce("Upload complete!"),!0;if(c>0?i.stop(`${c} files uploaded, but some errors occurred`):i.stop("Upload failed"),l.length===0){if(U("Upload failed with unknown error."),c>0&&(V(`Most files uploaded successfully. The theme may already be usable in HubSpot.
|
|
313
|
-
You can check your HubSpot Design Manager to verify.`),await ne({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(r<a){if(!await ne({message:"Try uploading again?"}))break;continue}break}let u=!1;for(let p of l)p.fixable?Po(t,p)?(F(`Auto-fixed: ${p.message}`),u=!0):V(`Could not auto-fix: ${p.message}`):U(p.message);if(!(u&&r<a)){if(c>0&&(V(`${c} files uploaded successfully despite errors.
|
|
314
|
-
The theme may work \u2014 check HubSpot Design Manager.`),await ne({message:"Continue anyway?",initialValue:!0})))return!0;if(!u){if(i.start("Cleaning up stuck modules..."),o)try{await es(s,`${e}/modules`)}catch{}else T(`hs cms delete "${e}/modules"`,{cwd:Uo(t,"..")});i.stop("Cleaned up modules, retrying...")}}}return U("Upload failed after multiple attempts."),!1}g();import{execFileSync as is}from"child_process";import{rmSync as ul}from"fs";import{basename as Wo}from"path";Q();async function Bo(t){let{portalId:e,sourceDir:n,themePath:s,wasCloned:o}=t;await le("You're all set!");let a=Et(e)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await _e(`Your React page has been converted and uploaded to HubSpot.
|
|
315
|
-
The theme and modules are now in your account, but you still
|
|
316
|
-
need to ${I.bold("create a new landing page")} that uses them.
|
|
317
|
-
|
|
318
|
-
Next steps:
|
|
319
|
-
|
|
320
|
-
${I.bold("1.")} Go to HubSpot ${I.muted("\u2192")} Content ${I.muted("\u2192")} Landing Pages ${I.muted("\u2192")} Create
|
|
321
|
-
${I.bold("2.")} Choose your uploaded theme from the theme picker
|
|
322
|
-
${I.bold("3.")} Select the landing page template that was just created
|
|
323
|
-
${I.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
|
|
324
|
-
${I.bold("5.")} Click each section to edit text, images, and colors
|
|
325
|
-
${I.bold("6.")} Upload images via File Manager ${I.muted("(Settings \u2192 Files)")}
|
|
326
|
-
${I.bold("7.")} Preview and publish!`,"What's next"),await ne({message:"Open HubSpot Landing Pages in your browser?"})){let c=e?`https://${a}/page-ui/${e}/management/pages/landing`:`https://${a}`;try{let d=process.platform;d==="darwin"?is("open",[c],{stdio:"ignore"}):d==="win32"?is("cmd",["/c","start","",c],{stdio:"ignore"}):is("xdg-open",[c],{stdio:"ignore"}),F("Opening HubSpot Landing Pages...")}catch{q(`Open this URL in your browser: ${I.info(c)}`)}}let l=[];if(o&&S(n)&&l.push({path:n,label:`Cloned source (${Wo(n)})`}),S(s)&&l.push({path:s,label:`Theme directory (${Wo(s)})`}),l.length>0&&await ne({message:"Clean up local working directories?"}))for(let d of l)try{ul(d.path,{recursive:!0,force:!0}),F(`Removed ${d.label}`)}catch{V(`Could not remove ${d.label} \u2014 delete manually if needed.`)}await ce(`Thanks for using hub${I.vibes("Vibes")}! ${I.vibes("~")}`)}te();async function Vo(){Ee();let t=await cn(),e=await dn();z({lastSourcePath:e.sourceDir});let n=await fn();z({lastThemePath:n.themePath}),await wn({aiEngine:t.aiEngine,model:t.model,sourceDir:e.sourceDir,themePath:n.themePath}),await gt(n.themePath),await Bo({portalId:t.portalId,sourceDir:e.sourceDir,themePath:n.themePath,wasCloned:e.wasCloned})}g();async function Ko(){Ee(),await cn()}g();te();async function Yo(){Ee();let t=_();t.aiEngine||(U("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let e=await dn(),n=await fn();await wn({aiEngine:t.aiEngine,sourceDir:e.sourceDir,themePath:n.themePath})}g();te();async function zo(){Ee();let t=_();if(t.lastThemePath)if(await ne({message:`Upload from ${t.lastThemePath}?`}))await gt(t.lastThemePath);else{let n=await Ae({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await gt(n)}else{let e=await Ae({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:n=>n.trim()?void 0:"Path is required"});await gt(e)}}g();te();async function qo(){Ee(),await le("Environment Diagnostics");let t=0,e=kt();e.found?sn(e.version)?F(`Node.js v${e.version}`):(V(`Node.js v${e.version} \u2014 too old (need 18+)`),q(" Update at https://nodejs.org"),t++):(U("Node.js \u2014 not installed"),q(" Install from https://nodejs.org"),t++);let n=$t();n.found?F(`Git ${n.version}`):(U("Git \u2014 not installed"),q(" Install from https://git-scm.com"),t++);let s=Me();if(!s.found)V("HubSpot CLI \u2014 not installed (only needed for deployment)"),q(" Install: npm install -g @hubspot/cli");else if(!io(s.version))V(`HubSpot CLI v${s.version} \u2014 too old (need v8+)`),q(" Update: npm install -g @hubspot/cli@latest"),t++;else{F(`HubSpot CLI v${s.version}`);let p=Ne();p.authenticated?F(`HubSpot portal${p.portalName?`: ${p.portalName}`:""} (ID: ${p.portalId})`):(V("HubSpot \u2014 not authenticated"),q(" Run: hs init"))}let o=Tt();o.found?F(`Claude Code ${o.version} at ${o.path}`):q(I.muted("Claude Code \u2014 not installed"));let i=Mt();i.found?F(`Gemini CLI ${i.version} at ${i.path}`):q(I.muted("Gemini CLI \u2014 not installed"));let a=Nt();a.found?F(`OpenAI Codex ${a.version} at ${a.path}`):q(I.muted("OpenAI Codex \u2014 not installed"));let r=_(),l=!!(r.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(r.openaiApiKey||process.env.OPENAI_API_KEY),d=!!(r.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?F("Anthropic API key configured"):q(I.muted("Anthropic API key \u2014 not set")),c?F("OpenAI API key configured"):q(I.muted("OpenAI API key \u2014 not set")),d?F("Google AI API key configured"):q(I.muted("Google AI API key \u2014 not set"));let u={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"};r.aiEngine&&F(`AI engine: ${u[r.aiEngine]||r.aiEngine}`),r.lastThemePath&&q(I.muted(`Last theme: ${r.lastThemePath}`)),!o.found&&!i.found&&!a.found&&!l&&!c&&!d&&(V("No AI engine available"),q(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),q(" Or install: Claude Code \u2014 https://claude.ai/code"),q(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),q(" Codex CLI \u2014 https://github.com/openai/codex"),t++),console.log(),t===0?await ce("Everything looks good!"):await ce(I.warn(`${t} issue${t>1?"s":""} found \u2014 see above`))}g();import{join as Kn}from"path";import{existsSync as Id}from"fs";import{execFileSync as Bs}from"child_process";import Yn from"chalk";g();import{createServer as yd}from"http";import{readFileSync as Us,existsSync as Ws}from"fs";import{join as Vn,extname as ma}from"path";import{createHash as bd}from"crypto";import{WebSocketServer as Sd}from"ws";g();g();g();g();import{readFileSync as Be,readdirSync as ps,existsSync as pe,writeFileSync as En,mkdirSync as fi,rmSync as cs,renameSync as ds}from"fs";import{join as oe,dirname as vl}from"path";import{homedir as wl}from"os";g();import{existsSync as We,writeFileSync as ml,mkdirSync as pl}from"fs";import{join as Re}from"path";function Qo(t){return/^[0-9a-f]{4,40}$/i.test(t)}var kn=null;function ke(){return kn!==null||(kn=T("git --version").success),kn}function $n(t){if(!ke())return!1;if(We(Re(t,".git")))return Xo(t),!0;let e=T("git init",{cwd:t});return e.success?(fl(t),Xo(t),T("git add -A",{cwd:t}),T('git commit -m "Initial theme"',{cwd:t}),!0):(console.warn(`[project-git] git init failed in ${t}: ${e.stderr}`),!1)}function Xo(t){let e=Re(t,".vibespot");We(e)||pl(e,{recursive:!0})}function fl(t){let e=Re(t,".gitignore");ml(e,[".vibespot/","node_modules/",""].join(`
|
|
327
|
-
`),"utf-8")}function rs(t,e){if(!ke()||!We(Re(t,".git"))||(T("git add -A",{cwd:t}),T("git diff --cached --quiet",{cwd:t}).success))return null;let s=e.length>72?e.slice(0,69)+"...":e,o=T(`git commit -m "${s.replace(/"/g,'\\"')}"`,{cwd:t});if(!o.success)return console.warn(`[project-git] commit failed: ${o.stderr}`),null;let i=T("git rev-parse --short HEAD",{cwd:t});return i.success?i.stdout:null}function Zo(t,e,n,s){if(!ke()||!We(Re(t,".git")))return null;for(let u of s){let p=Re(t,u);We(p)&&T(`git add "${u}"`,{cwd:t})}if(T("git diff --cached --quiet",{cwd:t}).success)return null;let i=`[${e}] `,a=72-i.length,r=n.length>a?n.slice(0,a-3)+"...":n,l=i+r,c=T(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:t});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let d=T("git rev-parse --short HEAD",{cwd:t});return d.success?d.stdout:null}function ei(t,e=50){if(!ke())return[];if(!We(Re(t,".git")))return[];let n=T(`git log --pretty=format:"%h|%H|%s|%at" -n ${e}`,{cwd:t});if(!n.success||!n.stdout.trim())return[];let s=[];for(let o of n.stdout.split(`
|
|
328
|
-
`)){let i=o.split("|");if(i.length<4)continue;let a=parseInt(i[3],10)*1e3;s.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:a,date:new Date(a).toISOString()})}return s}function ti(t,e,n=50){if(!ke())return[];if(!We(Re(t,".git")))return[];let s=e.replace(/[[\]\\]/g,"\\$&"),o=T(`git log --grep="\\[${s}\\]" --pretty=format:"%h|%H|%s|%at" -n ${n}`,{cwd:t});if(!o.success||!o.stdout.trim())return[];let i=[];for(let a of o.stdout.split(`
|
|
329
|
-
`)){let r=a.split("|");if(r.length<4)continue;let l=parseInt(r[3],10)*1e3;i.push({hash:r[0],fullHash:r[1],message:r[2],timestamp:l,date:new Date(l).toISOString()})}return i}function ni(t,e){if(!ke())return{success:!1,error:"Git not available"};if(!We(Re(t,".git")))return{success:!1,error:"Not a git repo"};if(!Qo(e))return{success:!1,error:"Invalid commit hash"};let n=T(`git cat-file -t ${e}`,{cwd:t});if(!n.success||n.stdout.trim()!=="commit")return{success:!1,error:`Commit ${e} not found`};let s=T(`git log --format="%s" -1 ${e}`,{cwd:t}),o=s.success?s.stdout:e,i=T(`git checkout ${e} -- .`,{cwd:t});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let a=`Rollback to: ${o}`.slice(0,72);return T(`git commit -m "${a.replace(/"/g,'\\"')}"`,{cwd:t}),{success:!0}}function si(t,e,n,s){if(!ke())return{success:!1,error:"Git not available"};if(!We(Re(t,".git")))return{success:!1,error:"Not a git repo"};if(!Qo(n))return{success:!1,error:"Invalid commit hash"};let o=T(`git cat-file -t ${n}`,{cwd:t});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${n} not found`};let i=T(`git log --format="%s" -1 ${n}`,{cwd:t}),a=i.success?i.stdout:n,r=0;for(let d of s)T(`git checkout ${n} -- "${d}"`,{cwd:t}).success&&r++;if(r===0)return{success:!1,error:"No files could be restored from that commit"};T("git add -A",{cwd:t});let c=`${`[${e}] `}Rollback to: ${a}`.slice(0,72);return T(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:t}),{success:!0}}g();g();import{readFileSync as gl,existsSync as hl,writeFileSync as yl,mkdirSync as bl}from"fs";import{join as as}from"path";function nt(t){let e=v();e&&(e.modules=t.modules,e.moduleOrder=t.moduleOrder,e.sharedCss=t.sharedCss,e.sharedJs=t.sharedJs,e.template=t.template,e.messages=t.messages)}function Ye(){let t=v();if(!t)return;let e=Se();e&&(e.modules=t.modules,e.moduleOrder=t.moduleOrder,e.sharedCss=t.sharedCss,e.sharedJs=t.sharedJs,e.template=t.template,e.messages=t.messages)}function ze(t,e,n){let s=v();if(!s)return;let o={role:t,content:e,timestamp:Date.now()};n&&(o.pipeline=n),s.messages.push(o),s.updatedAt=Date.now(),Ye(),Sl()}function oi(t){let e=v();e&&(e.assets||(e.assets=[]),e.assets.push(t),e.updatedAt=Date.now(),D())}function Oe(t){let e=v();if(e){if(t.sharedCss!==void 0&&(e.sharedCss=t.sharedCss),t.sharedJs!==void 0&&(e.sharedJs=t.sharedJs),t.template!==void 0&&(e.template=t.template),t.modules)for(let n of t.modules){let s=n.moduleName.toLowerCase(),o=e.modules.findIndex(i=>i.moduleName.toLowerCase()===s);o>=0?e.modules[o]=n:(e.modules.push(n),e.moduleOrder.some(i=>i.toLowerCase()===s)||e.moduleOrder.push(n.moduleName))}e.updatedAt=Date.now(),Ye()}}function ht(t){let e=v();e&&(e.moduleOrder=t,e.updatedAt=Date.now(),Ye())}function ii(t){let e=v();e&&(e.modules=e.modules.filter(n=>n.moduleName!==t),e.moduleOrder=e.moduleOrder.filter(n=>n!==t),e.updatedAt=Date.now(),Ye())}function ri(t){let e=v();e&&(e.moduleOrder=e.moduleOrder.filter(n=>n!==t),e.updatedAt=Date.now(),Ye())}function ai(t,e,n){let s=v();if(!s)return;let o=s.modules.find(i=>i.moduleName===t);if(o)try{let i=JSON.parse(o.fieldsJson);ci(i,e,n),o.fieldsJson=JSON.stringify(i,null,2),s.updatedAt=Date.now(),Ye()}catch{}}function ue(){let t=v();if(!t)return[];let e=[];for(let n of t.moduleOrder){let s=t.modules.find(o=>o.moduleName===n);s&&e.push(s)}for(let n of t.modules)t.moduleOrder.includes(n.moduleName)||e.push(n);return e}function Sl(){let t=v();if(t)try{let e=as(t.themePath,".vibespot");bl(e,{recursive:!0});let n={sessionId:t.id,themeName:t.themeName,messages:t.messages,updatedAt:Date.now()};yl(as(e,"chat.json"),JSON.stringify(n,null,2),"utf-8")}catch{}}function li(t){let e=as(t,".vibespot","chat.json");if(!hl(e))return[];try{let n=JSON.parse(gl(e,"utf-8"));return Array.isArray(n.messages)?n.messages:[]}catch{return[]}}function ci(t,e,n){let s=e.split("."),o=s[0],i=t.find(a=>a.name===o);i&&(s.length===1?i.default=n:i.children&&ci(i.children,s.slice(1).join("."),n))}function Tn(t){if(t.templates&&t.templates.length>0)return;if(!t.modules||t.modules.length===0){t.templates=[],t.activeTemplateId="";return}let e=`lp-${t.themeName}`,n={id:e,label:`${t.themeName} Landing Page`,pageType:"landing_page",templateFile:`templates/lp-${t.themeName}.html`,modules:[...t.modules],moduleOrder:[...t.moduleOrder],sharedCss:t.sharedCss||"",sharedJs:t.sharedJs||"",template:t.template||"",messages:[...t.messages]};t.templates=[n],t.activeTemplateId=e}function Se(){let t=v();return!t||!t.activeTemplateId||!t.templates?.length?null:t.templates.find(e=>e.id===t.activeTemplateId)||null}function ls(t){let e=v();if(!e)return!1;let n=e.templates.find(s=>s.id===t);return n?(e.activeTemplateId=t,nt(n),e.updatedAt=Date.now(),!0):!1}function di(t,e){let n=v();if(!n)throw new Error("No active session");let s=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),i=`${t==="blog_post"?"bp":t==="website_page"?"wp":t==="module_only"?"mo":"lp"}-${s}`,a={id:i,label:e,pageType:t,templateFile:t==="module_only"?"":`templates/${i}.html`,modules:[],moduleOrder:[],sharedCss:"",sharedJs:"",template:"",messages:[]};return n.templates.push(a),n.activeTemplateId=i,nt(a),n.updatedAt=Date.now(),a}function ui(t,e){let n=v();if(!n)return null;let s=n.templates.find(c=>c.id===t);if(!s)return null;let o=e||`${s.label} (Copy)`,i=o.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),r=`${s.pageType==="blog_post"?"bp":s.pageType==="website_page"?"wp":s.pageType==="module_only"?"mo":"lp"}-${i}`,l={id:r,label:o,pageType:s.pageType,templateFile:s.pageType==="module_only"?"":`templates/${r}.html`,modules:s.modules.map(c=>({...c})),moduleOrder:[...s.moduleOrder],sharedCss:s.sharedCss,sharedJs:s.sharedJs,template:s.template,messages:[]};return n.templates.push(l),n.activeTemplateId=r,nt(l),n.updatedAt=Date.now(),l}function mi(t,e){let n=v();if(!n)return!1;let s=n.templates.find(o=>o.id===t);return s?(s.label=e,n.updatedAt=Date.now(),!0):!1}function pi(t){let e=v();if(!e)return!1;let n=e.templates.findIndex(s=>s.id===t);return n<0?!1:(e.templates.splice(n,1),e.activeTemplateId===t&&(e.templates.length>0?ls(e.templates[0].id):(e.activeTemplateId="",e.modules=[],e.moduleOrder=[],e.sharedCss="",e.sharedJs="",e.template="",e.messages=[])),e.updatedAt=Date.now(),!0)}function qe(){let t=v();if(!t)return[];let e=new Map;for(let n of t.templates)for(let s of n.modules){let o=e.get(s.moduleName);o?o.usedIn.push(n.label):e.set(s.moduleName,{module:s,usedIn:[n.label]})}return Array.from(e.values())}var Z=oe(wl(),".vibespot","sessions"),us=oe(Z,"_index.json"),yt=null;function Mn(){if(yt)return yt;try{return pe(us)?(yt=JSON.parse(Be(us,"utf-8")),yt):ms()}catch{return ms()}}function Nn(t){yt=t;try{fi(Z,{recursive:!0}),En(us,JSON.stringify(t),"utf-8")}catch{}}function ms(){if(!pe(Z))return[];let t=[];for(let e of ps(Z).filter(n=>n.endsWith(".json")&&n!=="_index.json"))try{let n=JSON.parse(Be(oe(Z,e),"utf-8")),s=n.templates||[];t.push({id:n.id,themeName:n.themeName,updatedAt:n.updatedAt,moduleCount:s.reduce((o,i)=>o+(i.modules?.length||0),0),templateCount:s.length})}catch{}return yt=t,Nn(t),t}function xl(t){let e=Mn(),n=t.templates||[],s={id:t.id,themeName:t.themeName,updatedAt:t.updatedAt,moduleCount:n.reduce((i,a)=>i+(a.modules?.length||0),0),templateCount:n.length},o=e.findIndex(i=>i.id===t.id);o>=0?e[o]=s:e.push(s),Nn(e)}function Cl(t){let e=Mn().filter(n=>n.id!==t);Nn(e)}function Al(t){let e=Mn().filter(n=>n.themeName!==t);Nn(e)}var fe=null;function v(){return fe}function Il(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function Ft(t,e){let n={id:Il(),themePath:t,themeName:e,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return fe=n,$n(t),n}function D(){if(!fe)return;fi(Z,{recursive:!0});let t=oe(Z,`${fe.id}.json`);En(t,JSON.stringify(fe,null,2),"utf-8"),xl(fe)}function _n(t){let e=oe(Z,t+".json");if(!pe(e))return null;try{let n=JSON.parse(Be(e,"utf-8"));return n.templates||(n.templates=[]),n.activeTemplateId||(n.activeTemplateId=""),Tn(n),fe=n,n}catch{return null}}function bt(){return pe(Z)?Mn():[]}function gi(t,e=!1){let n=oe(Z,t+".json"),s="";if(e)try{let o=JSON.parse(Be(n,"utf-8"));s=o.themeName||"",o.themePath&&pe(o.themePath)&&cs(o.themePath,{recursive:!0,force:!0})}catch{}else try{s=JSON.parse(Be(n,"utf-8")).themeName||""}catch{}try{pe(n)&&cs(n)}catch{}if(s&&pe(Z)){for(let o of ps(Z).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(Be(oe(Z,o),"utf-8")).themeName===s&&cs(oe(Z,o))}catch{}Al(s)}else Cl(t);fe?.id===t&&(fe=null)}function hi(t,e){let n=oe(Z,t+".json");if(!pe(n))return{ok:!1,error:"Session not found"};let s;try{s=JSON.parse(Be(n,"utf-8"))}catch{return{ok:!1,error:"Failed to read session"}}let o=s.themeName;if(o===e)return{ok:!0};let i=s.themePath,a=oe(vl(i),e);if(pe(i)){if(pe(a))return{ok:!1,error:"A project with that name already exists"};try{ds(i,a)}catch(p){return{ok:!1,error:`Failed to rename folder: ${p instanceof Error?p.message:String(p)}`}}let r=oe(a,"css",`${o}-theme.css`),l=oe(a,"css",`${e}-theme.css`);if(pe(r))try{ds(r,l)}catch{}let c=oe(a,"js",`${o}-animations.js`),d=oe(a,"js",`${e}-animations.js`);if(pe(c))try{ds(c,d)}catch{}let u=oe(a,"theme.json");if(pe(u))try{let p=JSON.parse(Be(u,"utf-8"));p.label=e,p.name=e,En(u,JSON.stringify(p,null,2),"utf-8")}catch{}}if(pe(Z))for(let r of ps(Z).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(Be(oe(Z,r),"utf-8"));l.themeName===o&&(l.themeName=e,l.themePath=a,l.updatedAt=Date.now(),En(oe(Z,r),JSON.stringify(l,null,2),"utf-8"))}catch{}return fe&&fe.themeName===o&&(fe.themeName=e,fe.themePath=a,fe.updatedAt=Date.now()),ms(),{ok:!0}}g();import{readFileSync as fs,readdirSync as Dt,existsSync as ve,writeFileSync as Ce,mkdirSync as Jt,rmSync as yi}from"fs";import{join as P}from"path";function ae(t){try{return fs(t,"utf-8")}catch{return""}}function kl(t){let e=[];for(let n of t.moduleOrder){let s=t.modules.find(o=>o.moduleName===n);s&&e.push(s)}for(let n of t.modules)t.moduleOrder.includes(n.moduleName)||e.push(n);return e}function $l(t,e){let n=ae(t);if(!n||e==="home.html"||e.endsWith("-listing.html"))return null;let s=e.replace(/\.html$/,""),o="landing_page";s.startsWith("bp-")?o="blog_post":s.startsWith("wp-")?o="website_page":s.startsWith("mo-")&&(o="module_only");let i=s,a=n.match(/<!--[\s\S]*?label:\s*"?([^"\n]+)"?\s*[\s\S]*?-->/);a&&(i=a[1].trim());let r=/dnd_module\s+path=["']\.\.\/modules\/(.+?)\.module["']/g,l=[],c;for(;(c=r.exec(n))!==null;)l.push(c[1]);return{id:s,label:i,pageType:o,moduleNames:l,templateContent:n,filename:e}}function Tl(t,e,n,s,o){if(!ve(t))return[];let i=[],a=Dt(t).filter(r=>r.endsWith(".html")&&r!=="home.html");for(let r of a){let l=P(t,r),c=$l(l,r);if(!c||c.moduleNames.length===0&&i.length>0)continue;let d=[],u=[];for(let p of c.moduleNames){let f=e.get(p);f&&(d.push(f),u.push(p))}i.push({id:c.id,label:c.label,pageType:c.pageType,templateFile:`templates/${c.filename}`,modules:d,moduleOrder:u,sharedCss:n,sharedJs:s,template:c.templateContent,messages:i.length===0?[...o]:[]})}return i}function Ht(t){let e=v();if(!e)return;let n=li(t);n.length>0&&e.messages.length===0&&(e.messages=n),$n(t);let s=P(t,"modules");if(!ve(s))return;let o=Dt(s,{withFileTypes:!0});for(let h of o){if(!h.isDirectory()||!h.name.endsWith(".module"))continue;let y=P(s,h.name),b=h.name.replace(/\.module$/,""),A={moduleName:b,fieldsJson:ae(P(y,"fields.json")),metaJson:ae(P(y,"meta.json")),moduleHtml:ae(P(y,"module.html")),moduleCss:ae(P(y,"module.css")),moduleJs:ae(P(y,"module.js"))||void 0};A.fieldsJson&&A.moduleHtml&&(e.modules.push(A),e.moduleOrder.push(b))}let i=P(t,"css"),a=P(t,"js"),r="",l="";if(ve(i)){let h=Dt(i).filter(y=>y.endsWith("-theme.css"));h.length>0&&(r=ae(P(i,h[0])),e.sharedCss=r)}if(ve(a)){let h=Dt(a).filter(y=>y.endsWith("-animations.js"));h.length>0&&(l=ae(P(a,h[0])),e.sharedJs=l)}let c=P(t,".vibespot","styleguide.md"),d=P(t,".vibespot","brandvoice.md");(ve(c)||ve(d))&&(e.brandAssets||(e.brandAssets={}),ve(c)&&(e.brandAssets.styleguide=ae(c)),ve(d)&&(e.brandAssets.brandvoice=ae(d)));let u=P(t,"templates"),p=new Map(e.modules.map(h=>[h.moduleName,h])),f=Tl(u,p,r,l,e.messages);if(f.length>0){e.templates=f,e.activeTemplateId=f[0].id;let h=f[0].moduleOrder;if(h.length>0){let y=new Set(e.moduleOrder),b=h.filter(A=>y.has(A));for(let A of e.moduleOrder)b.includes(A)||b.push(A);e.moduleOrder=b}nt(f[0])}else e.templates||(e.templates=[]),e.activeTemplateId||(e.activeTemplateId=""),Tn(e)}function Xe(){let t=v();if(!t)return;let e=t.themePath,n=new Map;if(t.templates.length>0)for(let l of t.templates)for(let c of l.modules)n.set(c.moduleName,c);for(let l of t.modules)n.set(l.moduleName,l);let s=P(e,"modules");Jt(s,{recursive:!0});for(let l of n.values())Jt(P(s,`${l.moduleName}.module`),{recursive:!0});for(let l of n.values()){let c=P(s,`${l.moduleName}.module`);Ce(P(c,"fields.json"),l.fieldsJson,"utf-8"),Ce(P(c,"meta.json"),l.metaJson,"utf-8"),Ce(P(c,"module.html"),l.moduleHtml,"utf-8"),Ce(P(c,"module.css"),l.moduleCss,"utf-8"),l.moduleJs&&Ce(P(c,"module.js"),l.moduleJs,"utf-8")}if(t.sharedCss){let l=P(e,"css");Jt(l,{recursive:!0}),Ce(P(l,`${t.themeName}-theme.css`),t.sharedCss,"utf-8")}if(t.sharedJs){let l=P(e,"js");Jt(l,{recursive:!0}),Ce(P(l,`${t.themeName}-animations.js`),t.sharedJs,"utf-8")}let o=P(e,"templates");Jt(o,{recursive:!0});let i=P(o,"home.html");(t.templates.length>0||t.modules.length>0)&&ve(i)&&yi(i,{force:!0});let r=new Set;if(t.templates.length>0)for(let l of t.templates){if(l.pageType==="module_only"||l.modules.length===0)continue;let c=l.template||Nl(l),d=bi(c,l.label,l.pageType),u=`${l.id}.html`;Ce(P(o,u),d,"utf-8"),r.add(u),l.pageType==="blog_post"&&(_l(o,l),r.add(`${l.id}-listing.html`))}else if(t.modules.length>0){let l=t.template||Pl(),c=bi(l,`${t.themeName} Landing Page`),d=`lp-${t.themeName}.html`;Ce(P(o,d),c,"utf-8"),r.add(d)}try{for(let l of Dt(o))l.startsWith("lp-")&&l.endsWith(".html")&&!r.has(l)&&yi(P(o,l),{force:!0})}catch{}El(),Ml()}function Si(){let t=v();t&&(t.modules=[],t.moduleOrder=[],t.sharedCss="",t.sharedJs="",t.template="",Ht(t.themePath),t.updatedAt=Date.now(),Ye())}function vi(){let t=v();if(!t)return;let e=Se();if(!e)return;let n=t.themePath,s=P(n,"modules");e.modules=[];for(let o of e.moduleOrder){let i=P(s,`${o}.module`);if(!ve(i))continue;let a={moduleName:o,fieldsJson:ae(P(i,"fields.json")),metaJson:ae(P(i,"meta.json")),moduleHtml:ae(P(i,"module.html")),moduleCss:ae(P(i,"module.css")),moduleJs:ae(P(i,"module.js"))||void 0};a.fieldsJson&&a.moduleHtml&&e.modules.push(a)}if(e.templateFile){let o=P(n,e.templateFile);ve(o)&&(e.template=ae(o))}nt(e),t.updatedAt=Date.now()}function El(){let t=v();if(!t)return;let e=P(t.themePath,"templates","layouts","base.html");if(ve(e))try{let n=fs(e,"utf-8");if(n.includes("template_js"))return;let s='{{ require_js(get_asset_url("../../js/main.js")) }}';n.includes(s)?n=n.replace(s,s+`
|
|
94
|
+
Return ONLY the template HTML content, no markdown fences.`}var Bo,Ve=J(()=>{"use strict";g();Z();Bo=new Map});var Ai=J(()=>{"use strict";g()});import{existsSync as ze,writeFileSync as Ql,mkdirSync as Zl}from"fs";import{join as Je}from"path";function ki(t){return/^[0-9a-f]{4,40}$/i.test(t)}function Ee(){return Ln!==null||(Ln=T("git --version").success),Ln}function Hn(t){if(!Ee())return!1;if(ze(Je(t,".git")))return Ii(t),!0;let e=T("git init",{cwd:t});return e.success?(ec(t),Ii(t),T("git add -A",{cwd:t}),T('git commit -m "Initial theme"',{cwd:t}),!0):(console.warn(`[project-git] git init failed in ${t}: ${e.stderr}`),!1)}function Ii(t){let e=Je(t,".vibespot");ze(e)||Zl(e,{recursive:!0})}function ec(t){let e=Je(t,".gitignore");Ql(e,[".vibespot/","node_modules/",""].join(`
|
|
95
|
+
`),"utf-8")}function Ts(t,e){if(!Ee()||!ze(Je(t,".git"))||(T("git add -A",{cwd:t}),T("git diff --cached --quiet",{cwd:t}).success))return null;let s=e.length>72?e.slice(0,69)+"...":e,o=T(`git commit -m "${s.replace(/"/g,'\\"')}"`,{cwd:t});if(!o.success)return console.warn(`[project-git] commit failed: ${o.stderr}`),null;let i=T("git rev-parse --short HEAD",{cwd:t});return i.success?i.stdout:null}function $i(t,e,n,s){if(!Ee()||!ze(Je(t,".git")))return null;for(let u of s){let p=Je(t,u);ze(p)&&T(`git add "${u}"`,{cwd:t})}if(T("git diff --cached --quiet",{cwd:t}).success)return null;let i=`[${e}] `,a=72-i.length,r=n.length>a?n.slice(0,a-3)+"...":n,l=i+r,c=T(`git commit -m "${l.replace(/"/g,'\\"')}"`,{cwd:t});if(!c.success)return console.warn(`[project-git] template commit failed: ${c.stderr}`),null;let d=T("git rev-parse --short HEAD",{cwd:t});return d.success?d.stdout:null}function Ti(t,e=50){if(!Ee())return[];if(!ze(Je(t,".git")))return[];let n=T(`git log --pretty=format:"%h|%H|%s|%at" -n ${e}`,{cwd:t});if(!n.success||!n.stdout.trim())return[];let s=[];for(let o of n.stdout.split(`
|
|
96
|
+
`)){let i=o.split("|");if(i.length<4)continue;let a=parseInt(i[3],10)*1e3;s.push({hash:i[0],fullHash:i[1],message:i[2],timestamp:a,date:new Date(a).toISOString()})}return s}function Ei(t,e,n=50){if(!Ee())return[];if(!ze(Je(t,".git")))return[];let s=e.replace(/[[\]\\]/g,"\\$&"),o=T(`git log --grep="\\[${s}\\]" --pretty=format:"%h|%H|%s|%at" -n ${n}`,{cwd:t});if(!o.success||!o.stdout.trim())return[];let i=[];for(let a of o.stdout.split(`
|
|
97
|
+
`)){let r=a.split("|");if(r.length<4)continue;let l=parseInt(r[3],10)*1e3;i.push({hash:r[0],fullHash:r[1],message:r[2],timestamp:l,date:new Date(l).toISOString()})}return i}function Ni(t,e){if(!Ee())return{success:!1,error:"Git not available"};if(!ze(Je(t,".git")))return{success:!1,error:"Not a git repo"};if(!ki(e))return{success:!1,error:"Invalid commit hash"};let n=T(`git cat-file -t ${e}`,{cwd:t});if(!n.success||n.stdout.trim()!=="commit")return{success:!1,error:`Commit ${e} not found`};let s=T(`git log --format="%s" -1 ${e}`,{cwd:t}),o=s.success?s.stdout:e,i=T(`git checkout ${e} -- .`,{cwd:t});if(!i.success)return{success:!1,error:`Checkout failed: ${i.stderr}`};let a=`Rollback to: ${o}`.slice(0,72);return T(`git commit -m "${a.replace(/"/g,'\\"')}"`,{cwd:t}),{success:!0}}function Mi(t,e,n,s){if(!Ee())return{success:!1,error:"Git not available"};if(!ze(Je(t,".git")))return{success:!1,error:"Not a git repo"};if(!ki(n))return{success:!1,error:"Invalid commit hash"};let o=T(`git cat-file -t ${n}`,{cwd:t});if(!o.success||o.stdout.trim()!=="commit")return{success:!1,error:`Commit ${n} not found`};let i=T(`git log --format="%s" -1 ${n}`,{cwd:t}),a=i.success?i.stdout:n,r=0;for(let d of s)T(`git checkout ${n} -- "${d}"`,{cwd:t}).success&&r++;if(r===0)return{success:!1,error:"No files could be restored from that commit"};T("git add -A",{cwd:t});let c=`${`[${e}] `}Rollback to: ${a}`.slice(0,72);return T(`git commit -m "${c.replace(/"/g,'\\"')}"`,{cwd:t}),{success:!0}}var Ln,Yt=J(()=>{"use strict";g();ct();Ln=null});import{readFileSync as tc,existsSync as nc,writeFileSync as sc,mkdirSync as oc}from"fs";import{join as Es}from"path";function mt(t){let e=v();e&&(e.modules=t.modules,e.moduleOrder=t.moduleOrder,e.sharedCss=t.sharedCss,e.sharedJs=t.sharedJs,e.template=t.template,e.messages=t.messages)}function et(){let t=v();if(!t)return;let e=Ce();e&&(e.modules=t.modules,e.moduleOrder=t.moduleOrder,e.sharedCss=t.sharedCss,e.sharedJs=t.sharedJs,e.template=t.template,e.messages=t.messages)}function tt(t,e,n){let s=v();if(!s)return;let o={role:t,content:e,timestamp:Date.now()};n&&(o.pipeline=n),s.messages.push(o),s.updatedAt=Date.now(),et(),ic()}function Pi(t){let e=v();e&&(e.assets||(e.assets=[]),e.assets.push(t),e.updatedAt=Date.now(),D())}function De(t){let e=v();if(e){if(t.sharedCss!==void 0&&(e.sharedCss=t.sharedCss),t.sharedJs!==void 0&&(e.sharedJs=t.sharedJs),t.template!==void 0&&(e.template=t.template),t.modules)for(let n of t.modules){let s=n.moduleName.toLowerCase(),o=e.modules.findIndex(i=>i.moduleName.toLowerCase()===s);o>=0?e.modules[o]=n:(e.modules.push(n),e.moduleOrder.some(i=>i.toLowerCase()===s)||e.moduleOrder.push(n.moduleName))}e.updatedAt=Date.now(),et()}}function At(t){let e=v();e&&(e.moduleOrder=t,e.updatedAt=Date.now(),et())}function _i(t){let e=v();e&&(e.modules=e.modules.filter(n=>n.moduleName!==t),e.moduleOrder=e.moduleOrder.filter(n=>n!==t),e.updatedAt=Date.now(),et())}function Ri(t){let e=v();e&&(e.moduleOrder=e.moduleOrder.filter(n=>n!==t),e.updatedAt=Date.now(),et())}function Oi(t,e,n){let s=v();if(!s)return;let o=s.modules.find(i=>i.moduleName===t);if(o)try{let i=JSON.parse(o.fieldsJson);Fi(i,e,n),o.fieldsJson=JSON.stringify(i,null,2),s.updatedAt=Date.now(),et()}catch{}}function me(){let t=v();if(!t)return[];let e=[];for(let n of t.moduleOrder){let s=t.modules.find(o=>o.moduleName===n);s&&e.push(s)}for(let n of t.modules)t.moduleOrder.includes(n.moduleName)||e.push(n);return e}function ic(){let t=v();if(t)try{let e=Es(t.themePath,".vibespot");oc(e,{recursive:!0});let n={sessionId:t.id,themeName:t.themeName,messages:t.messages,updatedAt:Date.now()};sc(Es(e,"chat.json"),JSON.stringify(n,null,2),"utf-8")}catch{}}function ji(t){let e=Es(t,".vibespot","chat.json");if(!nc(e))return[];try{let n=JSON.parse(tc(e,"utf-8"));return Array.isArray(n.messages)?n.messages:[]}catch{return[]}}function Fi(t,e,n){let s=e.split("."),o=s[0],i=t.find(a=>a.name===o);i&&(s.length===1?i.default=n:i.children&&Fi(i.children,s.slice(1).join("."),n))}var Gn=J(()=>{"use strict";g();qt();zt()});function Un(t){if(t.templates&&t.templates.length>0)return;if(!t.modules||t.modules.length===0){t.templates=[],t.activeTemplateId="";return}let e=`lp-${t.themeName}`,n={id:e,label:`${t.themeName} Landing Page`,pageType:"landing_page",templateFile:`templates/lp-${t.themeName}.html`,modules:[...t.modules],moduleOrder:[...t.moduleOrder],sharedCss:t.sharedCss||"",sharedJs:t.sharedJs||"",template:t.template||"",messages:[...t.messages]};t.templates=[n],t.activeTemplateId=e}function Ce(){let t=v();return!t||!t.activeTemplateId||!t.templates?.length?null:t.templates.find(e=>e.id===t.activeTemplateId)||null}function Ns(t){let e=v();if(!e)return!1;let n=e.templates.find(s=>s.id===t);return n?(e.activeTemplateId=t,mt(n),e.updatedAt=Date.now(),!0):!1}function Ji(t,e){let n=v();if(!n)throw new Error("No active session");let s=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),i=`${t==="blog_post"?"bp":t==="website_page"?"wp":t==="module_only"?"mo":"lp"}-${s}`,a={id:i,label:e,pageType:t,templateFile:t==="module_only"?"":`templates/${i}.html`,modules:[],moduleOrder:[],sharedCss:"",sharedJs:"",template:"",messages:[]};return n.templates.push(a),n.activeTemplateId=i,mt(a),n.updatedAt=Date.now(),a}function Di(t,e){let n=v();if(!n)return null;let s=n.templates.find(c=>c.id===t);if(!s)return null;let o=e||`${s.label} (Copy)`,i=o.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""),r=`${s.pageType==="blog_post"?"bp":s.pageType==="website_page"?"wp":s.pageType==="module_only"?"mo":"lp"}-${i}`,l={id:r,label:o,pageType:s.pageType,templateFile:s.pageType==="module_only"?"":`templates/${r}.html`,modules:s.modules.map(c=>({...c})),moduleOrder:[...s.moduleOrder],sharedCss:s.sharedCss,sharedJs:s.sharedJs,template:s.template,messages:[]};return n.templates.push(l),n.activeTemplateId=r,mt(l),n.updatedAt=Date.now(),l}function Li(t,e){let n=v();if(!n)return!1;let s=n.templates.find(o=>o.id===t);return s?(s.label=e,n.updatedAt=Date.now(),!0):!1}function Hi(t){let e=v();if(!e)return!1;let n=e.templates.findIndex(s=>s.id===t);return n<0?!1:(e.templates.splice(n,1),e.activeTemplateId===t&&(e.templates.length>0?Ns(e.templates[0].id):(e.activeTemplateId="",e.modules=[],e.moduleOrder=[],e.sharedCss="",e.sharedJs="",e.template="",e.messages=[])),e.updatedAt=Date.now(),!0)}function nt(){let t=v();if(!t)return[];let e=new Map;for(let n of t.templates)for(let s of n.modules){let o=e.get(s.moduleName);o?o.usedIn.push(n.label):e.set(s.moduleName,{module:s,usedIn:[n.label]})}return Array.from(e.values())}var zt=J(()=>{"use strict";g();qt();Gn()});import{readFileSync as qe,readdirSync as Os,existsSync as ye,writeFileSync as Wn,mkdirSync as Gi,rmSync as Ms,renameSync as Ps}from"fs";import{join as ie,dirname as rc}from"path";import{homedir as ac}from"os";function Bn(){if(It)return It;try{return ye(_s)?(It=JSON.parse(qe(_s,"utf-8")),It):Rs()}catch{return Rs()}}function Kn(t){It=t;try{Gi(te,{recursive:!0}),Wn(_s,JSON.stringify(t),"utf-8")}catch{}}function Rs(){if(!ye(te))return[];let t=[];for(let e of Os(te).filter(n=>n.endsWith(".json")&&n!=="_index.json"))try{let n=JSON.parse(qe(ie(te,e),"utf-8")),s=n.templates||[];t.push({id:n.id,themeName:n.themeName,updatedAt:n.updatedAt,moduleCount:s.reduce((o,i)=>o+(i.modules?.length||0),0),templateCount:s.length})}catch{}return It=t,Kn(t),t}function lc(t){let e=Bn(),n=t.templates||[],s={id:t.id,themeName:t.themeName,updatedAt:t.updatedAt,moduleCount:n.reduce((i,a)=>i+(a.modules?.length||0),0),templateCount:n.length},o=e.findIndex(i=>i.id===t.id);o>=0?e[o]=s:e.push(s),Kn(e)}function cc(t){let e=Bn().filter(n=>n.id!==t);Kn(e)}function dc(t){let e=Bn().filter(n=>n.themeName!==t);Kn(e)}function v(){return be}function uc(){return`vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}function Xt(t,e){let n={id:uc(),themePath:t,themeName:e,templates:[],activeTemplateId:"",messages:[],modules:[],sharedCss:"",sharedJs:"",template:"",moduleOrder:[],createdAt:Date.now(),updatedAt:Date.now()};return be=n,Hn(t),n}function D(){if(!be)return;Gi(te,{recursive:!0});let t=ie(te,`${be.id}.json`);Wn(t,JSON.stringify(be,null,2),"utf-8"),lc(be)}function Vn(t){let e=ie(te,t+".json");if(!ye(e))return null;try{let n=JSON.parse(qe(e,"utf-8"));return n.templates||(n.templates=[]),n.activeTemplateId||(n.activeTemplateId=""),Un(n),be=n,n}catch{return null}}function kt(){return ye(te)?Bn():[]}function Ui(t,e=!1){let n=ie(te,t+".json"),s="";if(e)try{let o=JSON.parse(qe(n,"utf-8"));s=o.themeName||"",o.themePath&&ye(o.themePath)&&Ms(o.themePath,{recursive:!0,force:!0})}catch{}else try{s=JSON.parse(qe(n,"utf-8")).themeName||""}catch{}try{ye(n)&&Ms(n)}catch{}if(s&&ye(te)){for(let o of Os(te).filter(i=>i.endsWith(".json")&&i!=="_index.json"))try{JSON.parse(qe(ie(te,o),"utf-8")).themeName===s&&Ms(ie(te,o))}catch{}dc(s)}else cc(t);be?.id===t&&(be=null)}function Wi(t,e){let n=ie(te,t+".json");if(!ye(n))return{ok:!1,error:"Session not found"};let s;try{s=JSON.parse(qe(n,"utf-8"))}catch{return{ok:!1,error:"Failed to read session"}}let o=s.themeName;if(o===e)return{ok:!0};let i=s.themePath,a=ie(rc(i),e);if(ye(i)){if(ye(a))return{ok:!1,error:"A project with that name already exists"};try{Ps(i,a)}catch(p){return{ok:!1,error:`Failed to rename folder: ${p instanceof Error?p.message:String(p)}`}}let r=ie(a,"css",`${o}-theme.css`),l=ie(a,"css",`${e}-theme.css`);if(ye(r))try{Ps(r,l)}catch{}let c=ie(a,"js",`${o}-animations.js`),d=ie(a,"js",`${e}-animations.js`);if(ye(c))try{Ps(c,d)}catch{}let u=ie(a,"theme.json");if(ye(u))try{let p=JSON.parse(qe(u,"utf-8"));p.label=e,p.name=e,Wn(u,JSON.stringify(p,null,2),"utf-8")}catch{}}if(ye(te))for(let r of Os(te).filter(l=>l.endsWith(".json")&&l!=="_index.json"))try{let l=JSON.parse(qe(ie(te,r),"utf-8"));l.themeName===o&&(l.themeName=e,l.themePath=a,l.updatedAt=Date.now(),Wn(ie(te,r),JSON.stringify(l,null,2),"utf-8"))}catch{}return be&&be.themeName===o&&(be.themeName=e,be.themePath=a,be.updatedAt=Date.now()),Rs(),{ok:!0}}var te,_s,It,be,qt=J(()=>{"use strict";g();Yt();zt();te=ie(ac(),".vibespot","sessions"),_s=ie(te,"_index.json"),It=null;be=null});import{readFileSync as js,readdirSync as Zt,existsSync as pe,writeFileSync as ke,mkdirSync as Qt,rmSync as Bi}from"fs";import{join as _}from"path";function re(t){try{return js(t,"utf-8")}catch{return""}}function mc(t){let e=[];for(let n of t.moduleOrder){let s=t.modules.find(o=>o.moduleName===n);s&&e.push(s)}for(let n of t.modules)t.moduleOrder.includes(n.moduleName)||e.push(n);return e}function pc(t,e){let n=re(t);if(!n||e==="home.html"||e.endsWith("-listing.html"))return null;let s=e.replace(/\.html$/,""),o="landing_page";s.startsWith("bp-")?o="blog_post":s.startsWith("wp-")?o="website_page":s.startsWith("mo-")&&(o="module_only");let i=s,a=n.match(/<!--[\s\S]*?label:\s*"?([^"\n]+)"?\s*[\s\S]*?-->/);a&&(i=a[1].trim());let r=/dnd_module\s+path=["']\.\.\/modules\/(.+?)\.module["']/g,l=[],c;for(;(c=r.exec(n))!==null;)l.push(c[1]);return{id:s,label:i,pageType:o,moduleNames:l,templateContent:n,filename:e}}function fc(t,e,n,s,o){if(!pe(t))return[];let i=[],a=Zt(t).filter(r=>r.endsWith(".html")&&r!=="home.html");for(let r of a){let l=_(t,r),c=pc(l,r);if(!c||c.moduleNames.length===0&&i.length>0)continue;let d=[],u=[];for(let p of c.moduleNames){let f=e.get(p);f&&(d.push(f),u.push(p))}i.push({id:c.id,label:c.label,pageType:c.pageType,templateFile:`templates/${c.filename}`,modules:d,moduleOrder:u,sharedCss:n,sharedJs:s,template:c.templateContent,messages:i.length===0?[...o]:[]})}return i}function en(t){let e=v();if(!e)return;let n=ji(t);n.length>0&&e.messages.length===0&&(e.messages=n),Hn(t);let s=_(t,"modules");if(!pe(s))return;let o=Zt(s,{withFileTypes:!0});for(let y of o){if(!y.isDirectory()||!y.name.endsWith(".module"))continue;let b=_(s,y.name),A=y.name.replace(/\.module$/,""),w={moduleName:A,fieldsJson:re(_(b,"fields.json")),metaJson:re(_(b,"meta.json")),moduleHtml:re(_(b,"module.html")),moduleCss:re(_(b,"module.css")),moduleJs:re(_(b,"module.js"))||void 0};w.fieldsJson&&w.moduleHtml&&(e.modules.push(w),e.moduleOrder.push(A))}let i=_(t,"css"),a=_(t,"js"),r="",l="";if(pe(i)){let y=Zt(i).filter(b=>b.endsWith("-theme.css"));y.length>0&&(r=re(_(i,y[0])),e.sharedCss=r)}if(pe(a)){let y=Zt(a).filter(b=>b.endsWith("-animations.js"));y.length>0&&(l=re(_(a,y[0])),e.sharedJs=l)}let c=_(t,".vibespot","styleguide.md"),d=_(t,".vibespot","brandvoice.md"),u=_(t,".vibespot","theme-context.md");(pe(c)||pe(d)||pe(u))&&(e.brandAssets||(e.brandAssets={}),pe(c)&&(e.brandAssets.styleguide=re(c)),pe(d)&&(e.brandAssets.brandvoice=re(d)),pe(u)&&(e.brandAssets.themeContext=re(u)));let p=_(t,"templates"),f=new Map(e.modules.map(y=>[y.moduleName,y])),h=fc(p,f,r,l,e.messages);if(h.length>0){e.templates=h,e.activeTemplateId=h[0].id;let y=h[0].moduleOrder;if(y.length>0){let b=new Set(e.moduleOrder),A=y.filter(w=>b.has(w));for(let w of e.moduleOrder)A.includes(w)||A.push(w);e.moduleOrder=A}mt(h[0])}else e.templates||(e.templates=[]),e.activeTemplateId||(e.activeTemplateId=""),Un(e)}function st(){let t=v();if(!t)return;let e=t.themePath,n=new Map;if(t.templates.length>0)for(let l of t.templates)for(let c of l.modules)n.set(c.moduleName,c);for(let l of t.modules)n.set(l.moduleName,l);let s=_(e,"modules");Qt(s,{recursive:!0});for(let l of n.values())Qt(_(s,`${l.moduleName}.module`),{recursive:!0});for(let l of n.values()){let c=_(s,`${l.moduleName}.module`);ke(_(c,"fields.json"),l.fieldsJson,"utf-8"),ke(_(c,"meta.json"),l.metaJson,"utf-8"),ke(_(c,"module.html"),l.moduleHtml,"utf-8"),ke(_(c,"module.css"),l.moduleCss,"utf-8"),l.moduleJs&&ke(_(c,"module.js"),l.moduleJs,"utf-8")}if(t.sharedCss){let l=_(e,"css");Qt(l,{recursive:!0}),ke(_(l,`${t.themeName}-theme.css`),t.sharedCss,"utf-8")}if(t.sharedJs){let l=_(e,"js");Qt(l,{recursive:!0}),ke(_(l,`${t.themeName}-animations.js`),t.sharedJs,"utf-8")}let o=_(e,"templates");Qt(o,{recursive:!0});let i=_(o,"home.html");(t.templates.length>0||t.modules.length>0)&&pe(i)&&Bi(i,{force:!0});let r=new Set;if(t.templates.length>0)for(let l of t.templates){if(l.pageType==="module_only"||l.modules.length===0)continue;let c=l.template||yc(l),d=Ki(c,l.label,l.pageType),u=`${l.id}.html`;ke(_(o,u),d,"utf-8"),r.add(u),l.pageType==="blog_post"&&(bc(o,l),r.add(`${l.id}-listing.html`))}else if(t.modules.length>0){let l=t.template||Sc(),c=Ki(l,`${t.themeName} Landing Page`),d=`lp-${t.themeName}.html`;ke(_(o,d),c,"utf-8"),r.add(d)}try{for(let l of Zt(o))l.startsWith("lp-")&&l.endsWith(".html")&&!r.has(l)&&Bi(_(o,l),{force:!0})}catch{}gc(),hc()}function Vi(){let t=v();t&&(t.modules=[],t.moduleOrder=[],t.sharedCss="",t.sharedJs="",t.template="",en(t.themePath),t.updatedAt=Date.now(),et())}function Yi(){let t=v();if(!t)return;let e=Ce();if(!e)return;let n=t.themePath,s=_(n,"modules");e.modules=[];for(let o of e.moduleOrder){let i=_(s,`${o}.module`);if(!pe(i))continue;let a={moduleName:o,fieldsJson:re(_(i,"fields.json")),metaJson:re(_(i,"meta.json")),moduleHtml:re(_(i,"module.html")),moduleCss:re(_(i,"module.css")),moduleJs:re(_(i,"module.js"))||void 0};a.fieldsJson&&a.moduleHtml&&e.modules.push(a)}if(e.templateFile){let o=_(n,e.templateFile);pe(o)&&(e.template=re(o))}mt(e),t.updatedAt=Date.now()}function gc(){let t=v();if(!t)return;let e=_(t.themePath,"templates","layouts","base.html");if(pe(e))try{let n=js(e,"utf-8");if(n.includes("template_js"))return;let s='{{ require_js(get_asset_url("../../js/main.js")) }}';n.includes(s)?n=n.replace(s,s+`
|
|
330
98
|
{% if template_js %}
|
|
331
99
|
{{ require_js(get_asset_url(template_js)) }}
|
|
332
100
|
{% endif %}`):n=n.replace("{{ standard_footer_includes }}",`{% if template_js %}
|
|
333
101
|
{{ require_js(get_asset_url(template_js)) }}
|
|
334
102
|
{% endif %}
|
|
335
|
-
{{ standard_footer_includes }}`),
|
|
103
|
+
{{ standard_footer_includes }}`),ke(e,n,"utf-8")}catch{}}function hc(){let t=v();if(!t)return;let e=_(t.themePath,"theme.json");if(pe(e))try{let n=JSON.parse(js(e,"utf-8"));n.label=t.themeName,n.name=t.themeName,ke(e,JSON.stringify(n,null,2),"utf-8")}catch{}}function Ki(t,e,n="landing_page"){return t.includes("templateType")?t:`<!--
|
|
336
104
|
templateType: ${n==="blog_post"?"blog_post":"page"}
|
|
337
105
|
isAvailableForNewContent: true
|
|
338
106
|
label: "${e}"
|
|
339
107
|
-->
|
|
340
|
-
`+t}function
|
|
108
|
+
`+t}function yc(t){if(t.modules.length===0)return"";let n=v().themeName,o=mc(t).map(a=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
|
|
341
109
|
{% dnd_module path="../modules/${a.moduleName}.module" %}
|
|
342
110
|
{% end_dnd_module %}
|
|
343
111
|
{% end_dnd_section %}`).join(`
|
|
@@ -368,7 +136,7 @@ ${o}
|
|
|
368
136
|
|
|
369
137
|
{% block footer %}
|
|
370
138
|
{% endblock footer %}
|
|
371
|
-
`}function
|
|
139
|
+
`}function bc(t,e){let n=`<!--
|
|
372
140
|
templateType: blog_listing
|
|
373
141
|
isAvailableForNewContent: true
|
|
374
142
|
label: "${e.label} - Listing"
|
|
@@ -393,7 +161,7 @@ ${o}
|
|
|
393
161
|
{% endif %}
|
|
394
162
|
</div>
|
|
395
163
|
{% endblock body %}
|
|
396
|
-
`;
|
|
164
|
+
`;ke(_(t,`${e.id}-listing.html`),n,"utf-8")}function Sc(){let t=v();if(!t||t.modules.length===0)return"";let e=t.themeName,s=me().map(o=>` {% dnd_section padding={"top":"0","bottom":"0","left":"0","right":"0"}, full_width=true %}
|
|
397
165
|
{% dnd_module path="../modules/${o.moduleName}.module" %}
|
|
398
166
|
{% end_dnd_module %}
|
|
399
167
|
{% end_dnd_section %}`).join(`
|
|
@@ -424,7 +192,7 @@ ${s}
|
|
|
424
192
|
|
|
425
193
|
{% block footer %}
|
|
426
194
|
{% endblock footer %}
|
|
427
|
-
`}g();g();function
|
|
195
|
+
`}var zi=J(()=>{"use strict";g();qt();Gn();zt();Yt()});var qi=J(()=>{"use strict";g();Ai();qt();Gn();zi();zt()});var Se=J(()=>{"use strict";g();qi()});function Yn(t){let e={};for(let n of t)n.type==="group"&&n.occurrence&&Array.isArray(n.default)?e[n.name]=n.default:n.type==="group"&&n.children?e[n.name]=Yn(n.children):e[n.name]=n.default??"";return e}function Js(t,e){let n=t;return n=Tc(n),n=er(n,e),n=tr(n,e),n=nr(n,e),n=Nc(n),n}function Ds(t){let e=[t.sharedCss||"",...t.moduleCssArray].filter(Boolean).map(o=>`<style>${o}</style>`).join(`
|
|
428
196
|
`),n=[t.sharedJs||"",...t.moduleJsArray].filter(Boolean).map(o=>`<script>${o}</script>`).join(`
|
|
429
197
|
`),s=t.renderedModules.join(`
|
|
430
198
|
`);return`<!DOCTYPE html>
|
|
@@ -471,11 +239,11 @@ document.querySelectorAll('img').forEach(function(img){
|
|
|
471
239
|
});
|
|
472
240
|
</script>
|
|
473
241
|
</body>
|
|
474
|
-
</html>`}
|
|
242
|
+
</html>`}function Tc(t){return t=t.replace(vc,""),t=t.replace(wc,""),t=t.replace(xc,""),Xi.lastIndex=0,t=t.replace(Xi,(e,n)=>`/theme-assets/${n}`),Qi.lastIndex=0,t=t.replace(Qi,""),t=t.replace(Cc,""),t=t.replace(Ac,""),t=t.replace(Ic,""),t=t.replace(kc,""),t=t.replace($c,""),t}function er(t,e){let n=t,s=0;for(;s<30;){s++;let o=Ec(n);if(!o)break;let{varName:i,iterExpr:a,body:r,start:l,end:c}=o,d=Mc(a,e),u="";Array.isArray(d)&&(u=d.map((p,f)=>{let h={...e,[i]:p,loop:{index:f+1,index0:f,first:f===0,last:f===d.length-1,length:d.length}},y=er(r,h);return y=tr(y,h),y=nr(y,h),y}).join("")),n=n.slice(0,l)+u+n.slice(c)}return n}function Ec(t){let e=/\{%[-\s]*for\s+(\w+)\s+in\s+([\w.]+(?:\([^)]*\))?(?:\|[\w(),"' ]+)*)\s*-?%\}/g,n=/\{%[-\s]*(for\s|endfor)\s*.*?-?%\}/g,s=e.exec(t);if(!s)return null;let o=s[1],i=s[2],a=s.index+s[0].length;n.lastIndex=a;let r=1,l;for(;(l=n.exec(t))!==null;)if(l[1].startsWith("for"))r++;else if(r--,r===0){let c=t.slice(a,l.index);return{varName:o,iterExpr:i,body:c,start:s.index,end:l.index+l[0].length}}return null}function tr(t,e){let n=t,s=0;for(;Fs.test(n)&&s<50;)s++,n=n.replace(Fs,(o,i,a)=>{let r=a.split(/\{%[-\s]*else\s*-?%\}/),l=r[0],c=r[1]||"",d=l.split(/\{%[-\s]*elif\s+(.*?)\s*-?%\}/);if(d.length>1){if($t(i,e))return d[0];for(let u=1;u<d.length;u+=2){let p=d[u],f=d[u+1]||"";if($t(p,e))return f}return c}return $t(i,e)?l:c}),Fs.lastIndex=0;return n}function nr(t,e){return t.replace(/\{\{[-\s]*(.*?)[-\s]*\}\}/g,(n,s)=>{let i=s.trim().split("|"),a=i[0].trim(),r=pt(e,a);for(let c=1;c<i.length;c++)r=or(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 Nc(t){return t=t.replace(/\{%.*?%\}/gs,""),t=t.replace(/\{\{.*?\}\}/gs,""),t}function Mc(t,e){let n=t.match(/^range\(\s*(.+?)\s*,\s*(.+?)\s*\)$/);if(n){let o=Zi(n[1],e),i=Zi(n[2],e),a=[];for(let r=o;r<i;r++)a.push(r);return a}let s=t.match(/^(.+?)\|split\(['"](.+?)['"]\)$/);if(s){let o=pt(e,s[1].trim());return typeof o=="string"?o.split(s[2]):[]}return pt(e,t)}function Zi(t,e){let s=t.trim().split("|"),o=s[0].trim();if(!isNaN(Number(o)))return Number(o);let i=pt(e,o);for(let a=1;a<s.length;a++)i=or(i,s[a].trim());return Number(i)||0}function pt(t,e){let n=e.split("."),s=t;for(let o of n){if(s==null||typeof s!="object")return;s=s[o]}return s}function $t(t,e){let n=t.trim();if(n.startsWith("not "))return!$t(n.slice(4),e);if(n.includes(" and "))return n.split(" and ").every(i=>$t(i,e));if(n.includes(" or "))return n.split(" or ").some(i=>$t(i,e));let s=n.match(/^(.+?)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);if(s){let i=pt(e,s[1].trim()),a=s[2],r=s[3].trim();switch(typeof r=="string"&&r.startsWith('"')&&r.endsWith('"')||typeof r=="string"&&r.startsWith("'")&&r.endsWith("'")?r=r.slice(1,-1):isNaN(Number(r))?r=pt(e,r):r=Number(r),a){case"==":return i==r;case"!=":return i!=r;case">":return Number(i)>Number(r);case"<":return Number(i)<Number(r);case">=":return Number(i)>=Number(r);case"<=":return Number(i)<=Number(r)}}let o=pt(e,n);return sr(o)}function sr(t){return!(t==null||t===""||t===0||t===!1||Array.isArray(t)&&t.length===0)}function or(t,e){let n=t==null?"":String(t),s=e.match(/^(\w+)\((.*)\)$/),o=s?s[1]:e,i=s?s[2].replace(/^["']|["']$/g,""):void 0;switch(o){case"escape":case"e":return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");case"lower":return n.toLowerCase();case"upper":return n.toUpperCase();case"capitalize":return n.charAt(0).toUpperCase()+n.slice(1);case"trim":return n.trim();case"truncate":if(i){let a=parseInt(i,10);return n.length>a?n.slice(0,a)+"...":n}return n;case"default":return sr(t)?t:i??"";case"length":return Array.isArray(t)?t.length:n.length;case"join":return Array.isArray(t)?t.join(i??", "):n;case"int":case"float":return Number(n)||0;case"abs":return Math.abs(Number(n));case"round":return Math.round(Number(n));default:return t}}var vc,wc,xc,Xi,Qi,Cc,Ac,Ic,kc,$c,Fs,ir=J(()=>{"use strict";g();vc=/\{%[-\s]*require_(css|js)\b.*?%\}/gs,wc=/\{%[-\s]*end_require_(css|js)\s*%\}/gs,xc=/\{\{[-\s]*require_(css|js)\(.*?\)\s*\}\}/gs,Xi=/\{\{[-\s]*get_asset_url\(["'](?:[^"'\/]+\/)?assets\/(.*?)["']\)\s*\}\}/gs,Qi=/\{\{[-\s]*get_asset_url\(.*?\)\s*\}\}/gs,Cc=/\{%[-\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\b.*?%\}/gs,Ac=/\{%[-\s]*module\b.*?%\}/gs,Ic=/\{%[-\s]*(extends|block|endblock|set)\b.*?%\}/gs,kc=/\{#.*?#\}/gs,$c=/\{\{[-\s]*content\.\w+.*?\}\}/gs,Fs=/\{%[-\s]*if\s+(.*?)\s*-?%\}([\s\S]*?)\{%[-\s]*endif\s*-?%\}/g});var Gs={};lt(Gs,{buildModulePreviewHtml:()=>Hs,buildPreviewHtml:()=>Ls});function Pc(t){if(!t)return{bg:"#0f0f14",surface:"#1a1a20",text:"#ffffff",textMuted:"#666",border:"#333"};let e=(r,l)=>{for(let c of r){let d=new RegExp(`${c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\s*:\\s*([^;})]+)`,"i"),u=t.match(d);if(u)return u[1].trim()}return l},n=e(["--bg","--background","--color-bg","--bg-primary","--body-bg"],"#0f0f14"),s=e(["--surface","--bg-secondary","--card-bg","--color-surface"],n),o=e(["--text","--color-text","--text-primary","--fg","--foreground"],"#ffffff"),i=e(["--text-muted","--text-secondary","--muted","--color-text-muted"],"#666"),a=e(["--border","--border-color","--color-border"],"#333");return{bg:n,surface:s,text:o,textMuted:i,border:a}}function Ls(){let t=v();if(!t)return rr();let e=me(),n=t.moduleOrder||[];if(e.length===0&&n.length===0)return rr();let s=[],o=[],i=[],a=new Set;for(let c of e){if(c.moduleHtml.includes("dnd_area")||c.moduleHtml.includes("extends "))continue;let d;try{let f=JSON.parse(c.fieldsJson);d={module:Yn(f)}}catch{d={module:{}}}let u=Js(c.moduleHtml,d),p=c.moduleName.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");s.push(`<div class="vibespot-module" id="${p}" data-module="${c.moduleName}">${u}</div>`),a.add(c.moduleName),c.moduleCss&&o.push(c.moduleCss),c.moduleJs&&i.push(c.moduleJs)}let r=Pc(t.sharedCss);for(let c of n)if(!a.has(c)){let d=c.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");s.push(`<div class="vibespot-module vibespot-module--pending" id="${d}" data-module="${c}">
|
|
475
243
|
<div class="vibespot-placeholder">
|
|
476
244
|
<div class="vibespot-placeholder__name">${c}</div>
|
|
477
245
|
</div>
|
|
478
|
-
</div>`)}let l=`body{background:${r.bg}}.vibespot-placeholder{display:flex;align-items:center;justify-content:center;min-height:200px;padding:3rem;background:${r.surface};border:1px dashed ${r.border};border-radius:12px;margin:1rem 0}.vibespot-placeholder__name{font-size:1.5rem;font-weight:600;font-family:system-ui,sans-serif;color:${r.textMuted};letter-spacing:.5px;animation:vp-fade 2s ease-in-out infinite}@keyframes vp-fade{0%,100%{opacity:.3}50%{opacity:.8}}`;return
|
|
246
|
+
</div>`)}let l=`body{background:${r.bg}}.vibespot-placeholder{display:flex;align-items:center;justify-content:center;min-height:200px;padding:3rem;background:${r.surface};border:1px dashed ${r.border};border-radius:12px;margin:1rem 0}.vibespot-placeholder__name{font-size:1.5rem;font-weight:600;font-family:system-ui,sans-serif;color:${r.textMuted};letter-spacing:.5px;animation:vp-fade 2s ease-in-out infinite}@keyframes vp-fade{0%,100%{opacity:.3}50%{opacity:.8}}`;return Ds({renderedModules:s,sharedCss:t.sharedCss,moduleCssArray:[l,...o],sharedJs:t.sharedJs,moduleJsArray:i})}function rr(){return`<!DOCTYPE html>
|
|
479
247
|
<html lang="en">
|
|
480
248
|
<head>
|
|
481
249
|
<meta charset="utf-8">
|
|
@@ -526,8 +294,8 @@ document.querySelectorAll('img').forEach(function(img){
|
|
|
526
294
|
<div class="welcome__sub">Build Something Great</div>
|
|
527
295
|
</div>
|
|
528
296
|
</body>
|
|
529
|
-
</html>`}function
|
|
530
|
-
`)}catch{}}}var
|
|
297
|
+
</html>`}function Hs(t){let e=v();if(!e)return"";let n;for(let i of e.templates)if(n=i.modules.find(a=>a.moduleName===t),n)break;if(n||(n=e.modules.find(i=>i.moduleName===t)),!n)return"";let s;try{let i=JSON.parse(n.fieldsJson);s={module:Yn(i)}}catch{s={module:{}}}let o=Js(n.moduleHtml,s);return Ds({renderedModules:[`<div class="vibespot-module" data-module="${n.moduleName}">${o}</div>`],sharedCss:e.sharedCss,moduleCssArray:n.moduleCss?[n.moduleCss]:[],sharedJs:e.sharedJs,moduleJsArray:n.moduleJs?[n.moduleJs]:[]})}var zn=J(()=>{"use strict";g();ir();Se()});import{appendFileSync as _c,mkdirSync as Rc,readdirSync as Oc,unlinkSync as jc}from"fs";import{join as Ks}from"path";import{homedir as Fc}from"os";function Dc(){if(!Ws)try{Rc(qn,{recursive:!0}),Ws=!0}catch{}}function Lc(){if(!Bs){Bs=!0;try{let t=Date.now()-Jc*864e5;for(let e of Oc(qn)){if(!e.startsWith("vibespot-")||!e.endsWith(".log"))continue;let n=e.slice(9,19),s=new Date(n).getTime();if(s&&s<t)try{jc(Ks(qn,e))}catch{}}}catch{}}}function Hc(){let e=new Date().toISOString().slice(0,10);return Ks(qn,`vibespot-${e}.log`)}function Gc(){return new Date().toISOString().slice(11,23)}function Us(t,e){if(Dc(),!!Ws){Bs||Lc();try{_c(Hc(),`${Gc()} ${t} ${e}
|
|
298
|
+
`)}catch{}}}var qn,Jc,Ws,Bs,E,ve=J(()=>{"use strict";g();qn=Ks(Fc(),".vibespot","logs"),Jc=7,Ws=!1,Bs=!1;E={info(t,e,n){let s=n?`[${t}] ${e} ${JSON.stringify(n)}`:`[${t}] ${e}`;console.log(s),Us("INFO",s)},warn(t,e,n){let s=n?`[${t}] ${e} ${JSON.stringify(n)}`:`[${t}] ${e}`;console.warn(s),Us("WARN",s)},error(t,e,n){let s=n instanceof Error?n.message:n?String(n):"",o=s?`[${t}] ${e}: ${s}`:`[${t}] ${e}`;console.error(o),Us("ERROR",o)}}});function Le(t){try{return JSON.parse(t)}catch{}let e=t,n=-1;for(let s=0;s<20;s++)try{return JSON.parse(e)}catch(o){if(!(o instanceof SyntaxError))return null;let i=/position (\d+)/.exec(o.message);if(!i)return null;let a=parseInt(i[1],10);if(a<=n)return null;n=a;let r=Math.max(0,a-5),c=e.slice(r,a+1).lastIndexOf('"');if(c===-1)return null;let d=r+c;if(d>0&&e[d-1]==="\\")return null;e=e.slice(0,d)+'\\"'+e.slice(d+1)}return null}function tn(t){let e=t.indexOf('"modules"');if(e===-1)return null;let n=t.indexOf("[",e);if(n===-1)return null;let s=-1,o=0,i=!1,a=!1;for(let d=n+1;d<t.length;d++){let u=t[d];if(a){a=!1;continue}if(u==="\\"){a=!0;continue}if(u==='"'){i=!i;continue}i||(u==="{"&&o++,u==="}"&&(o--,o===0&&(s=d)))}if(s===-1)return null;let l=t.slice(0,s+1)+"]}",c=l.trimStart().startsWith("{")?l:"{"+l;return Le(c)}function Vs(t){return{moduleName:String(t.moduleName||""),fieldsJson:typeof t.fieldsJson=="string"?t.fieldsJson:JSON.stringify(t.fieldsJson,null,2),metaJson:typeof t.metaJson=="string"?t.metaJson:JSON.stringify(t.metaJson,null,2),moduleHtml:String(t.moduleHtml||""),moduleCss:String(t.moduleCss||""),moduleJs:t.moduleJs?String(t.moduleJs):void 0}}function ar(t,e){let n=!1,s,o=/```vibespot-modules\s*\n?([\s\S]*?)```/g;for(;(s=o.exec(t))!==null;)try{E.info("parse","Found vibespot-modules block",{length:s[1].length});let i=Le(s[1]);if(!i||typeof i!="object")throw E.warn("parse","tryParseJSON returned non-object",{result:typeof i}),new Error("Invalid JSON after repair");let a=i;a.modules&&Array.isArray(a.modules)&&(De({modules:a.modules.map(r=>Vs(r)),sharedCss:a.sharedCss!==void 0?String(a.sharedCss):void 0,sharedJs:a.sharedJs!==void 0?String(a.sharedJs):void 0}),n=!0)}catch(i){E.warn("parse","Failed to parse vibespot-modules block",{error:i instanceof Error?i.message:String(i)})}if(!n){let i=/```(?:json)?\s*\n([\s\S]*?)```/g;for(;(s=i.exec(t))!==null;)if(s[1].includes('"modules"'))try{let a=Le(s[1]);if(!a||typeof a!="object")throw new Error("Invalid JSON after repair");let r=a;r.modules&&Array.isArray(r.modules)&&(De({modules:r.modules.map(l=>Vs(l)),sharedCss:r.sharedCss!==void 0?String(r.sharedCss):void 0,sharedJs:r.sharedJs!==void 0?String(r.sharedJs):void 0}),n=!0)}catch(a){E.warn("parse","Failed to parse JSON module block",{error:a instanceof Error?a.message:String(a)})}}if(!n&&(t.match(/```/g)||[]).length%2!==0&&t.includes('"modules"')){E.info("parse","Detected truncated response (odd fence count), attempting salvage");let a=t.lastIndexOf("```"),r=t.slice(a+3);r=r.replace(/^[\w-]*\s*\n?/,"");let l=tn(r);if(l){let c=l;c.modules&&Array.isArray(c.modules)&&c.modules.length>0&&(E.info("parse","Salvaged modules from truncated response",{count:c.modules.length}),De({modules:c.modules.map(d=>Vs(d)),sharedCss:c.sharedCss!==void 0?String(c.sharedCss):void 0,sharedJs:c.sharedJs!==void 0?String(c.sharedJs):void 0}),n=!0,e&&e("Response was truncated \u2014 some modules may be incomplete. Try sending your request again for the full set."))}}if(!n){E.info("parse","No modules applied",{responseLength:t.length,hasVibespot:t.includes("vibespot-modules"),hasModules:t.includes('"modules"'),fenceCount:(t.match(/```/g)||[]).length});let i=t.includes("vibespot-modules")||t.includes('"modules"'),a=/\bmodule|modul/i.test(t)&&(/\bcreated?\b|\berstellt\b|\bgenerat/i.test(t)||/\|.*\|.*\|/m.test(t));if(i||a){let r=i?"Module changes could not be applied \u2014 the AI response contained invalid JSON. Try sending your request again.":"The AI described modules but did not include the required structured data. Try sending your request again.";E.warn("parse",r),e&&e(r)}}}var Xn=J(()=>{"use strict";g();Se();ve()});function Tt(){let t=v();return t?{pageType:Ce()?.pageType,brandAssets:t.brandAssets}:{}}function Et(t,e,n=!1,s,o){let i=`You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.
|
|
531
299
|
|
|
532
300
|
## Your Role
|
|
533
301
|
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.
|
|
@@ -606,7 +374,7 @@ The current template's modules are listed in page order in the user message. Thi
|
|
|
606
374
|
- **Rearrange**: When the user asks to reorder sections, include a "moduleOrder" array in the vibespot-modules JSON with the new sequence of module names.
|
|
607
375
|
- **Remove**: When the user asks to remove a section, omit it from the output.
|
|
608
376
|
- **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.
|
|
609
|
-
- **Design consistency**: Match the existing theme's design language \u2014 reuse the same CSS custom properties, class naming prefix, spacing scale, and typography.`,a=s?
|
|
377
|
+
- **Design consistency**: Match the existing theme's design language \u2014 reuse the same CSS custom properties, class naming prefix, spacing scale, and typography.`,a=s?zo(s):"",r=a?`
|
|
610
378
|
|
|
611
379
|
## Page Type Context
|
|
612
380
|
${a}`:"",l="";if(o?.styleguide&&(l+=`
|
|
@@ -615,13 +383,13 @@ ${a}`:"",l="";if(o?.styleguide&&(l+=`
|
|
|
615
383
|
${o.styleguide}`),o?.brandvoice&&(l+=`
|
|
616
384
|
|
|
617
385
|
## Brand Voice
|
|
618
|
-
${o.brandvoice}`),o?.humanify!==!1){let d=
|
|
386
|
+
${o.brandvoice}`),o?.humanify!==!1){let d=Yo();d&&(l+=`
|
|
619
387
|
|
|
620
388
|
## Anti-AI Copy Rules (Humanify)
|
|
621
389
|
${d}`)}let c="\n\n## REMINDER \u2014 Output Format (CRITICAL)\nYour response MUST contain a ```vibespot-modules code block with the full JSON. Without this block, no modules will be created. Do NOT respond with only text, tables, or descriptions. The JSON block is mandatory.";return n?i+r+l+`
|
|
622
390
|
|
|
623
391
|
## HubSpot CMS Rules
|
|
624
|
-
${
|
|
392
|
+
${Ze()}
|
|
625
393
|
|
|
626
394
|
## Conversion Guide Reference
|
|
627
395
|
${t}`+c:i+r+l+`
|
|
@@ -649,16 +417,16 @@ When using scroll-animate classes (opacity: 0 \u2192 visible), you MUST include
|
|
|
649
417
|
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.
|
|
650
418
|
|
|
651
419
|
## Design Guide
|
|
652
|
-
${
|
|
420
|
+
${Ko()}
|
|
653
421
|
|
|
654
422
|
## Content & Copywriting Guide
|
|
655
|
-
${
|
|
423
|
+
${Vo()}
|
|
656
424
|
|
|
657
425
|
## HubSpot CMS Rules
|
|
658
|
-
${
|
|
426
|
+
${Ze()}
|
|
659
427
|
|
|
660
428
|
## Conversion Guide Reference
|
|
661
|
-
${t}`+c}function
|
|
429
|
+
${t}`+c}function nn(){let t=v(),e=[],n=t.modules,s=n.length;if(s>0){e.push(`
|
|
662
430
|
|
|
663
431
|
## Page Narrative (module sequence)
|
|
664
432
|
`),e.push(`This template has ${s} module${s===1?"":"s"} in this order:
|
|
@@ -695,13 +463,13 @@ ${t.sharedCss}
|
|
|
695
463
|
\`\`\`js
|
|
696
464
|
${t.sharedJs}
|
|
697
465
|
\`\`\`
|
|
698
|
-
`)}let o=
|
|
466
|
+
`)}let o=nt(),i=new Set(t.modules.map(r=>r.moduleName)),a=o.filter(r=>!i.has(r.module.moduleName));if(a.length>0){e.push(`
|
|
699
467
|
|
|
700
468
|
## Available modules in this theme (reusable)
|
|
701
469
|
`);for(let r of a)e.push(`- ${r.module.moduleName} (used in: ${r.usedIn.join(", ")})
|
|
702
470
|
`);e.push(`
|
|
703
471
|
The user can ask to reuse any of these modules by name.
|
|
704
|
-
`)}return e.join("")}function
|
|
472
|
+
`)}return e.join("")}function Ys(t,e){let n=v(),s=n.messages.slice(-20);s.length>0&&s[s.length-1].role==="user"&&s[s.length-1].content===t&&(s=s.slice(0,-1));let o=s.map(d=>({role:d.role,content:d.content})),i=nn(),a="";if(n.assets?.length){let d=n.assets.filter(u=>u.type==="image"&&u.usage==="asset");d.length>0&&(a=`
|
|
705
473
|
|
|
706
474
|
## Available Theme Assets
|
|
707
475
|
These images are in the theme's assets/ folder. Reference them with get_asset_url("${n.themeName}/assets/filename"):
|
|
@@ -715,56 +483,59 @@ ${i}`),a&&(r+=a),r+="\n\n---\nRemember: respond with a ```vibespot-modules JSON
|
|
|
715
483
|
[Attached document: ${d.originalName}]
|
|
716
484
|
${d.extractedText}`),d.type==="image"&&d.usage==="asset"&&d.assetPath&&(r+=`
|
|
717
485
|
|
|
718
|
-
[Uploaded image: ${d.originalName} \u2192 available as get_asset_url("${d.assetPath}")]`);let c=l?e.filter(d=>d.type==="image"&&d.base64):[];if(c.length>0){let d=[];for(let u of c)d.push({type:"image",source:{type:"base64",media_type:u.mimeType,data:u.base64}});d.push({type:"text",text:r}),o.push({role:"user",content:d})}else o.push({role:"user",content:r});return o}var
|
|
486
|
+
[Uploaded image: ${d.originalName} \u2192 available as get_asset_url("${d.assetPath}")]`);let c=l?e.filter(d=>d.type==="image"&&d.base64):[];if(c.length>0){let d=[];for(let u of c)d.push({type:"image",source:{type:"base64",media_type:u.mimeType,data:u.base64}});d.push({type:"text",text:r}),o.push({role:"user",content:d})}else o.push({role:"user",content:r});return o}var lr=J(()=>{"use strict";g();Ve();Se()});import{spawn as Uc}from"child_process";async function Wc(){return zs||(zs=(await import("@anthropic-ai/sdk")).default),zs}function cr(t){if(!t?.length)return"";let e=[];for(let n of t)n.type==="image"&&n.usage==="asset"&&n.assetPath&&e.push(`
|
|
719
487
|
[Uploaded image: ${n.originalName} \u2192 use get_asset_url("${n.assetPath}")]`),n.type==="document"&&n.extractedText&&e.push(`
|
|
720
488
|
|
|
721
489
|
---
|
|
722
490
|
[Attached document: ${n.originalName}]
|
|
723
|
-
${n.extractedText}`);return e.join("")}
|
|
724
|
-
`);R=
|
|
491
|
+
${n.extractedText}`);return e.join("")}async function dr(t,e,n,s,o,i,a,r){let l=await Wc(),c=new l({apiKey:e}),d=le(),p=v().modules.length>0,f=Ys(t,r),h=Tt(),y=Et(d,n,p,h.pageType,h.brandAssets);E.info("anthropic","API call",{model:s,systemPromptLength:y.length,messageCount:f.length,messageRoles:f.map(b=>b.role),lastMessageLength:typeof f[f.length-1]?.content=="string"?f[f.length-1].content.length:"multimodal",conversionGuideLength:d.length});for(let b=0;;b++)try{let A="",w=0,$=i||(()=>{});$(fe[0]);let R=setInterval(()=>{w++,$(fe[Math.min(w,fe.length-1)])},6e3);try{let P=c.messages.stream({model:s,max_tokens:48e3,system:y,messages:f});for await(let N of P)if(N.type==="content_block_delta"&&N.delta.type==="text_delta"){let L=N.delta.text;A+=L,o(L)}}finally{clearInterval(R)}a&&a(A);return}catch(A){let w=A.status,$=A.error?.type;if(!(w===429||$==="rate_limit_error"||A instanceof Error&&A.message.includes("429"))||b>=qs.length)throw A;let P=qs[b];E.warn("ai-engine",`Rate limited (429), attempt ${b+1}/${qs.length} \u2014 waiting ${P}s`),i&&i(`Rate limited by Anthropic API \u2014 retrying in ${P}s...`),await new Promise(N=>setTimeout(N,P*1e3)),i&&i("Retrying...")}}async function ur(t,e,n,s,o,i,a,r){let l=le(),c=v().modules.length>0,d=Ys(t,r),u=Tt(),p=d.map(P=>typeof P.content=="string"?P:{role:P.role,content:P.content.map(N=>N.type==="text"?{type:"text",text:N.text}:{type:"image_url",image_url:{url:`data:${N.source.media_type};base64,${N.source.data}`}})}),f=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:s,max_tokens:48e3,stream:!0,messages:[{role:"system",content:Et(l,n,c,u.pageType,u.brandAssets)},...p]})});if(!f.ok){let P=await f.text();throw new Error(`OpenAI API error (${f.status}): ${P}`)}let h=0,y=i||(()=>{});y(fe[0]);let b=setInterval(()=>{h++,y(fe[Math.min(h,fe.length-1)])},6e3),A="",w=f.body.getReader(),$=new TextDecoder,R="";try{for(;;){let{done:P,value:N}=await w.read();if(P)break;R+=$.decode(N,{stream:!0});let L=R.split(`
|
|
492
|
+
`);R=L.pop()||"";for(let ne of L){if(!ne.startsWith("data: "))continue;let U=ne.slice(6).trim();if(U==="[DONE]")break;try{let O=JSON.parse(U).choices?.[0]?.delta?.content;O&&(A+=O,o(O))}catch{}}}}finally{clearInterval(b)}a&&a(A)}async function mr(t,e,n,s,o,i,a){let r=le(),l=v(),c=l.modules.length>0,d=nn(),u=Tt(),p=[];for(let U of l.messages.slice(-20))p.push({role:U.role==="assistant"?"model":"user",parts:[{text:U.content}]});let f=d?`${t}
|
|
725
493
|
|
|
726
494
|
---
|
|
727
|
-
${d}`:t;if(a?.length)for(let
|
|
495
|
+
${d}`:t;if(a?.length)for(let U of a)U.type==="document"&&U.extractedText&&(f+=`
|
|
728
496
|
|
|
729
497
|
---
|
|
730
|
-
[Attached document: ${
|
|
731
|
-
${
|
|
498
|
+
[Attached document: ${U.originalName}]
|
|
499
|
+
${U.extractedText}`),U.type==="image"&&U.usage==="asset"&&U.assetPath&&(f+=`
|
|
732
500
|
|
|
733
|
-
[Uploaded image: ${
|
|
734
|
-
`);
|
|
501
|
+
[Uploaded image: ${U.originalName} \u2192 available as get_asset_url("${U.assetPath}")]`);let h=[];if(a?.length)for(let U of a)U.type==="image"&&U.base64&&h.push({inlineData:{mimeType:U.mimeType,data:U.base64}});h.push({text:f}),p.push({role:"user",parts:h});let b=`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse&key=${e}`,A=await fetch(b,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({systemInstruction:{parts:[{text:Et(r,n,c,u.pageType,u.brandAssets)}]},contents:p,generationConfig:{maxOutputTokens:48e3}})});if(!A.ok){let U=await A.text();throw new Error(`Gemini API error (${A.status}): ${U}`)}let w=0,$=o||(()=>{});$(fe[0]);let R=setInterval(()=>{w++,$(fe[Math.min(w,fe.length-1)])},6e3),P="",N=A.body.getReader(),L=new TextDecoder,ne="";try{for(;;){let{done:U,value:G}=await N.read();if(U)break;ne+=L.decode(G,{stream:!0});let O=ne.split(`
|
|
502
|
+
`);ne=O.pop()||"";for(let z of O){if(!z.startsWith("data: "))continue;let ae=z.slice(6).trim();try{let Rt=JSON.parse(ae).candidates?.[0]?.content?.parts?.[0]?.text;Rt&&(P+=Rt,s(Rt))}catch{}}}}finally{clearInterval(R)}i&&i(P)}function Qn(t,e,n,s){return new Promise((o,i)=>{let a={...process.env};delete a.CLAUDECODE;let r=Uc(t,e,{stdio:["pipe","pipe","pipe"],env:a}),l="",c="",d=!1,u=h=>{d||(d=!0,h())};r.stdout.on("data",h=>{let y=h.toString();l+=y,s&&s(y)}),r.stderr.on("data",h=>{c+=h.toString()}),r.on("error",h=>u(()=>i(new Error(`${t} failed to start: ${h.message}`)))),r.on("close",h=>{u(()=>{h!==0?i(new Error(`${t} exited with code ${h}.
|
|
735
503
|
`+(c?`Stderr: ${c.slice(0,500)}
|
|
736
504
|
`:"")+(l?`Output: ${l.slice(0,500)}`:"No output"))):o(l)})}),r.stdin.on("error",()=>{}),r.stdin.write(n)?r.stdin.end():r.stdin.once("drain",()=>r.stdin.end());let f=setTimeout(()=>{r.kill(),u(()=>i(new Error(`${t} timed out after 5 minutes.
|
|
737
505
|
`+(c?`Stderr: ${c.slice(0,500)}
|
|
738
|
-
`:"")+`Partial output (${l.length} chars): ${l.slice(0,500)}`)))},3e5);r.on("close",()=>clearTimeout(f))})}async function
|
|
506
|
+
`:"")+`Partial output (${l.length} chars): ${l.slice(0,500)}`)))},3e5);r.on("close",()=>clearTimeout(f))})}async function pr(t,e,n,s,o,i){let a=le(),r=M(),l=v().modules.length>0,c=Tt(),d=Et(a,e,l,c.pageType,c.brandAssets);d+=`
|
|
739
507
|
|
|
740
508
|
## User Request
|
|
741
|
-
`+t,d+=
|
|
509
|
+
`+t,d+=nn(),d+=cr(i),d+="\n\n---\nRemember: respond with a ```vibespot-modules JSON block containing ALL modules. No text-only responses.";let u=["--print"];r.claudeCodeModel&&u.push("--model",r.claudeCodeModel);let p=0,f=s||(()=>{});f(fe[0]);let h=setInterval(()=>{p++;let y=fe[Math.min(p,fe.length-1)];f(y)},6e3);try{let y=await Qn("claude",u,d,b=>{n(b)});o&&o(y)}finally{clearInterval(h)}}async function Xs(t,e,n,s,o,i,a){let r=le(),l=v().modules.length>0,c=Tt(),d=Et(r,n,l,c.pageType,c.brandAssets);d+=`
|
|
742
510
|
|
|
743
511
|
## User Request
|
|
744
|
-
`+e,d+=
|
|
512
|
+
`+e,d+=nn(),d+=cr(a),d+="\n\n---\nRemember: respond with a ```vibespot-modules JSON block containing ALL modules. No text-only responses.";let u,p;t==="gemini"?(u="gemini",p=[]):(u="codex",p=["exec","--full-auto"]);let f=0,h=o||(()=>{});h(fe[0]);let y=setInterval(()=>{f++;let b=fe[Math.min(f,fe.length-1)];h(b)},6e3);try{let b=await Qn(u,p,d,A=>{s(A)});i&&i(b)}finally{clearInterval(y)}}var zs,fe,qs,Qs=J(()=>{"use strict";g();Ve();ee();Se();lr();ve();zs=null;fe=["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..."],qs=[10,20,40,60,120]});function m(t,e,n){t.writeHead(e,{"Content-Type":"application/json"}),t.end(JSON.stringify(n))}function j(t,e){let n=[];t.on("data",s=>n.push(s)),t.on("end",()=>e(Buffer.concat(n).toString("utf-8")))}function Zs(t,e,n){j(t,s=>{try{n(JSON.parse(s||"{}"))}catch{m(e,400,{error:"Invalid JSON in request body"})}})}var ot=J(()=>{"use strict";g()});import{createWriteStream as Bc,mkdirSync as fr,existsSync as eo,readFileSync as to}from"fs";import{join as ft,extname as Kc}from"path";import{randomUUID as Vc}from"crypto";import Yc from"busboy";function Qc(t){return t.replace(/[^a-zA-Z0-9._-]/g,"_").replace(/_{2,}/g,"_").replace(/^_+|_+$/g,"").toLowerCase()}function Zc(t,e){if(!eo(ft(t,e)))return e;let n=Kc(e),s=e.slice(0,-n.length||void 0),o=1;for(;eo(ft(t,`${s}-${o}${n}`));)o++;return`${s}-${o}${n}`}async function ed(t){let e=(await import("pdf-parse")).default,n=to(t);return(await e(n)).text}async function td(t){return(await(await import("mammoth")).extractRawText({path:t})).value}function nd(t){return to(t,"utf-8")}function hr(t,e){let n=v();if(!n){m(e,400,{error:"No active session"});return}if(!(t.headers["content-type"]||"").includes("multipart/form-data")){m(e,400,{error:"Expected multipart/form-data"});return}let o=[],i=[],a=0,r=[],l=Yc({headers:t.headers,limits:{fileSize:zc,files:10}});l.on("file",(c,d,u)=>{let{filename:p,mimeType:f}=u;if(a++,!Xc.has(f)){i.push(`Unsupported file type: ${p} (${f})`),d.resume();return}let h=gr.has(f),y=Qc(p),b=Vc(),A,w;h?(A=ft(n.themePath,"assets"),fr(A,{recursive:!0}),w=Zc(A,y)):(A=ft(n.themePath,".vibespot","uploads"),fr(A,{recursive:!0}),w=`${b}-${y}`);let $=ft(A,w),R=Bc($),P=0,N=!1;d.on("data",L=>{P+=L.length}),d.on("limit",()=>{N=!0,i.push(`File too large (>10MB): ${p}`)}),d.pipe(R),r.push(new Promise(L=>{R.on("finish",()=>{if(!N){let ne={id:b,filename:w,originalName:p,type:h?"image":"document",usage:h?"asset":"context",mimeType:f,size:P,addedAt:new Date().toISOString()};o.push(ne),Pi(ne)}L()}),R.on("error",()=>{i.push(`Failed to write: ${p}`),L()})}))}),l.on("finish",async()=>{await Promise.all(r);for(let c of o)if(c.type==="document"){let d=ft(n.themePath,".vibespot","uploads",c.filename);try{c.mimeType==="application/pdf"?c.extractedText=await ed(d):c.mimeType==="application/vnd.openxmlformats-officedocument.wordprocessingml.document"?c.extractedText=await td(d):c.extractedText=nd(d),E.info("upload",`Extracted text from ${c.originalName} (${c.extractedText.length} chars)`)}catch(u){E.warn("upload",`Failed to extract text from ${c.originalName}: ${u}`),c.extractedText=`[Could not extract text from ${c.originalName}]`}}if(a===0){m(e,400,{error:"No files uploaded"});return}m(e,200,{files:o.map(c=>({id:c.id,filename:c.filename,originalName:c.originalName,type:c.type,usage:c.usage,size:c.size})),errors:i.length>0?i:void 0})}),l.on("error",c=>{E.error("upload",`Busboy error: ${c}`),m(e,500,{error:"Upload failed"})}),t.pipe(l)}function yr(t){let e=v();return e?.assets?t.map(n=>{let s=e.assets.find(i=>i.id===n);if(!s)return null;let o={id:s.id,filename:s.filename,originalName:s.originalName,type:s.type,usage:s.usage,mimeType:s.mimeType};if(s.type==="image"){let i=ft(e.themePath,"assets",s.filename);eo(i)&&(o.base64=to(i).toString("base64")),o.assetPath=`${e.themeName}/assets/${s.filename}`}else s.type==="document"&&(o.extractedText=s.extractedText);return o}).filter(n=>n!==null):[]}var zc,gr,qc,Xc,no=J(()=>{"use strict";g();ot();Se();ve();zc=10*1024*1024,gr=new Set(["image/png","image/jpeg","image/jpg","image/svg+xml","image/webp","image/gif"]),qc=new Set(["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/markdown","text/plain"]),Xc=new Set([...gr,...qc])});async function br(t,e){for(let n=0;;n++)try{return await t()}catch(s){let o=s.status,i=s.error?.type;if(!(o===429||i==="rate_limit_error"||s instanceof Error&&s.message.includes("429"))||n>=so.length)throw s;let r=so[n];E.warn("agent-adapter",`Rate limited (429), attempt ${n+1}/${so.length} \u2014 waiting ${r}s`),e&&e(`Rate limited \u2014 retrying in ${r}s...`),await new Promise(l=>setTimeout(l,r*1e3)),e&&e("Retrying...")}}function Zn(t){if(t&&typeof t=="object"&&!Array.isArray(t)){let e=t;for(let n of["fieldsJson","metaJson"])e[n]&&typeof e[n]=="object"&&(e[n]=JSON.stringify(e[n]))}return t}async function sd(){return oo||(oo=(await import("@anthropic-ai/sdk")).default),oo}async function od(t,e,n){let s=await sd(),o=new s({apiKey:t}),i=n.messages;if(n.structuredOutput){let a={name:n.structuredOutput.name,description:`Return the result as structured JSON matching the ${n.structuredOutput.name} schema.`,input_schema:n.structuredOutput.schema};return br(async()=>{let r=await o.messages.create({model:e,max_tokens:n.maxTokens||16e3,system:n.systemPrompt,messages:i,tools:[a],tool_choice:{type:"tool",name:n.structuredOutput.name}});for(let c of r.content)if(c.type==="tool_use")return{type:"structured",data:Zn(c.input)};return{type:"text",text:r.content.filter(c=>c.type==="text").map(c=>c.text).join("")}},n.onStatus)}return br(async()=>{let a="",r=o.messages.stream({model:e,max_tokens:n.maxTokens||16e3,system:n.systemPrompt,messages:i});for await(let l of r)l.type==="content_block_delta"&&l.delta.type==="text_delta"&&(a+=l.delta.text,n.onChunk&&n.onChunk(l.delta.text));return{type:"text",text:a}},n.onStatus)}function io(t){let e={...t};if(e.type==="object"&&(e.additionalProperties=!1,e.properties&&typeof e.properties=="object")){let n={};for(let[s,o]of Object.entries(e.properties))n[s]=o&&typeof o=="object"?io(o):o;e.properties=n}return e.items&&typeof e.items=="object"&&(e.items=io(e.items)),e}async function id(t,e,n){let s=[{role:"system",content:n.systemPrompt},...n.messages.map(l=>({role:l.role,content:typeof l.content=="string"?l.content:l.content.map(c=>({type:"text",text:c.text}))}))],o={model:e,max_tokens:n.maxTokens||16e3,messages:s};n.structuredOutput&&(o.response_format={type:"json_schema",json_schema:{name:n.structuredOutput.name,strict:!0,schema:io(n.structuredOutput.schema)}});let i=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(!i.ok){let l=await i.text(),c=i.status;if(c===429){let d=new Error(`OpenAI rate limit: ${l}`);throw d.status=429,d}throw new Error(`OpenAI API error (${c}): ${l}`)}let r=(await i.json()).choices?.[0]?.message?.content||"";if(n.structuredOutput)try{return{type:"structured",data:Zn(JSON.parse(r))}}catch{return E.warn("agent-adapter","OpenAI structured output parse failed, returning raw text"),{type:"text",text:r}}return{type:"text",text:r}}async function rd(t,e,n){let s=e||"gemini-2.5-flash",o=n.messages.map(d=>({role:d.role==="assistant"?"model":"user",parts:typeof d.content=="string"?[{text:d.content}]:d.content.map(u=>({text:u.text}))})),i={systemInstruction:{parts:[{text:n.systemPrompt}]},contents:o,generationConfig:{maxOutputTokens:n.maxTokens||16e3,...n.structuredOutput?{responseMimeType:"application/json",responseSchema:n.structuredOutput.schema}:{}}},a=`https://generativelanguage.googleapis.com/v1beta/models/${s}:generateContent?key=${t}`,r=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!r.ok){let d=await r.text(),u=r.status;if(u===429){let p=new Error(`Gemini rate limit: ${d}`);throw p.status=429,p}throw new Error(`Gemini API error (${u}): ${d}`)}let c=(await r.json()).candidates?.[0]?.content?.parts?.[0]?.text||"";if(n.structuredOutput)try{return{type:"structured",data:Zn(JSON.parse(c))}}catch{return E.warn("agent-adapter","Gemini structured output parse failed, returning raw text"),{type:"text",text:c}}return{type:"text",text:c}}function ad(t){switch(t){case"claude-code":{let e=M(),n=["--print"];return e.claudeCodeModel&&n.push("--model",e.claudeCodeModel),{bin:"claude",args:n}}case"gemini-cli":return{bin:"gemini",args:[]};case"codex-cli":return{bin:"codex",args:["exec","--full-auto"]};default:throw new Error(`Not a CLI engine: ${t}`)}}function ld(t){let e=[t.systemPrompt];for(let n of t.messages){let s=n.role==="user"?"User":"Assistant",o=typeof n.content=="string"?n.content:n.content.map(i=>i.text).join(`
|
|
745
513
|
`);e.push(`
|
|
746
514
|
|
|
747
515
|
## ${s}
|
|
748
|
-
${o}`)}if(t.structuredOutput){let n=
|
|
516
|
+
${o}`)}if(t.structuredOutput){let n=Sr(t.structuredOutput.schema);e.push(`
|
|
749
517
|
|
|
750
518
|
## Output Format \u2014 CRITICAL
|
|
751
519
|
Respond with a JSON code block. Wrap your JSON in \`\`\`json fences. No prose or explanation before or after the code block.
|
|
752
520
|
|
|
753
521
|
The JSON must match this structure:
|
|
754
|
-
${n}`)}return e.join("")}function
|
|
755
|
-
`)}function
|
|
756
|
-
${e.map((
|
|
757
|
-
`)}`:"No modules yet (new page).",
|
|
522
|
+
${n}`)}return e.join("")}function Sr(t,e=0){let n=" ".repeat(e),s=t.properties,o=t.required||[];if(!s)return`${n}${JSON.stringify(t)}`;let i=["{"];for(let[a,r]of Object.entries(s)){let l=o.includes(a)?" (required)":"",c=r.type||"any",d=r.description?` \u2014 ${r.description}`:"",u=r.enum?` [${r.enum.join(", ")}]`:"";if(c==="array"&&r.items){let p=r.items.type||"object";i.push(`${n} "${a}": ${c}<${p}>${l}${d}${u}`)}else c==="object"&&r.properties?i.push(`${n} "${a}": ${Sr(r,e+1)}${l}${d}`):i.push(`${n} "${a}": ${c}${l}${d}${u}`)}return i.push(`${n}}`),i.join(`
|
|
523
|
+
`)}function cd(t){let e=t.trim(),n=Le(e);if(n&&typeof n=="object")return n;let s=e.match(/```(?:json|vibespot-modules)?\s*\n([\s\S]*?)```/i);if(s){let r=s[1].trim(),l=Le(r);if(l&&typeof l=="object")return l;let c=tn(r);if(c&&typeof c=="object")return c}let o=e.indexOf("{"),i=e.lastIndexOf("}");if(o!==-1&&i>o){let r=e.slice(o,i+1),l=Le(r);if(l&&typeof l=="object")return l;let c=tn(r);if(c&&typeof c=="object")return c}let a=tn(e);return a&&typeof a=="object"?a:null}async function dd(t,e,n){let{bin:s,args:o}=ad(t),i=ld(n),a=await Qn(s,o,i,n.onChunk);if(!n.structuredOutput)return{type:"text",text:a};let r=cd(a);return r?{type:"structured",data:Zn(r)}:(E.warn("agent-cli",`${t}: failed to parse structured output, returning text`,{outputPreview:a.slice(0,500),outputLength:a.length}),{type:"text",text:a})}async function md(t,e,n,s){switch(E.info("agent-adapter",`${t} API call`,{model:n,structured:!!s.structuredOutput,schemaName:s.structuredOutput?.name,systemPromptLength:s.systemPrompt.length,messageCount:s.messages.length}),t){case"anthropic-api":return od(e,n,s);case"openai-api":return id(e,n,s);case"gemini-api":return rd(e,n,s);default:throw new Error(`Unsupported API engine: ${t}`)}}async function Ne(t,e,n,s){return ud.has(t)?md(t,e,n,s):(E.info("agent-adapter",`${t} CLI call`,{structured:!!s.structuredOutput,schemaName:s.structuredOutput?.name,systemPromptLength:s.systemPrompt.length,messageCount:s.messages.length}),dd(t,n,s))}function es(t){return t==="anthropic-api"||t==="openai-api"||t==="gemini-api"||t==="claude-code"||t==="gemini-cli"||t==="codex-cli"}function sn(t){return t==="claude-code"||t==="gemini-cli"||t==="codex-cli"}var so,oo,ud,it=J(()=>{"use strict";g();Qs();Xn();ee();ve();so=[10,20,40,60,120];oo=null;ud=new Set(["anthropic-api","openai-api","gemini-api"])});function vr(t,e,n,s){let o=e.length>0?`Current template modules (in page order):
|
|
524
|
+
${e.map((r,l)=>`${l+1}. ${r}`).join(`
|
|
525
|
+
`)}`:"No modules yet (new page).",i=n.length>0?`
|
|
758
526
|
|
|
759
527
|
Module library (reusable from other templates):
|
|
760
|
-
${n.map(
|
|
761
|
-
`)}`:""
|
|
528
|
+
${n.map(r=>`- ${r.name} (used in: ${r.usedIn.join(", ")})`).join(`
|
|
529
|
+
`)}`:"",a=s?`
|
|
530
|
+
|
|
531
|
+
## Product Context
|
|
532
|
+
${s}`:"";return`You are the Intent Analyzer for vibeSpot, a HubSpot CMS page builder.
|
|
762
533
|
|
|
763
534
|
Your job: classify the user's request and plan which modules need work. You do NOT generate module code \u2014 you only plan.
|
|
764
535
|
|
|
765
536
|
## Theme: "${t}"
|
|
766
537
|
|
|
767
|
-
${
|
|
538
|
+
${o}${i}${a}
|
|
768
539
|
|
|
769
540
|
## Classification Rules
|
|
770
541
|
|
|
@@ -805,7 +576,7 @@ CRITICAL: When the user corrects a misclassification (e.g., "I was referencing t
|
|
|
805
576
|
If the user asks for multiple things (e.g., "make hero taller AND add testimonials"), capture ALL parts:
|
|
806
577
|
- Affected existing modules in \`affectedModules\`
|
|
807
578
|
- New modules in \`newModules\`
|
|
808
|
-
- Set the broadest applicable intent (prefer "modify" + newModules over splitting)`}var
|
|
579
|
+
- Set the broadest applicable intent (prefer "modify" + newModules over splitting)`}var wr,xr=J(()=>{"use strict";g();wr={type:"object",properties:{intent:{type:"string",enum:["create","modify","add","remove","rearrange","style_change","question"]},affectedModules:{type:"array",items:{type:"string"},description:"Names of existing modules that need changes"},unchangedModules:{type:"array",items:{type:"string"},description:"Names of existing modules that stay as-is"},newModules:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:{type:"string"},position:{type:"number"}},required:["name","description","position"]},description:"New modules to create"},reuseModules:{type:"array",items:{type:"object",properties:{name:{type:"string"},sourceTemplate:{type:"string"},position:{type:"number"}},required:["name","sourceTemplate","position"]},description:"Modules to copy from the library (immutable structure)"},guidesNeeded:{type:"array",items:{type:"string",enum:["design","content","conversion","hubspot_rules","humanify"]}},designSystemChanges:{type:"boolean",description:"True if shared CSS / design system needs regeneration"},answer:{type:"string",description:'For "question" intent only \u2014 the answer to return directly'}},required:["intent","affectedModules","unchangedModules","newModules","guidesNeeded","designSystemChanges"]}});async function Cr(t,e,n,s,o,i,a){i({type:"agent_step",step:"analyzing",label:"Analyzing your request..."});let r=e.modules.map(f=>f.moduleName),l=vr(e.themeName,r,a,e.brandAssets?.themeContext),c=[],d=e.messages.slice(-6);for(let f of d)if(f.role==="user"||f.role==="assistant"){let h=f.role==="assistant"&&f.content.length>300?f.content.slice(0,300)+"...":f.content;c.push({role:f.role,content:h})}c.push({role:"user",content:t});let u=await Ne(n,s,o,{systemPrompt:l,messages:c,structuredOutput:{schema:wr,name:"pipeline_plan"},maxTokens:2e3});if(u.type!=="structured"){E.warn("intent-analyzer","Did not get structured output, falling back");let f=e.modules.length===0;return{intent:f?"create":"modify",affectedModules:f?[]:r,unchangedModules:[],newModules:[],guidesNeeded:["design","content","conversion","hubspot_rules","humanify"],designSystemChanges:f}}let p=u.data;return p.affectedModules=p.affectedModules||[],p.unchangedModules=p.unchangedModules||[],p.newModules=p.newModules||[],p.guidesNeeded=p.guidesNeeded||[],E.info("intent-analyzer","Plan",{intent:p.intent,affected:p.affectedModules.length,unchanged:p.unchangedModules.length,new:p.newModules.length,reuse:p.reuseModules?.length||0,designSystem:p.designSystemChanges}),i({type:"agent_decision",step:"analyzing",decision:pd(p)}),p}function pd(t){let e=[`Intent: ${t.intent}`];return t.affectedModules.length>0&&e.push(`Modifying: ${t.affectedModules.join(", ")}`),t.unchangedModules.length>0&&e.push(`Unchanged: ${t.unchangedModules.join(", ")}`),t.newModules.length>0&&e.push(`New: ${t.newModules.map(n=>n.name).join(", ")}`),t.reuseModules?.length&&e.push(`Reuse: ${t.reuseModules.map(n=>`${n.name} from ${n.sourceTemplate}`).join(", ")}`),t.designSystemChanges&&e.push("Design system changes: yes"),e.join(" | ")}var Ar=J(()=>{"use strict";g();it();xr();ve()});function Ir(t,e){let n=[];return n.push(`You are the Design System Architect for vibeSpot, a HubSpot CMS page builder.
|
|
809
580
|
|
|
810
581
|
Your job: create a complete, production-ready CSS design system for a landing page theme. You produce the :root custom properties, shared utility/component CSS, and optional shared JS (scroll animations). Downstream agents will use YOUR CSS classes and variables to build individual modules.
|
|
811
582
|
|
|
@@ -892,10 +663,13 @@ Good system font stacks by style:
|
|
|
892
663
|
| Geometric | Futura, "Century Gothic", "Trebuchet MS", sans-serif | system-ui, sans-serif |`),n.push(`
|
|
893
664
|
|
|
894
665
|
## Design Guide
|
|
895
|
-
${
|
|
666
|
+
${fd()}`),e?.styleguide&&n.push(`
|
|
896
667
|
|
|
897
668
|
## Brand Style Guide
|
|
898
|
-
${e.styleguide}`),
|
|
669
|
+
${e.styleguide}`),e?.themeContext&&n.push(`
|
|
670
|
+
|
|
671
|
+
## Product Context
|
|
672
|
+
${e.themeContext}`),n.join("")}function $r(t,e,n,s){let o=[];return o.push(`You are the Module Planner for vibeSpot, a HubSpot CMS page builder.
|
|
899
673
|
|
|
900
674
|
Your job: plan the modules for a landing page. You define what each module contains (content brief) and how it should be laid out. You do NOT write module code \u2014 downstream Module Developers handle that.
|
|
901
675
|
|
|
@@ -918,13 +692,16 @@ ${e}
|
|
|
918
692
|
- moduleOrder: list module names in the order they should appear on the page`),(!s||s.includes("content"))&&o.push(`
|
|
919
693
|
|
|
920
694
|
## Content & Copywriting Guide
|
|
921
|
-
${
|
|
695
|
+
${gd()}`),n?.brandvoice&&o.push(`
|
|
922
696
|
|
|
923
697
|
## Brand Voice
|
|
924
|
-
${n.brandvoice}`),n?.
|
|
698
|
+
${n.brandvoice}`),n?.themeContext&&o.push(`
|
|
699
|
+
|
|
700
|
+
## Product Context
|
|
701
|
+
${n.themeContext}`),n?.humanify!==!1&&s?.includes("humanify")&&o.push(`
|
|
925
702
|
|
|
926
703
|
## Anti-AI Copy Rules
|
|
927
|
-
${
|
|
704
|
+
${hd()}`),o.join("")}function fd(){return`### Design Philosophy
|
|
928
705
|
You are a senior UI designer. Every page must look professionally designed, not like AI output.
|
|
929
706
|
Avoid "AI slop": purple gradients on white, cookie-cutter card grids, no personality.
|
|
930
707
|
|
|
@@ -1027,7 +804,7 @@ Include these in shared CSS:
|
|
|
1027
804
|
| All animations same speed | Stagger with increasing delays |
|
|
1028
805
|
| Skip hover/focus states | Every interactive element needs feedback |
|
|
1029
806
|
| Use \`<br>\` tags for spacing | Use proper margin/padding |
|
|
1030
|
-
| Put everything in a shadowed card | Vary: full-bleed, contained, floating |`}function
|
|
807
|
+
| Put everything in a shadowed card | Vary: full-bleed, contained, floating |`}function gd(){return`### Mandatory Page Sections (generate all)
|
|
1031
808
|
1. **Navigation Bar** \u2014 Logo, 4-5 nav links, CTA button, sticky on scroll
|
|
1032
809
|
2. **Hero** \u2014 Badge/pill, primary headline, subheadline, primary + secondary CTA, trust signals, visual element
|
|
1033
810
|
3. **Social Proof Bar** \u2014 Logo strip of 4-6 clients OR stats bar (compact, py-8)
|
|
@@ -1115,7 +892,7 @@ Alternate backgrounds every 2-3 sections to create visual "chapters." Sprinkle t
|
|
|
1115
892
|
- Invent plausible specifics: neighborhood names, "48 hours" not "quickly", "\u20AC49" not "affordable"
|
|
1116
893
|
- Keep paragraphs to 2-3 sentences max
|
|
1117
894
|
- Aim for 6th-grade reading level
|
|
1118
|
-
- Include section labels (UPPERCASE, letter-spacing 0.1em, accent color, 2-3 words) above every headline`}function
|
|
895
|
+
- Include section labels (UPPERCASE, letter-spacing 0.1em, accent color, 2-3 words) above every headline`}function hd(){return`### Banned Punctuation
|
|
1119
896
|
- **Em dashes (\u2014)**: NEVER use. Biggest AI tell. Replace with periods, commas, or parentheses.
|
|
1120
897
|
- **Semicolons**: Feel academic, not conversational. Use periods instead.
|
|
1121
898
|
- **Exclamation marks**: One per page maximum. Zero is ideal for B2B.
|
|
@@ -1145,28 +922,28 @@ seamless, cutting-edge, groundbreaking, game-changer, revolutionary, transformat
|
|
|
1145
922
|
- Use plain short words: use > utilize, start > commence, help > facilitate
|
|
1146
923
|
- Vary sentence length aggressively: mix 3-word, 12-word, and 25-word sentences
|
|
1147
924
|
- Front-load the benefit in the first 5 words
|
|
1148
|
-
- Write like you'd explain it in a bar \u2014 if you wouldn't say it holding a beer, rewrite it`}async function
|
|
925
|
+
- Write like you'd explain it in a bar \u2014 if you wouldn't say it holding a beer, rewrite it`}var kr,Tr,Er=J(()=>{"use strict";g();kr={type:"object",properties:{cssVariables:{type:"object",description:"CSS custom property name \u2192 value map. Every var() used in sharedCss must be defined here."},sharedCss:{type:"string",description:"Complete shared CSS file. MUST start with :root {} block defining all cssVariables, followed by reset, typography, layout, components, animations, and responsive styles."},sharedJs:{type:"string",description:"Optional shared JS for scroll animations (IntersectionObserver). Wrap in IIFE. Empty string if not needed."},aesthetic:{type:"string",description:"Brief description of the chosen aesthetic direction (e.g., 'dark luxury with warm gold accents')"}},required:["cssVariables","sharedCss","aesthetic"]};Tr={type:"object",properties:{modules:{type:"array",items:{type:"object",properties:{name:{type:"string",description:"Module name in title-case"},description:{type:"string",description:"What this module does"},contentBrief:{type:"string",description:"Specific content: headlines, body copy, stats, CTAs"},layoutNotes:{type:"string",description:"Visual layout approach referencing shared CSS classes"}},required:["name","description","contentBrief","layoutNotes"]}},moduleOrder:{type:"array",items:{type:"string"},description:"Module names in page display order"},narrative:{type:"string",description:"Brief description of the page story/flow"}},required:["modules","moduleOrder","narrative"]}});async function Nr(t,e,n,s,o,i,a){a({type:"agent_step",step:"designing",label:"Creating design system..."});let r=Ir(n.themeName,n.brandAssets),l=`## User Request
|
|
1149
926
|
${t}`;n.modules.length>0&&e.designSystemChanges&&(l+=`
|
|
1150
927
|
|
|
1151
928
|
## Current Shared CSS (update this)
|
|
1152
929
|
\`\`\`css
|
|
1153
930
|
${n.sharedCss}
|
|
1154
|
-
\`\`\``);let c=await
|
|
1155
|
-
${Object.entries(p).map(([
|
|
931
|
+
\`\`\``);let c=await Ne(s,o,i,{systemPrompt:r,messages:[{role:"user",content:l}],structuredOutput:{schema:kr,name:"design_system"},maxTokens:16e3}),d;c.type!=="structured"?(E.warn("page-architect","Design system: did not get structured output, using fallback"),d={cssVariables:{},sharedCss:n.sharedCss||"",sharedJs:n.sharedJs||"",aesthetic:"default"}):(d=c.data,E.info("page-architect","Design system created",{aesthetic:d.aesthetic,varCount:Object.keys(d.cssVariables||{}).length,cssLength:d.sharedCss?.length||0}));let u=d.sharedCss||"",p=d.cssVariables;p&&typeof p=="object"&&Object.keys(p).length>0&&(u.includes(":root")||(u=`:root {
|
|
932
|
+
${Object.entries(p).map(([N,L])=>` ${N.startsWith("--")?N:`--${N}`}: ${L};`).join(`
|
|
1156
933
|
`)}
|
|
1157
934
|
}
|
|
1158
935
|
|
|
1159
|
-
${u}`));let f=[],h=/\b(Montserrat|Inter|Poppins|Raleway|Playfair|Lato|Roboto|Open\s?Sans|Nunito|Merriweather|Oswald|Source\s?Sans|Fira\s?Sans|Work\s?Sans|Manrope|Plus\s?Jakarta)\b/gi,y=[...new Set((t.match(h)||[]).map(
|
|
1160
|
-
`)}),a({type:"design_system_ready",sharedCss:u,sharedJs:d.sharedJs||"",aesthetic:d.aesthetic||""}),a({type:"agent_step",step:"designing",label:"Planning modules..."});let A
|
|
1161
|
-
${t}`;e.newModules.length>0&&(
|
|
936
|
+
${u}`));let f=[],h=/\b(Montserrat|Inter|Poppins|Raleway|Playfair|Lato|Roboto|Open\s?Sans|Nunito|Merriweather|Oswald|Source\s?Sans|Fira\s?Sans|Work\s?Sans|Manrope|Plus\s?Jakarta)\b/gi,y=[...new Set((t.match(h)||[]).map(P=>P.trim()))];if(y.length>0){let P=y.filter(L=>u.toLowerCase().includes(L.toLowerCase())),N=y.filter(L=>!P.includes(L));N.length>0&&f.push(`Note: ${N.join(", ")} not available \u2014 HubSpot modules use system font stacks (no external font imports allowed)`)}let b=[`Design system: ${d.aesthetic||"created"} | ${Object.keys(p||{}).length} variables, ${u.length} chars CSS`,...f];a({type:"agent_decision",step:"designing",decision:b.join(`
|
|
937
|
+
`)}),a({type:"design_system_ready",sharedCss:u,sharedJs:d.sharedJs||"",aesthetic:d.aesthetic||""}),a({type:"agent_step",step:"designing",label:"Planning modules..."});let A=$r(n.themeName,u,n.brandAssets,e.guidesNeeded),w=`## User Request
|
|
938
|
+
${t}`;e.newModules.length>0&&(w+=`
|
|
1162
939
|
|
|
1163
940
|
## Planned Modules
|
|
1164
|
-
${e.newModules.map((
|
|
1165
|
-
`)}`),n.modules.length>0&&!e.designSystemChanges&&(
|
|
941
|
+
${e.newModules.map((P,N)=>`${N+1}. **${P.name}** \u2014 ${P.description}`).join(`
|
|
942
|
+
`)}`),n.modules.length>0&&!e.designSystemChanges&&(w+=`
|
|
1166
943
|
|
|
1167
944
|
## Existing Modules (keeping)
|
|
1168
|
-
${n.modules.map(
|
|
1169
|
-
`)}`);let $=await
|
|
945
|
+
${n.modules.map(P=>`- ${P.moduleName}`).join(`
|
|
946
|
+
`)}`);let $=await Ne(s,o,i,{systemPrompt:A,messages:[{role:"user",content:w}],structuredOutput:{schema:Tr,name:"module_plan"},maxTokens:8e3}),R;return $.type!=="structured"?(E.warn("page-architect","Module planner: did not get structured output, using fallback"),R={modules:e.newModules.map(P=>({name:P.name,description:P.description,contentBrief:"Generate appropriate content",layoutNotes:"Use responsive layout"})),moduleOrder:e.newModules.map(P=>P.name),narrative:"Page generated from user request"}):(R=$.data,E.info("page-architect","Module plan",{moduleCount:R.modules.length})),a({type:"agent_decision",step:"designing",decision:`Page: ${R.narrative} | ${R.modules.length} modules planned`}),{designSystem:{cssVariables:d.cssVariables||{},sharedCss:u,sharedJs:d.sharedJs},modules:R.modules,moduleOrder:R.moduleOrder,narrative:R.narrative}}var Mr=J(()=>{"use strict";g();it();Er();ve()});function Pr(t){let e=0,n=[];return async function(o){e>=t&&await new Promise(i=>n.push(i)),e++;try{return await o()}finally{e--,n.length>0&&n.shift()()}}}var _r=J(()=>{"use strict";g()});function Rr(t,e,n,s){let o=[];return o.push(`You are a Module Developer for vibeSpot, a HubSpot CMS page builder.
|
|
1170
947
|
|
|
1171
948
|
Your job: generate ONE HubSpot CMS module. You receive a module specification and must produce the complete module code.
|
|
1172
949
|
|
|
@@ -1218,13 +995,16 @@ ${e}
|
|
|
1218
995
|
\`\`\``),(!n||n.includes("hubspot_rules"))&&o.push(`
|
|
1219
996
|
|
|
1220
997
|
## HubSpot CMS Rules
|
|
1221
|
-
${
|
|
998
|
+
${Ze()}`),(!n||n.includes("conversion"))&&o.push(`
|
|
1222
999
|
|
|
1223
1000
|
## Conversion Guide
|
|
1224
|
-
${
|
|
1001
|
+
${le()}`),s?.themeContext&&o.push(`
|
|
1002
|
+
|
|
1003
|
+
## Product Context
|
|
1004
|
+
${s.themeContext}`),s?.humanify!==!1&&n?.includes("humanify")&&o.push(`
|
|
1225
1005
|
|
|
1226
1006
|
## Anti-AI Copy Rules
|
|
1227
|
-
${
|
|
1007
|
+
${yd()}`),o.join("")}function yd(){return`### Banned Punctuation
|
|
1228
1008
|
- **Em dashes (\u2014)**: NEVER use. Replace with periods, commas, or parentheses. Hyphens for compounds fine.
|
|
1229
1009
|
- **Semicolons**: Use periods instead in marketing copy.
|
|
1230
1010
|
- **Exclamation marks**: One per page max. Zero ideal for B2B.
|
|
@@ -1263,7 +1043,7 @@ Never end with: "The future of [X] is here", "Your journey starts here", "Join t
|
|
|
1263
1043
|
- Keep slightly imperfect (fragments OK, mild hedging like "honestly didn't think")
|
|
1264
1044
|
- Full names, specific roles (not "John D., CEO")
|
|
1265
1045
|
- Never start with "This product is..." \u2014 start with the person's situation
|
|
1266
|
-
- Vary length and voice across testimonials`}function
|
|
1046
|
+
- Vary length and voice across testimonials`}function Or(t,e,n){let s=[];return s.push(`## User Request
|
|
1267
1047
|
${t}`),s.push(`
|
|
1268
1048
|
|
|
1269
1049
|
## Module Specification
|
|
@@ -1290,25 +1070,299 @@ ${n.moduleCss}
|
|
|
1290
1070
|
**module.js:**
|
|
1291
1071
|
\`\`\`js
|
|
1292
1072
|
${n.moduleJs}
|
|
1293
|
-
\`\`\``)),s.join("")}var
|
|
1073
|
+
\`\`\``)),s.join("")}var jr,Fr=J(()=>{"use strict";g();Ve();jr={type:"object",properties:{moduleName:{type:"string"},fieldsJson:{type:"string",description:"Complete fields.json content as a JSON string"},metaJson:{type:"string",description:"Complete meta.json content as a JSON string"},moduleHtml:{type:"string",description:"Complete module.html HubL template content"},moduleCss:{type:"string",description:"Complete module.css vanilla CSS content"},moduleJs:{type:"string",description:"Optional module.js vanilla JS content, or empty string if not needed"}},required:["moduleName","fieldsJson","metaJson","moduleHtml","moduleCss"]}});async function Jr(t,e,n,s,o,i,a,r,l,c,d){l({type:"agent_step",step:"developing",label:`Generating ${e.length} module${e.length===1?"":"s"}...`});let u=Rr(s,n,c,d),p=Pr(r),f=e.length,h=e.map((b,A)=>p(async()=>{l({type:"module_progress",module:b.name,status:"generating",current:A+1,total:f});let w="";for(let $=0;$<2;$++)try{$>0&&(E.warn("module-developer",`${b.name}: retrying after failure (attempt ${$+1})`),l({type:"module_progress",module:b.name,status:"retrying",current:A+1,total:f}));let R=await Dr(t,b,u,o,i,a);return l({type:"module_progress",module:b.name,status:"complete",current:A+1,total:f,moduleFiles:R}),{moduleName:b.name,module:R}}catch(R){w=R instanceof Error?R.message:typeof R=="object"&&R!==null?JSON.stringify(R):String(R),E.error("module-developer",`Failed: ${b.name} (attempt ${$+1})`,{error:w})}return l({type:"module_progress",module:b.name,status:"failed",current:A+1,total:f}),{moduleName:b.name,error:w}}));return(await Promise.allSettled(h)).map(b=>b.status==="fulfilled"?b.value:{moduleName:"unknown",error:b.reason instanceof Error?b.reason.message:String(b.reason)})}async function Dr(t,e,n,s,o,i,a=0){let r=Or(t,e,e.existingCode),l=await Ne(s,o,i,{systemPrompt:n,messages:[{role:"user",content:r}],structuredOutput:{schema:jr,name:"module_output"},maxTokens:16e3});if(l.type!=="structured"){if(a<2)return E.warn("module-developer",`${e.name}: no structured output, retry ${a+1}`),Dr(t,e,n,s,o,i,a+1);throw new Error(`Module "${e.name}" failed to produce structured output after ${a+1} attempts`)}let c=l.data,d=typeof c.fieldsJson=="string"?c.fieldsJson:JSON.stringify(c.fieldsJson,null,2),u=typeof c.metaJson=="string"?c.metaJson:JSON.stringify(c.metaJson,null,2);return{moduleName:e.name,fieldsJson:d,metaJson:u,moduleHtml:String(c.moduleHtml||""),moduleCss:String(c.moduleCss||""),moduleJs:c.moduleJs?String(c.moduleJs):void 0}}var Lr=J(()=>{"use strict";g();it();_r();Fr();ve()});function Gr(t,e,n){return n({type:"agent_step",step:"quality_check",label:"Quality check..."}),t.map(s=>{let o=[],i={...s};i.fieldsJson=Hr(i.fieldsJson,i.moduleName,"fieldsJson",o),i.metaJson=Hr(i.metaJson,i.moduleName,"metaJson",o),i.fieldsJson=bd(i.fieldsJson,i.moduleName,o),i.fieldsJson=Sd(i.fieldsJson,i.moduleName,o),i.moduleCss=vd(i.moduleCss,i.moduleName,"moduleCss",o),wd(i.moduleCss,i.moduleName,e,o),i.moduleHtml=xd(i.moduleHtml,i.moduleName,o),i.metaJson=Cd(i.metaJson,i.moduleName,o);let a=o.every(r=>r.autoFixed);return o.length>0&&E.info("validator",`${i.moduleName}: ${o.length} issues`,{autoFixed:o.filter(r=>r.autoFixed).length,unfixed:o.filter(r=>!r.autoFixed).length}),{module:i,issues:o,valid:a}})}function Hr(t,e,n,s){return!t||t.trim()===""?(s.push({module:e,field:n,message:`Empty ${n}`,autoFixed:n==="metaJson"}),n==="metaJson"?JSON.stringify({host_template_types:["PAGE"],is_available_for_new_content:!0}):t):(Le(t)===null&&s.push({module:e,field:n,message:`Invalid JSON in ${n}`,autoFixed:!1}),t)}function bd(t,e,n){let s=t;return/"name"\s*:\s*"name"/g.test(s)&&(n.push({module:e,field:"fieldsJson",message:'"name" is a reserved field name \u2192 renamed to "item_name"',autoFixed:!0}),s=s.replace(/"name"\s*:\s*"name"/g,'"name": "item_name"')),/"name"\s*:\s*"label"/g.test(s)&&(n.push({module:e,field:"fieldsJson",message:'"label" is a reserved field name \u2192 renamed to "section_label"',autoFixed:!0}),s=s.replace(/"name"\s*:\s*"label"/g,'"name": "section_label"')),s}function Sd(t,e,n){let s=t;return/"type"\s*:\s*"textarea"/g.test(s)&&(n.push({module:e,field:"fieldsJson",message:'"textarea" is deprecated \u2192 changed to "text"',autoFixed:!0}),s=s.replace(/"type"\s*:\s*"textarea"/g,'"type": "text"')),s}function vd(t,e,n,s){if(!t)return t;let o=t,i=/@import\s+url\([^)]*(?:fonts\.googleapis|cdnjs|unpkg|jsdelivr)[^)]*\)\s*;?/gi;return i.test(o)&&(s.push({module:e,field:n,message:"CDN @import removed (external imports not allowed)",autoFixed:!0}),o=o.replace(i,"/* CDN import removed */")),o}function wd(t,e,n,s){if(!t)return;let o=/\.([a-zA-Z][\w-]*)/g,i,a=0;for(;(i=o.exec(t))!==null;){let r=i[1];r.startsWith(n+"-")||r==="visible"||r==="active"||r==="scroll-animate"||r.startsWith("body-wrapper")||r.startsWith("dnd-")||r.startsWith("row-")||a++}a>3&&s.push({module:e,field:"moduleCss",message:`${a} CSS classes without "${n}-" prefix`,autoFixed:!1})}function xd(t,e,n){if(!t)return t;let s=t,o=/\{%[-~]?\s*(if|for|block|macro|endif|endfor|endblock|endmacro)\b[^%]*%\}/g,i=[],a;for(;(a=o.exec(s))!==null;){let c=a[1],d=!c.startsWith("end"),u=d?c:c.replace("end","");i.push({tag:c,isOpen:d,baseTag:u,start:a.index,end:a.index+a[0].length})}let r=[],l=[];for(let c=0;c<i.length;c++)if(i[c].isOpen)r.push(c);else{let d=-1;for(let u=r.length-1;u>=0;u--)if(i[r[u]].baseTag===i[c].baseTag){d=u;break}d!==-1?r.splice(d,1):l.push(c)}if(l.length>0){for(let c=l.length-1;c>=0;c--){let d=i[l[c]];s=s.slice(0,d.start)+`<!-- removed orphan {% ${d.tag} %} -->`+s.slice(d.end)}n.push({module:e,field:"moduleHtml",message:`Removed ${l.length} orphan closing tag${l.length===1?"":"s"} with no matching opener`,autoFixed:!0})}if(r.length>0){let c=r.map(u=>i[u].baseTag),d=c.reverse().map(u=>`{% end${u} %}`).join(`
|
|
1294
1074
|
`);s=`${s}
|
|
1295
|
-
${d}`,n.push({module:e,field:"moduleHtml",message:`Added ${c.length} missing closing tag${c.length===1?"":"s"}: ${c.map(u=>`{% end${u} %}`).join(", ")}`,autoFixed:!0})}return/\bnow\(\)/.test(s)&&(s=s.replace(/\bnow\(\)/g,"local_dt"),n.push({module:e,field:"moduleHtml",message:"Replaced now() with local_dt (now() is not valid HubL)",autoFixed:!0})),s}function
|
|
1296
|
-
`);a({type:"agent_decision",step:"quality_check",decision:`${
|
|
1297
|
-
${
|
|
1075
|
+
${d}`,n.push({module:e,field:"moduleHtml",message:`Added ${c.length} missing closing tag${c.length===1?"":"s"}: ${c.map(u=>`{% end${u} %}`).join(", ")}`,autoFixed:!0})}return/\bnow\(\)/.test(s)&&(s=s.replace(/\bnow\(\)/g,"local_dt"),n.push({module:e,field:"moduleHtml",message:"Replaced now() with local_dt (now() is not valid HubL)",autoFixed:!0})),s}function Cd(t,e,n){let s=Le(t);if(!s||typeof s!="object")return t;let o=s,i=!1;return o.host_template_types||(o.host_template_types=["PAGE"],i=!0),o.is_available_for_new_content===void 0&&(o.is_available_for_new_content=!0,i=!0),i?(n.push({module:e,field:"metaJson",message:"Added missing meta.json required fields",autoFixed:!0}),JSON.stringify(o,null,2)):t}var Ur=J(()=>{"use strict";g();Xn();ve()});import{execSync as Ad}from"child_process";async function Wr(t,e,n,s,o,i,a,r){let l=Date.now(),c=i;if(sn(n)){let O={"claude-code":"claude","gemini-cli":"gemini","codex-cli":"codex"}[n];if(O)try{Ad(`command -v ${O}`,{stdio:"ignore"})}catch{throw new Error(`CLI engine "${n}" requires "${O}" to be installed and on your PATH.`)}}let d=await Cr(t,e,n,s,o,a,r);if(d.intent==="question"&&d.answer){let G=Date.now()-l;return a({type:"pipeline_complete",modulesGenerated:0,modulesUnchanged:e.modules.length,durationMs:G}),{modules:[...e.modules],moduleOrder:e.moduleOrder,sharedCss:e.sharedCss,sharedJs:e.sharedJs,assistantMessage:d.answer,stats:{modulesGenerated:0,modulesUnchanged:e.modules.length,modulesFailed:0,durationMs:G}}}let u=null,p=e.sharedCss,f=e.sharedJs;(d.intent==="create"||d.designSystemChanges)&&(u=await Nr(t,d,e,n,s,o,a),p=u.designSystem.sharedCss||p,f=u.designSystem.sharedJs||f,a({type:"blueprint_ready",moduleOrder:u.moduleOrder,sharedCss:p,sharedJs:f}));let y=[];if(u)for(let G of u.modules)y.push({name:G.name,description:G.description,contentBrief:G.contentBrief,layoutNotes:G.layoutNotes});else{for(let G of d.newModules)y.push({name:G.name,description:G.description,contentBrief:"Generate appropriate content based on the user request",layoutNotes:"Use responsive layout matching the existing design system"});for(let G of d.affectedModules){let O=e.modules.find(z=>z.moduleName===G);O&&y.push({name:G,description:`Modify existing module: ${G}`,contentBrief:"Apply the user's requested changes",layoutNotes:"Preserve existing layout unless changes are requested",existingCode:O})}}let b=[],A=[];if(y.length>0){let G=await Jr(t,y,p,e.themeName,n,s,o,c,a,d.guidesNeeded,e.brandAssets);for(let O of G)O.module?b.push(O.module):A.push(O.moduleName)}let w=null;if(b.length>0){w=Gr(b,e.themeName,a),b=w.map(O=>O.module);let G=w.reduce((O,z)=>O+z.issues.length,0);if(G>0){let O=w.reduce((ae,xo)=>ae+xo.issues.filter(Rt=>Rt.autoFixed).length,0);E.info("pipeline",`Quality check: ${G} issues, ${O} auto-fixed`);let z=w.flatMap(ae=>ae.issues).map(ae=>`${ae.autoFixed?"\u2713":"\u26A0"} ${ae.module}: ${ae.message}`).join(`
|
|
1076
|
+
`);a({type:"agent_decision",step:"quality_check",decision:`${G} issues found, ${O} auto-fixed
|
|
1077
|
+
${z}`})}else a({type:"agent_decision",step:"quality_check",decision:"All modules passed quality checks"})}let $=Id(e,d,b,u,r),R=kd(e,d,u,$);if(u?.moduleOrder?.length){let G=new Set(u.moduleOrder),O=$.filter(z=>!G.has(z.moduleName)).map(z=>z.moduleName);O.length>0&&a({type:"agent_decision",step:"quality_check",decision:`\u26A0 ${O.length} module${O.length===1?"":"s"} missing from page order \u2014 auto-inserted: ${O.join(", ")}`})}let P=Date.now()-l,N=b.length,L=d.unchangedModules.length,ne=w?w.flatMap(G=>G.issues):[],U=$d(d,N,L,A,P,u,ne);return A.length>0?a({type:"pipeline_partial",succeeded:b.map(G=>G.moduleName),failed:A,durationMs:P}):a({type:"pipeline_complete",modulesGenerated:N,modulesUnchanged:L,durationMs:P}),{modules:$,moduleOrder:R,sharedCss:p,sharedJs:f,assistantMessage:U,stats:{modulesGenerated:N,modulesUnchanged:L,modulesFailed:A.length,durationMs:P}}}function Id(t,e,n,s,o){let i=[],a=new Set;for(let r of n)i.push(r),a.add(r.moduleName);for(let r of e.unchangedModules){if(a.has(r))continue;let l=t.modules.find(c=>c.moduleName===r);l&&(i.push(l),a.add(r))}if(e.reuseModules)for(let r of e.reuseModules){if(a.has(r.name))continue;let l=o.find(c=>c.name===r.name&&c.module);l&&l.module&&(i.push(l.module),a.add(r.name))}return i}function kd(t,e,n,s){if(n?.moduleOrder?.length){let r=[...n.moduleOrder],l=new Set(r);for(let c of s)if(!l.has(c.moduleName)){let d=r.findIndex(u=>u.toLowerCase().includes("footer"));d!==-1?r.splice(d,0,c.moduleName):r.push(c.moduleName),l.add(c.moduleName),E.warn("pipeline",`Module "${c.moduleName}" missing from blueprint order \u2014 inserted`)}return r}if(e.intent==="create")return s.map(r=>r.moduleName);let o=[...t.moduleOrder],i=[...e.newModules.map(r=>({name:r.name,position:r.position})),...(e.reuseModules||[]).map(r=>({name:r.name,position:r.position}))].sort((r,l)=>r.position-l.position);for(let r of i){let l=Math.min(r.position,o.length);o.splice(l,0,r.name)}let a=new Set(s.map(r=>r.moduleName));return o.filter(r=>a.has(r))}function $d(t,e,n,s,o,i,a){let r=Math.round(o/1e3),l=[];if(t.intent==="create")l.push(`Created ${e} module${e===1?"":"s"} in ${r}s.`);else if(t.intent==="modify"||t.intent==="style_change")l.push(`Updated ${e} module${e===1?"":"s"} in ${r}s.`),n>0&&l.push(`${n} module${n===1?"":"s"} unchanged.`);else if(t.intent==="add"){let u=t.newModules.map(p=>p.name).join(", ");l.push(`Added ${u} in ${r}s.`)}else t.intent==="remove"?l.push(`Removed modules in ${r}s.`):t.intent==="rearrange"&&l.push(`Rearranged modules in ${r}s.`);i?.narrative&&l.push(`
|
|
1298
1078
|
|
|
1299
1079
|
${i.narrative}`),s.length>0&&l.push(`
|
|
1300
1080
|
|
|
1301
1081
|
**Failed:** ${s.join(", ")}. You can retry these individually.`);let c=a.filter(u=>!u.autoFixed),d=a.filter(u=>u.autoFixed);if(d.length>0||c.length>0){let u=[];d.length>0&&u.push(`**Auto-fixed:** ${d.map(p=>`${p.module}: ${p.message}`).join(", ")}`),c.length>0&&u.push(`**Warnings:** ${c.map(p=>`${p.module}: ${p.message}`).join(", ")}`),l.push(`
|
|
1302
1082
|
|
|
1303
1083
|
${u.join(`
|
|
1304
|
-
`)}`)}return l.join("")}var
|
|
1084
|
+
`)}`)}return l.join("")}var Br=J(()=>{"use strict";g();it();Ar();Mr();Lr();Ur();ve();it()});var Kr={};lt(Kr,{applyPipelineResult:()=>mo,handleAgenticGenerate:()=>uo,handleGenerate:()=>Td,handleGenerateStream:()=>on,isGenerating:()=>Mt,resolveAgenticEngine:()=>ts,setParseWarningCallback:()=>lo,shouldUseAgenticMode:()=>po});import{execSync as ro}from"child_process";function lo(t){ao=t}function Mt(){return gt!==null}function Nt(t){if(gt){let e=v();if(!e||e.id!==gt){E.warn("ai-handler","Session changed during generation \u2014 discarding AI output");return}}tt("assistant",t),ar(t,ao||void 0),D()}async function on(t,e,n,s){let o=v();if(!o)throw new Error("No active session");gt=o.id;let a=s?.length?yr(s):void 0;try{let r=M(),l=r.aiEngine||co();switch(l){case"anthropic-api":case"api":{let c=ge("anthropic-api",r);if(!c)throw new Error("Anthropic API key not configured. Open Settings to add one.");await dr(t,c,o.themeName,r.anthropicApiModel||"claude-sonnet-4-6",e,n,Nt,a);break}case"openai-api":{let c=ge("openai-api",r);if(!c)throw new Error("OpenAI API key not configured. Open Settings to add one.");await ur(t,c,o.themeName,r.openaiApiModel||"gpt-4o",e,n,Nt,a);break}case"gemini-api":{let c=ge("gemini-api",r);if(!c)throw new Error("Gemini API key not configured. Open Settings to add one.");await mr(t,c,o.themeName,e,n,Nt,a);break}case"claude-code":await pr(t,o.themeName,e,n,Nt,a);break;case"gemini-cli":await Xs("gemini",t,o.themeName,e,n,Nt,a);break;case"codex-cli":await Xs("codex",t,o.themeName,e,n,Nt,a);break;default:throw new Error(`Unknown AI engine: ${l}. Open Settings to configure one.`)}}finally{gt=null,ao=null}}function co(){let t=M();if(t.anthropicApiKey||process.env.ANTHROPIC_API_KEY)return"anthropic-api";if(t.openaiApiKey||process.env.OPENAI_API_KEY)return"openai-api";if(t.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY)return"gemini-api";try{return ro("claude --version",{stdio:"pipe"}),"claude-code"}catch{}try{return ro("gemini --version",{stdio:"pipe"}),"gemini-cli"}catch{}try{return ro("codex --version",{stdio:"pipe"}),"codex-cli"}catch{}throw new Error("No AI engine available. Open Settings to configure one.")}async function Td(t){let e="";return await on(t,n=>{e+=n}),e}function Ed(){let t=v(),e=Ce(),n=e?[...e.modules]:[...t.modules],s=e?[...e.moduleOrder]:[...t.moduleOrder];return{modules:n,moduleOrder:s,sharedCss:e?.sharedCss||t.sharedCss,sharedJs:e?.sharedJs||t.sharedJs,messages:[...t.messages],themeName:t.themeName,themePath:t.themePath,brandAssets:t.brandAssets?{...t.brandAssets}:void 0}}function ts(t){let e=t.aiEngine||co();if(!es(e))throw new Error("Agentic pipeline is not available for this engine.");if(sn(e)){let o="";return e==="claude-code"&&(o=t.claudeCodeModel||""),{engine:e,apiKey:"",model:o}}let n=ge(e,t);if(!n)throw new Error(`API key not configured for ${e}. Open Settings to add one.`);let s;switch(e){case"anthropic-api":s=t.anthropicApiModel||"claude-sonnet-4-6";break;case"openai-api":s=t.openaiApiModel||"gpt-4o";break;case"gemini-api":s="gemini-2.5-flash";break;default:s=""}return{engine:e,apiKey:n,model:s}}async function uo(t,e,n){let s=v();if(!s)throw new Error("No active session");let o=s.id;gt=o;try{let i=M(),{engine:a,apiKey:r,model:l}=ts(i),c=i.agenticConcurrency||20,d=Ed(),u=nt(),p=new Set(d.modules.map(b=>b.moduleName)),f=u.filter(b=>!p.has(b.module.moduleName)).map(b=>({name:b.module.moduleName,usedIn:b.usedIn})),h=await Wr(t,d,a,r,l,c,e,f),y=v();if(!y||y.id!==o)throw E.warn("ai-handler","Session changed during agentic generation \u2014 discarding output"),new Error("Session changed during generation");return h}finally{gt=null}}function mo(t,e){De({modules:t.modules,sharedCss:t.sharedCss,sharedJs:t.sharedJs}),At(t.moduleOrder),tt("assistant",t.assistantMessage,e),D()}function po(){let t=M(),e=t.aiEngine||co();return es(e)?t.agenticMode===void 0?{useAgentic:!1,needsPrompt:!0}:{useAgentic:t.agenticMode,needsPrompt:!1}:{useAgentic:!1,needsPrompt:!1,reason:"Agentic pipeline is not available for this engine."}}var ao,gt,ns=J(()=>{"use strict";g();ee();Se();Xn();ve();Qs();no();Br();ao=null;gt=null});var ds={};lt(ds,{collectThemeFiles:()=>ka,extractDesignContext:()=>Xd});import{existsSync as as,readdirSync as ls,readFileSync as Kd}from"fs";import{join as He}from"path";import{spawn as Vd}from"child_process";async function Yd(){return go||(go=(await import("@anthropic-ai/sdk")).default),go}function ln(t){try{return Kd(t,"utf-8")}catch{return""}}function ka(t){let e=[],n=0;function s(r,l){if(!l.trim())return!0;let c=`
|
|
1085
|
+
### ${r}
|
|
1086
|
+
\`\`\`
|
|
1087
|
+
${l}
|
|
1088
|
+
\`\`\`
|
|
1089
|
+
`;return n+c.length>zd?!1:(e.push(c),n+=c.length,!0)}let o=ln(He(t,"theme.json"));o&&s("theme.json",o);let i=He(t,"css");if(as(i)){for(let r of ls(i).filter(l=>l.endsWith(".css")))if(!s(`css/${r}`,ln(He(i,r))))break}let a=He(t,"modules");if(as(a))for(let r of ls(a).filter(l=>l.endsWith(".module"))){let l=He(a,r),c=ln(He(l,"module.css"));if(c&&!s(`modules/${r}/module.css`,c))break}if(as(a))for(let r of ls(a).filter(l=>l.endsWith(".module"))){let l=He(a,r),c=ln(He(l,"module.html"));if(c&&!s(`modules/${r}/module.html`,c))break}if(as(a))for(let r of ls(a).filter(l=>l.endsWith(".module"))){let l=He(a,r),c=ln(He(l,"fields.json"));if(c&&!s(`modules/${r}/fields.json`,c))break}return e.join("")}function qd(){if(!cs)try{cs=I(mn("extraction-prompt.md"))}catch{cs=""}return cs}function ho(t,e,n){return new Promise((s,o)=>{let i={...process.env};delete i.CLAUDECODE;let a=Vd(t,e,{stdio:["pipe","pipe","pipe"],env:i,shell:!0}),r="",l="";a.stdout.on("data",c=>{r+=c.toString()}),a.stderr.on("data",c=>{l+=c.toString()}),a.on("error",c=>o(new Error(`${t} failed to start: ${c.message}`))),a.on("close",c=>{c===0||r.trim()?s(r.trim()):o(new Error(`${t} exited with code ${c}: ${l.trim()}`))}),a.stdin.write(n),a.stdin.end()})}async function Xd(t,e){e?.({status:"Collecting theme files..."});let n=ka(t);if(!n.trim())throw new Error("No CSS, HTML, or fields.json files found in theme.");let s=qd();if(!s)throw new Error("Extraction prompt not found (assets/extraction-prompt.md).");let o=`Analyze this HubSpot CMS theme and extract the design system:
|
|
1090
|
+
${n}`;e?.({status:"Analyzing design patterns..."});let i=M(),a=i.aiEngine||"anthropic-api",r="";switch(a){case"anthropic-api":case"api":{let l=ge("anthropic-api");if(!l)throw new Error("Anthropic API key not configured. Open Settings to add one.");let c=await Yd();r=(await new c({apiKey:l}).messages.create({model:i.anthropicApiModel||"claude-sonnet-4-6",max_tokens:8e3,system:s,messages:[{role:"user",content:o}]})).content.filter(p=>p.type==="text").map(p=>p.text).join("");break}case"openai-api":{let l=ge("openai-api");if(!l)throw new Error("OpenAI API key not configured. Open Settings to add one.");let c=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${l}`},body:JSON.stringify({model:i.openaiApiModel||"gpt-4o",max_tokens:8e3,messages:[{role:"system",content:s},{role:"user",content:o}]})});if(!c.ok)throw new Error(`OpenAI API error: ${c.status} ${await c.text()}`);r=(await c.json()).choices?.[0]?.message?.content||"";break}case"gemini-api":{let l=ge("gemini-api");if(!l)throw new Error("Gemini API key not configured. Open Settings to add one.");let c=i.geminiApiModel||"gemini-2.5-flash",d=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${c}:generateContent?key=${l}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({system_instruction:{parts:[{text:s}]},contents:[{role:"user",parts:[{text:o}]}],generationConfig:{maxOutputTokens:8e3}})});if(!d.ok)throw new Error(`Gemini API error: ${d.status} ${await d.text()}`);r=(await d.json()).candidates?.[0]?.content?.parts?.map(p=>p.text).join("")||"";break}case"claude-code":{let l=`${s}
|
|
1091
|
+
|
|
1092
|
+
## User Request
|
|
1093
|
+
${o}`,c=["--print"];i.claudeCodeModel&&c.push("--model",i.claudeCodeModel),r=await ho("claude",c,l);break}case"gemini-cli":{let l=`${s}
|
|
1094
|
+
|
|
1095
|
+
## User Request
|
|
1096
|
+
${o}`;r=await ho("gemini",[],l);break}case"codex-cli":{let l=`${s}
|
|
1097
|
+
|
|
1098
|
+
## User Request
|
|
1099
|
+
${o}`;r=await ho("codex",[],l);break}default:throw new Error(`Unknown AI engine: ${a}. Open Settings to configure one.`)}if(!r.trim())throw new Error("AI returned empty response.");return e?.({status:"Design extraction complete."}),r}var go,zd,cs,us=J(()=>{"use strict";g();Z();ee();go=null;zd=8e4;cs=""});var $a={};lt($a,{extractBrandvoice:()=>Qd});async function Qd(t,e,n,s){if(!t||t.length<50)return null;let o=`You are a brand strategist. Analyze the rendered landing page HTML below and extract a concise brand voice guide. The HTML contains the actual text content with all template variables resolved to their default values.
|
|
1100
|
+
|
|
1101
|
+
Return a markdown document with these sections (skip any section where the content provides no signal):
|
|
1102
|
+
|
|
1103
|
+
## Tone
|
|
1104
|
+
Overall communication style (e.g., confident but approachable, technical but clear, playful, authoritative).
|
|
1105
|
+
|
|
1106
|
+
## Voice Characteristics
|
|
1107
|
+
3-5 bullet points describing how this brand "sounds" (e.g., "Uses short, punchy sentences", "Addresses reader directly with 'you'").
|
|
1108
|
+
|
|
1109
|
+
## Vocabulary
|
|
1110
|
+
- **Preferred words**: Terms used repeatedly or intentionally
|
|
1111
|
+
- **Avoided patterns**: Any notable absences or anti-patterns
|
|
1112
|
+
|
|
1113
|
+
## Sentence Style
|
|
1114
|
+
Typical sentence length, structure, use of questions, imperatives, etc.
|
|
1115
|
+
|
|
1116
|
+
## Dos and Don'ts
|
|
1117
|
+
3-4 practical rules for writing in this voice (e.g., "Do: Lead with benefits, not features", "Don't: Use jargon without context").
|
|
1118
|
+
|
|
1119
|
+
Keep it actionable \u2014 this guide will be fed to AI to maintain consistent copy across pages.`;try{let i=await Ne(e,n,s,{systemPrompt:o,messages:[{role:"user",content:t}],maxTokens:1e3}),a=i.type==="text"?i.text:JSON.stringify(i.data);return!a||a.trim().length<20?null:(E.info("brandvoice-extractor",`Extracted brand voice (${a.length} chars)`),a.trim())}catch(i){let a=i instanceof Error?i.message:String(i);return E.warn("brandvoice-extractor",`Brand voice extraction failed: ${a}`),null}}var Ta=J(()=>{"use strict";g();it();ve()});var yo={};lt(yo,{extractThemeContext:()=>Zd});async function Zd(t,e,n,s,o){if(!t||t.length<50)return null;let a=`You are a content analyst. Extract a concise product/company brief from the rendered landing page HTML below. The HTML contains the actual text content (headings, paragraphs, button labels, image alt text, etc.) with all template variables resolved to their default values.
|
|
1120
|
+
|
|
1121
|
+
Return a markdown document with these sections (skip any section where the content provides no information):
|
|
1122
|
+
|
|
1123
|
+
## Product / Company
|
|
1124
|
+
Name, one-line description, and what it does.
|
|
1125
|
+
|
|
1126
|
+
## Value Propositions
|
|
1127
|
+
Key benefits or features (bulleted list).
|
|
1128
|
+
|
|
1129
|
+
## Target Audience
|
|
1130
|
+
Who this product/service is for.
|
|
1131
|
+
|
|
1132
|
+
## Tone & Voice
|
|
1133
|
+
Communication style (e.g., professional, casual, technical, friendly).
|
|
1134
|
+
|
|
1135
|
+
## Key Terminology
|
|
1136
|
+
Specific terms, product names, or branded language used consistently.
|
|
1137
|
+
|
|
1138
|
+
Keep it concise \u2014 this brief is used as context for AI-generated content on other pages in the same theme.${e?`
|
|
1139
|
+
|
|
1140
|
+
Existing product context (update if the new content adds info, keep what's still accurate):
|
|
1141
|
+
${e}`:""}`;try{let r=await Ne(n,s,o,{systemPrompt:a,messages:[{role:"user",content:t}],maxTokens:1e3}),l=r.type==="text"?r.text:JSON.stringify(r.data);return!l||l.trim().length<20?null:(E.info("context-extractor",`Extracted theme context (${l.length} chars)`),l.trim())}catch(r){let l=r instanceof Error?r.message:String(r);return E.warn("context-extractor",`Theme context extraction failed: ${l}`),null}}var bo=J(()=>{"use strict";g();it();ve()});g();g();import{Command as hu}from"commander";g();g();g();import yt from"chalk";var Pe={accent:"#FF7A59",accentBright:"#FF9A7A",success:"#00BDA5",info:"#0066FF",warn:"#FFB020",error:"#E23D2D",muted:"#8B8D91",vibes:"#00BDD6"},Co=!!process.env.NO_COLOR;function Ue(t){return Co?yt:yt.hex(t)}var k={accent:Ue(Pe.accent),accentBright:Ue(Pe.accentBright),success:Ue(Pe.success),info:Ue(Pe.info),warn:Ue(Pe.warn),error:Ue(Pe.error),muted:Ue(Pe.muted),vibes:Ue(Pe.vibes),heading:Co?yt.bold:yt.bold.hex(Pe.accent),command:Ue(Pe.accentBright),dim:yt.dim,bold:yt.bold};Z();function _e(){let t=k.vibes,e=k.accent,n=k.muted,s=[`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584\u2584")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2584\u2584\u2584\u2584\u2584 \u2588\u2588\u2588\u2588\u2588 \u2584\u2584\u2584\u2584 \u2580\u2580\u2588\u2588\u2580\u2580")}`,`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t("\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B ")}${e("\u2580\u2580\u2580\u2584 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t(" \u2588\u2584\u2584\u2588\u2580 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B ")}${e(" \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ")}`,`${t(" \u2580\u2580\u2580 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2580\u2580\u2580\u2580\u2580")}${t(" \u224B\u224B\u224B\u224B\u224B\u224B\u224B\u224B ")}${e("\u2580\u2580\u2580\u2580 \u2588\u2588 \u2580\u2580\u2580\u2580 \u2588\u2588 ")}`];console.log();for(let o of s)console.log(` ${o}`);console.log(),console.log(` ${n("AI-powered HubSpot Landing Pages")} ${k.dim(`v${St()}`)}`),console.log()}g();g();ct();ee();import{join as gn}from"path";import{homedir as hn}from"os";import{readFileSync as Mo,existsSync as yn,readdirSync as cl}from"fs";var dt=process.platform==="win32"?"where":"which";function Ft(){let t=T("node --version");return{name:"Node.js",found:t.success,version:t.stdout.replace(/^v/,""),path:T(`${dt} node`).stdout}}function Jt(){let t=T("git --version");return{name:"Git",found:t.success,version:t.stdout.replace("git version ",""),path:T(`${dt} git`).stdout}}function Re(){let t=T("hs --version");return{name:"HubSpot CLI",found:t.success,version:t.stdout,path:T(`${dt} hs`).stdout}}function Dt(){let t=T("claude --version");if(!t.success)return{name:"Claude Code",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=gn(hn(),".claude"),n=!1,s="Not signed in \u2014 run `claude` to authenticate";try{if(yn(e)){let o=cl(e);(o.some(a=>a.includes("credentials")||a.includes("auth")||a.includes("token")||a===".credentials.json")||o.length>2)&&(n=!0,s="Authenticated")}}catch{}return{name:"Claude Code",found:!0,version:t.stdout,path:T(`${dt} claude`).stdout,authenticated:n,authDetail:s}}function Lt(t){try{let e=gn(hn(),".hscli","config.yml");if(!yn(e))return"na1";let n=Mo(e,"utf-8"),s=n.indexOf(`accountId: ${t}`);if(s===-1)return"na1";let o=n.indexOf("personalAccessKey:",s);if(o===-1)return"na1";let a=n.slice(o,o+300).match(/personalAccessKey:[\s>-]*\n\s+(\S+)/);if(!a)return"na1";if(a[1].startsWith("CiRldTE"))return"eu1"}catch{}return"na1"}function Oe(){let t=T("hs accounts list");if(!t.success||!t.stdout)return{authenticated:!1,portalName:"",portalId:"",accounts:[]};let e=[],n="",s="",o=t.stdout.match(/Account:\s*(.+?)\s*\((\d+)\)/);o&&(n=o[1].trim(),s=o[2].trim());let i=t.stdout.split(`
|
|
1142
|
+
`);for(let a of i){let r=a.match(/^\s*(.+?)\s+(\d{5,})\s+(.*)/);if(r&&!/Account ID/i.test(a)&&!/^-+$/.test(a.trim())&&!/^Name\s/i.test(a.trim())){let l=r[1].trim(),c=r[2].trim(),d=r[3]?.trim()||"unknown";e.push({name:l,portalId:c,authType:d,isDefault:c===s})}}return o?{authenticated:!0,portalName:n,portalId:s,accounts:e}:e.length>0?{authenticated:!0,portalName:e[0].name,portalId:e[0].portalId,accounts:e}:{authenticated:t.stdout.length>0,portalName:"",portalId:"",accounts:[]}}function Ht(){let t=T("gemini --version");if(!t.success)return{name:"Gemini CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=gn(hn(),".config","gcloud","application_default_credentials.json"),n=yn(e),s=!!(process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||process.env.GOOGLE_AI_API_KEY),o=n||s;return{name:"Gemini CLI",found:!0,version:t.stdout,path:T(`${dt} gemini`).stdout,authenticated:o,authDetail:o?"Authenticated":"Run `gemini` to sign in with Google"}}function Gt(){let t=T("codex --version");if(!t.success)return{name:"OpenAI Codex CLI",found:!1,version:"",path:"",authenticated:!1,authDetail:"Not installed"};let e=!!process.env.OPENAI_API_KEY,n=!1;try{let i=gn(hn(),".codex","auth.json");yn(i)&&(n=Mo(i,"utf-8").length>10)}catch{}let s=e||n,o=n?"Authenticated (OAuth)":e?"Authenticated (API key)":"Not authenticated";return{name:"OpenAI Codex CLI",found:!0,version:t.stdout,path:T(`${dt} codex`).stdout,authenticated:s,authDetail:o}}function vs(){let t=T("gh --version");return{name:"GitHub CLI",found:t.success,version:t.stdout.split(`
|
|
1143
|
+
`)[0]?.replace("gh version ","").split(" ")[0]||"",path:T(`${dt} gh`).stdout}}function ws(){let t=T("gh auth status 2>&1");if(!t.success&&!t.stdout)return{authenticated:!1,username:""};let e=t.stdout||t.stderr||"",n=e.match(/Logged in to github\.com.*account\s+(\S+)/);if(n)return{authenticated:!0,username:n[1]};let s=e.match(/account\s+(\S+)/);return s&&e.includes("Logged in")?{authenticated:!0,username:s[1]}:{authenticated:e.includes("Logged in"),username:""}}function Po(){return!!process.env.ANTHROPIC_API_KEY}function bn(t){return parseInt(t.split(".")[0],10)>=18}function _o(t){let e=parseInt(t.split(".")[0],10);return!isNaN(e)&&e>=8}function dl(){let t=M(),e=t.hubspotUploadMode||"api",n=t.hubspotAccounts||[],s=n.map(i=>({name:i.portalName,portalId:i.portalId,authType:"personalaccesskey",isDefault:i.portalId===(t.activeHubSpotAccount||n[0]?.portalId)})),o=Xe();return{authenticated:!!o,portalName:o?.portalName||"",portalId:o?.portalId||"",dataCenter:o?o.dataCenter:"na1",accounts:s,uploadMode:e}}var Ss={name:"",found:!1,version:"",path:"",authenticated:!1,authDetail:"Disabled"};function Sn(){let t=M(),e=Ft(),n=Jt(),s=t.hubspotUploadMode||"api",o;if(s==="cli"){let b=Re(),A=b.found?Oe():{authenticated:!1,portalName:"",portalId:"",accounts:[]},w=A.portalId?Lt(A.portalId):"na1";o={...b,...A,dataCenter:w,uploadMode:"cli"}}else o={name:"HubSpot API",found:!0,version:"v3",path:"",...dl()};let i=vs(),a=i.found?ws():{authenticated:!1,username:""},r=t.enabledCLITools||[],l=jt("claude-code")?Dt():{...Ss,name:"Claude Code"},c=jt("gemini-cli")?Ht():{...Ss,name:"Gemini CLI"},d=jt("codex-cli")?Gt():{...Ss,name:"OpenAI Codex CLI"};function u(b,...A){if(b)return{configured:!0,masked:fn(b),source:"config"};for(let w of A)if(process.env[w])return{configured:!0,masked:fn(process.env[w]),source:"env"};return{configured:!1,masked:"",source:null}}let p=u(t.anthropicApiKey,"ANTHROPIC_API_KEY"),f=u(t.openaiApiKey,"OPENAI_API_KEY"),h=u(t.geminiApiKey,"GEMINI_API_KEY","GOOGLE_AI_API_KEY"),y=[];return l.found&&l.authenticated&&y.push("claude-code"),p.configured&&y.push("anthropic-api"),f.configured&&y.push("openai-api"),c.found&&c.authenticated&&y.push("gemini-cli"),h.configured&&y.push("gemini-api"),d.found&&d.authenticated&&y.push("codex-cli"),{tools:{node:e,git:n,hubspot:o,github:{...i,...a},claudeCode:l,geminiCli:c,codexCli:d},apiKeys:{anthropic:p,openai:f,gemini:h},activeEngine:t.aiEngine||null,availableEngines:y,enabledCLITools:r}}ct();ee();ut();g();import*as K from"@clack/prompts";function Cs(t){K.isCancel(t)&&(K.cancel(k.muted("Operation cancelled.")),process.exit(0))}async function ce(t){K.intro(k.heading(t))}async function de(t){K.outro(k.success(t))}async function je(t,e){K.note(t,e?k.heading(e):void 0)}async function $e(t){let e=await K.text({message:k.accent(t.message),placeholder:t.placeholder,defaultValue:t.defaultValue,validate:t.validate});return Cs(e),e}async function se(t){let e=await K.confirm({message:k.accent(t.message),initialValue:t.initialValue??!0});return Cs(e),e}async function wt(t){let e=await K.select({message:k.accent(t.message),options:t.options});return Cs(e),e}async function ue(){let t=K.spinner();return{start:e=>t.start(k.muted(e)),stop:e=>t.stop(k.success(e)),message:e=>t.message(k.muted(e))}}function X(t){K.log.info(t)}function F(t){K.log.success(k.success(t))}function V(t){K.log.warn(k.warn(t))}function W(t){K.log.error(k.error(t))}async function Cn(){await ce("Checking your environment");let t=Ft();t.found||(W("Node.js not found. Install it from https://nodejs.org"),process.exit(1)),bn(t.version)||(W(`Node.js ${t.version} is too old. Version 18+ required. Update at https://nodejs.org`),process.exit(1)),F(`Node.js v${t.version}`);let e=Jt();e.found||(W("Git not found. Install it from https://git-scm.com"),process.exit(1)),F(`Git ${e.version}`);let n=M(),s=n.hubspotUploadMode!=="cli",o="",i="";if(s){let y=he(),b=Xe();if(y)o=b?.portalId||"",i=b?.portalName||"",F(`HubSpot${i?`: ${i}`:""}${o?` (${o})`:""} \u2014 API mode`);else{V("No HubSpot account connected"),await je(`You need a Personal Access Key to deploy themes.
|
|
1144
|
+
Create one at: https://app.hubspot.com/l/personal-access-key
|
|
1145
|
+
Make sure the Content scope is enabled.`,"HubSpot connection required");let A=await $e({message:"Paste your Personal Access Key:",placeholder:"pat-na1-...",validate:$=>$.trim()?void 0:"Key is required"}),w=await ue();w.start("Validating key...");try{let $=await wn(A);Ot(A,$.portalId,$.portalName,$.dataCenter),y=A,o=$.portalId,i=$.portalName,w.stop(`Connected to ${$.portalName} (${$.portalId})`)}catch($){w.stop("Validation failed"),W(`Invalid key: ${$ instanceof Error?$.message:String($)}`),process.exit(1)}}}else{let y=Re();if(y.found)F(`HubSpot CLI v${y.version}`);else{V("HubSpot CLI not found"),await se({message:"Install HubSpot CLI globally?"})||(W("HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli"),process.exit(1));let w=await ue();w.start("Installing HubSpot CLI..."),T("npm install -g @hubspot/cli").success||(w.stop("Failed"),W("Try: npm install -g @hubspot/cli"),process.exit(1)),y=Re(),w.stop(`HubSpot CLI v${y.version} installed`)}let b=Oe();if(b.authenticated)F(`HubSpot portal${b.portalName?`: ${b.portalName}`:""} (ID: ${b.portalId})`);else{V("HubSpot not authenticated"),await se({message:"Run `hs init` now?"})||(W("Run `hs init` manually."),process.exit(1));let w=await ue();w.start("Waiting for HubSpot authentication..."),$o("hs init")||(w.stop("Authentication failed"),process.exit(1)),b=Oe(),w.stop(`Connected to portal${b.portalName?`: ${b.portalName}`:""} (ID: ${b.portalId})`)}o=b.portalId,i=b.portalName}let a=Dt(),r=Ht(),l=Gt(),c=Po(),d={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"},u,p=n.aiEngine,f=[];if(a.found&&f.push({value:"claude-code",label:"Claude Code",hint:p==="claude-code"?"last used \u2014 recommended":"uses your existing Claude subscription \u2014 recommended"}),r.found&&f.push({value:"gemini-cli",label:"Gemini CLI",hint:p==="gemini-cli"?"last used":"uses your existing Gemini setup"}),l.found&&f.push({value:"codex-cli",label:"OpenAI Codex",hint:p==="codex-cli"?"last used":"uses your existing OpenAI setup"}),c&&f.push({value:"api",label:"Anthropic API",hint:p==="api"?"last used":"uses your API key"}),p&&f.sort((y,b)=>y.value===p?-1:b.value===p?1:0),f.length===1)u=f[0].value,F(`AI engine: ${d[u]} (auto-detected)`);else if(f.length>1)u=await wt({message:"Choose your AI engine:",options:f});else if(await je(`You need an AI coding assistant to power the conversion.
|
|
1146
|
+
|
|
1147
|
+
${k.bold("Option 1:")} Install Claude Code ${k.muted("(recommended)")}
|
|
1148
|
+
https://claude.ai/code
|
|
1149
|
+
|
|
1150
|
+
${k.bold("Option 2:")} Install Gemini CLI
|
|
1151
|
+
https://github.com/google-gemini/gemini-cli
|
|
1152
|
+
|
|
1153
|
+
${k.bold("Option 3:")} Install OpenAI Codex
|
|
1154
|
+
https://github.com/openai/codex
|
|
1155
|
+
|
|
1156
|
+
${k.bold("Option 4:")} Set an Anthropic API key
|
|
1157
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
1158
|
+
(get one at https://console.anthropic.com)`,"AI engine required"),u=await wt({message:"Which will you set up?",options:[{value:"claude-code",label:"Claude Code",hint:"I'll install it now"},{value:"gemini-cli",label:"Gemini CLI",hint:"I'll install it now"},{value:"codex-cli",label:"OpenAI Codex",hint:"I'll install it now"},{value:"api",label:"Anthropic API",hint:"I'll enter my key"}]}),u==="api"){let y=await $e({message:"Enter your Anthropic API key:",placeholder:"sk-ant-api03-...",validate:b=>b.startsWith("sk-ant-")?void 0:"Key should start with sk-ant-"});process.env.ANTHROPIC_API_KEY=y,q({anthropicApiKey:y})}let h;return u==="claude-code"&&(h=await wt({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"}]})),q({aiEngine:u}),await de("Environment ready!"),{aiEngine:u,model:h,portalId:o,portalName:i}}g();ct();Z();import{readdirSync as As,statSync as bl}from"fs";import{join as Q,basename as Is,extname as Sl}from"path";function Do(t){let e=[],n=[Q(t,"src/components/landing"),Q(t,"src/components/sections"),Q(t,"src/components"),Q(t,"src/pages"),Q(t,"app/components"),Q(t,"components")];for(let s of n)if(S(s))try{let o=As(s);for(let i of o){let a=Q(s,i);if(!bl(a).isFile())continue;let l=Sl(i);if(![".tsx",".jsx"].includes(l))continue;let c=Is(i,l);if(c.startsWith("ui")||c==="index")continue;let d=I(a),u=vl(c,d);e.push({name:c,path:a,description:u})}}catch{}return e}function vl(t,e){let n=[];return/carousel|slider|swiper|embla/i.test(e)&&n.push("carousel"),/accordion|collapsible|expand/i.test(e)&&n.push("accordion"),/form|submit|input.*email/i.test(e)&&n.push("form"),/nav|navigation|menu/i.test(e)&&n.push("navigation"),/hero|headline|tagline/i.test(e)&&n.push("hero"),/footer|copyright/i.test(e)&&n.push("footer"),/testimonial|quote|review/i.test(e)&&n.push("testimonials"),/pricing|plan|tier/i.test(e)&&n.push("pricing"),/faq|question.*answer/i.test(e)&&n.push("FAQ"),/feature|benefit|advantage/i.test(e)&&n.push("features"),/contact|get.in.touch/i.test(e)&&n.push("contact"),/cta|call.to.action/i.test(e)&&n.push("CTA"),/team|member|bio/i.test(e)&&n.push("team"),n.length===0?t.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim():n.join(", ")}function Lo(t){let e=[Q(t,"src/index.css"),Q(t,"src/globals.css"),Q(t,"src/app/globals.css"),Q(t,"app/globals.css")],n=0,s=[];for(let o of e){if(!S(o))continue;let i=I(o),a=i.match(/--[\w-]+:/g);a&&(n+=a.length);let r=i.match(/font-family:\s*['"]([^'"]+)['"]/g);if(r)for(let c of r){let d=c.match(/['"]([^'"]+)['"]/)?.[1];d&&!s.includes(d)&&s.push(d)}let l=i.match(/@import\s+url\([^)]*fonts\.googleapis\.com[^)]*family=([^&)]+)/g);if(l)for(let c of l){let d=c.match(/family=([^&)]+)/)?.[1]?.replace(/\+/g," ");d&&!s.includes(d)&&s.push(d)}}return{varCount:n,fonts:s}}function Ho(t){let e=[],n=Q(t,"src/hooks");if(S(n))try{let o=As(n);for(let i of o)/scroll/i.test(i)&&e.push("Scroll animations"),/intersection/i.test(i)&&e.push("Scroll animations")}catch{}let s=Q(t,"src/components/landing");if(S(s))try{let o=As(s);for(let i of o){if(!i.endsWith(".tsx")&&!i.endsWith(".jsx"))continue;let a=I(Q(s,i));/carousel|embla|swiper/i.test(a)&&!e.includes("Carousel")&&e.push("Carousel"),/accordion|collapsible/i.test(a)&&!e.includes("Accordion")&&e.push("Accordion"),/typing|typewriter/i.test(a)&&!e.includes("Typing animation")&&e.push("Typing animation"),/parallax|requestAnimationFrame/i.test(a)&&!e.includes("Parallax")&&e.push("Parallax")}}catch{}return e.length===0&&e.push("Scroll animations"),e}function Go(t){let e,n=!1;if(t.startsWith("http")||t.startsWith("git@")){n=!0;let l=Is(t.replace(/\.git$/,""))||"react-source";if(e=Q(process.cwd(),"workspace",l),!S(e)){let c=T(`git clone --depth 1 "${t}" "${e}"`);if(!c.success)throw new Error(`Failed to clone ${t}: ${c.stderr}`)}}else if(e=t,!S(e))throw new Error(`Directory not found: ${e}`);let s=Do(e),o=S(Q(e,"tailwind.config.ts"))||S(Q(e,"tailwind.config.js")),{varCount:i,fonts:a}=Lo(e),r=Ho(e);return{sourceDir:e,wasCloned:n,components:s,hasTailwind:o,cssVarCount:i,fonts:a,interactions:r}}async function An(){await ce("Source Project");let t=await $e({message:"GitHub URL or local path to your React project:",placeholder:"https://github.com/user/my-lovable-page",validate:h=>{if(!h.trim())return"Please enter a URL or path"}}),e,n=!1;if(t.startsWith("http")||t.startsWith("git@")){n=!0;let h=Is(t.replace(/\.git$/,""))||"react-source";if(e=Q(process.cwd(),"workspace",h),S(e))F(`Using existing clone: ${k.dim(e)}`);else{let y=await ue();y.start("Cloning repository..."),T(`git clone --depth 1 "${t}" "${e}"`).success||(y.stop("Clone failed"),W(`Failed to clone ${t}. Check the URL and your access permissions.`),process.exit(1)),y.stop(`Cloned to ${k.dim(e)}`)}}else e=t,S(e)||(W(`Directory not found: ${e}`),process.exit(1)),F(`Using local source: ${k.dim(e)}`);let s=await ue();s.start("Analyzing project structure...");let o=Do(e),i=S(Q(e,"tailwind.config.ts"))||S(Q(e,"tailwind.config.js")),{varCount:a,fonts:r}=Lo(e),l=Ho(e);s.stop(`Found ${o.length} landing page components`),o.length===0&&(V("No components found. Make sure the React source has .tsx/.jsx files in src/components/"),process.exit(1));let c=o.map((h,y)=>` ${k.dim(`${y+1}.`)} ${k.bold(h.name)} ${k.muted(`\u2014 ${h.description}`)}`).join(`
|
|
1159
|
+
`),d=i?`Tailwind + custom CSS (${a} variables)`:`Custom CSS (${a} variables)`,u=r.length>0?r.join(", "):"System fonts",p=l.join(", ");return await je(`${c}
|
|
1160
|
+
|
|
1161
|
+
CSS: ${d}
|
|
1162
|
+
JS: ${p}
|
|
1163
|
+
Font: ${u}`,`${o.length} components detected`),await se({message:"Does this look right?"})||(W("Please adjust your source directory and try again."),process.exit(0)),await de("Source analyzed!"),{sourceDir:e,wasCloned:n,components:o,hasTailwind:i,cssVarCount:a,fonts:r,interactions:l}}g();ct();Z();import{join as Kt}from"path";ee();g();import{mkdirSync as Qe,writeFileSync as In}from"fs";import{join as Te}from"path";function kn(t,e){Qe(t,{recursive:!0}),Qe(Te(t,"templates"),{recursive:!0}),Qe(Te(t,"modules"),{recursive:!0}),Qe(Te(t,"css"),{recursive:!0}),Qe(Te(t,"js"),{recursive:!0}),Qe(Te(t,"images"),{recursive:!0}),Qe(Te(t,"assets"),{recursive:!0});let n={label:e,preview_path:"./templates/home.html",screenshot_path:"./images/template-previews/home.png",enable_domain_stylesheets:!1,version:"1.0.0",author:{name:"vibeSpot",url:"https://github.com/borismichel/vibespot"}};In(Te(t,"theme.json"),JSON.stringify(n,null,2)+`
|
|
1164
|
+
`),In(Te(t,"fields.json"),`[]
|
|
1165
|
+
`);let s=`<!--
|
|
1166
|
+
templateType: page
|
|
1167
|
+
isAvailableForNewContent: false
|
|
1168
|
+
label: ${e} (placeholder)
|
|
1169
|
+
screenshotPath: ../images/template-previews/home.png
|
|
1170
|
+
-->
|
|
1171
|
+
{% extends "./layouts/base.html" %}
|
|
1172
|
+
|
|
1173
|
+
{% block body %}
|
|
1174
|
+
{% dnd_area "main_content"
|
|
1175
|
+
label="Main Content",
|
|
1176
|
+
class="body-container body-container--${e}"
|
|
1177
|
+
%}
|
|
1178
|
+
{% end_dnd_area %}
|
|
1179
|
+
{% endblock body %}
|
|
1180
|
+
`;In(Te(t,"templates","home.html"),s);let o=`<!--
|
|
1181
|
+
templateType: none
|
|
1182
|
+
isAvailableForNewContent: false
|
|
1183
|
+
label: Base Layout
|
|
1184
|
+
-->
|
|
1185
|
+
<!DOCTYPE html>
|
|
1186
|
+
<html lang="{{ html_lang }}" {{ html_lang_dir }}>
|
|
1187
|
+
<head>
|
|
1188
|
+
<meta charset="utf-8">
|
|
1189
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1190
|
+
{% if template_css %}
|
|
1191
|
+
{{ require_css(get_asset_url(template_css)) }}
|
|
1192
|
+
{% endif %}
|
|
1193
|
+
{{ standard_header_includes }}
|
|
1194
|
+
</head>
|
|
1195
|
+
<body>
|
|
1196
|
+
{% block body %}{% endblock body %}
|
|
1197
|
+
{% if template_js %}
|
|
1198
|
+
{{ require_js(get_asset_url(template_js)) }}
|
|
1199
|
+
{% endif %}
|
|
1200
|
+
{{ standard_footer_includes }}
|
|
1201
|
+
</body>
|
|
1202
|
+
</html>
|
|
1203
|
+
`;Qe(Te(t,"templates","layouts"),{recursive:!0}),In(Te(t,"templates","layouts","base.html"),o)}$n();async function Tn(){await ce("HubSpot Theme Setup");let t=await wt({message:"Do you have an existing HubSpot theme?",options:[{value:"fetch",label:"Fetch my existing theme from HubSpot",hint:"downloads your current theme"},{value:"create",label:"Start fresh (HubSpot Boilerplate)",hint:"creates a new starter theme"}]}),e,n,s=Kt(process.cwd(),"workspace");if(Ae(s),t==="fetch"){e=await $e({message:"What's your theme name in HubSpot?",placeholder:"My-Company-Theme",validate:u=>u.trim()?void 0:"Theme name is required"}),n=Kt(s,e);let l=await ue();l.start("Fetching theme from HubSpot...");let c=M(),d=he();if(c.hubspotUploadMode==="cli"||!d)T(`hs cms fetch "${e}" "${n}"`).success||(l.stop("Fetch failed"),W(`Could not fetch theme "${e}". Check the name in HubSpot Design Manager.`),process.exit(1));else try{await Bt(d,e,n)}catch(u){l.stop("Fetch failed"),W(`Could not fetch theme "${e}": ${u instanceof Error?u.message:String(u)}`),process.exit(1)}l.stop(`Theme fetched: ${k.dim(n)}`)}else{e=await $e({message:"Name for your new theme:",placeholder:"my-theme",defaultValue:"my-theme"}),n=Kt(s,e);let l=await ue();l.start("Creating theme...");try{kn(n,e)}catch(c){l.stop("Creation failed"),W(`Could not create theme "${e}": ${c instanceof Error?c.message:String(c)}`),process.exit(1)}l.stop(`Theme created: ${k.dim(n)}`)}await ce("Checking theme compatibility");let o=Kt(n,"templates/layouts/base.html");S(o)||(W(`base.html not found at ${o}. Your theme may have a different structure.`),process.exit(1)),F("base.html found");let i=I(o),a=!1;if(i.includes("template_css"))F("template_css support");else{V("Missing template_css support in base.html");let l=i.indexOf("theme-overrides.css")!==-1?i.indexOf("{{",i.lastIndexOf(`
|
|
1204
|
+
`,i.indexOf("theme-overrides.css"))):i.lastIndexOf("require_css");if(l>0){let c=i.lastIndexOf(`
|
|
1205
|
+
`,l);i=i.slice(0,c)+`
|
|
1206
|
+
{% if template_css %}
|
|
1207
|
+
{{ require_css(get_asset_url(template_css)) }}
|
|
1208
|
+
{% endif %}`+i.slice(c),a=!0}}if(i.includes("template_js"))F("template_js support");else{V("Missing template_js support in base.html");let l=i.indexOf("require_js");if(l>0){let c=i.indexOf(`
|
|
1209
|
+
`,l),d=i.indexOf(`
|
|
1210
|
+
`,c+1),u=`
|
|
1211
|
+
{% if template_js %}
|
|
1212
|
+
{{ require_js(get_asset_url(template_js)) }}
|
|
1213
|
+
{% endif %}`,p=i.indexOf("}}",l)+2+i.slice(i.indexOf("}}",l)+2).indexOf(`
|
|
1214
|
+
`)+1;i=i.slice(0,i.indexOf(`
|
|
1215
|
+
`,i.indexOf("}}",l)+2))+u+i.slice(i.indexOf(`
|
|
1216
|
+
`,i.indexOf("}}",l)+2)),a=!0}}if(a){let l=await ue();l.start("Patching base.html..."),H(o,i),l.stop("base.html patched with template_css/template_js support")}let r=Kt(n,".hsignore");if(S(r)){let l=I(r);l.includes("docs/")||(H(r,l+`
|
|
1217
|
+
docs/
|
|
1218
|
+
`),F("Added docs/ to .hsignore"))}else H(r,`docs/
|
|
1219
|
+
*.md
|
|
1220
|
+
node_modules/
|
|
1221
|
+
.git
|
|
1222
|
+
`),F("Created .hsignore");return await de("Theme ready!"),{themePath:n,themeName:e}}g();import{join as Ie}from"path";import{readdirSync as Vt,rmSync as si}from"fs";g();Ve();Z();import{spawn as Il}from"child_process";import{join as B,basename as kl}from"path";import{readdirSync as Fe,statSync as ti,writeFileSync as $l}from"fs";var Tl=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"]),En=class{model;reported=new Set;moduleCount=0;expectedModules=0;constructor(e){this.model=e}async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||le();this.reported.clear(),this.moduleCount=0,this.expectedModules=0;let a=this.countSourceComponents(n),r=this.listModules(s),l=this.listDir(B(s,"css")),c=this.listDir(B(s,"js")),d=this.listDir(B(s,"templates")),u=this.buildFullPrompt(n,s,i);o("convert",`Starting Claude Code (${a} source components found)...`);let p="",f="",h=setInterval(()=>{this.reportProgress(s,r,l,c,d,o)},3e3);try{await new Promise((w,$)=>{let R={...process.env};delete R.CLAUDECODE;let P=["--print","--max-turns","50","--allowedTools","Read,Glob,Grep,Write,Edit,Bash"];this.model&&P.push("--model",this.model);let N=Il("claude",P,{cwd:s,stdio:["pipe","pipe","pipe"],env:R,shell:!0});N.stdout.on("data",L=>{p+=L.toString()}),N.stderr.on("data",L=>{f+=L.toString()}),N.on("error",L=>$(new Error(`Claude Code failed to start: ${L.message}`))),N.on("close",L=>{L!==0?$(new Error(`Claude Code exited with code ${L}.
|
|
1223
|
+
`+(f?`Stderr: ${f.slice(0,500)}
|
|
1224
|
+
`:"")+(p?`Output: ${p.slice(0,500)}`:"No output"))):w()}),N.stdin.on("error",()=>{}),N.stdin.write(u),N.stdin.end(),setTimeout(()=>{N.kill(),$(new Error("Claude Code timed out after 30 minutes"))},18e5)})}finally{clearInterval(h)}let y=B(s,"..","vibespot-conversion.log");try{let $=["=== vibeSpot Conversion Log ===",`Timestamp: ${new Date().toISOString()}`,`Source: ${n}`,`Theme: ${s}`,`Model: ${this.model||"default"}`,"","=== PROMPT SENT ===",u.slice(0,500)+`
|
|
1225
|
+
... (truncated, full guide follows)`,"","=== CLAUDE CODE STDOUT ===",p||"(empty)","","=== CLAUDE CODE STDERR ===",f||"(empty)",""].join(`
|
|
1226
|
+
`);$l(y,$,"utf-8"),o("status",`Log written to ${kl(y)}`)}catch{}o("scan","Scanning generated files...");let b=this.scanGeneratedFiles(s);if(b.modules.filter(w=>!r.has(w.moduleName+".module")).length===0){let w=p.slice(0,1500)||"(no output)",$=f.slice(0,500);throw new Error(`Claude Code did not create any new module files.
|
|
1227
|
+
|
|
1228
|
+
This usually means the model described the conversion instead of using Write tool to create files.
|
|
1229
|
+
|
|
1230
|
+
Possible causes:
|
|
1231
|
+
- Model didn't use Write tool (just printed text)
|
|
1232
|
+
- Claude Code hit a rate limit or API error
|
|
1233
|
+
- The source directory was not accessible
|
|
1234
|
+
|
|
1235
|
+
Source: ${e.sourceDir}
|
|
1236
|
+
Theme: ${s}
|
|
1237
|
+
`+($?`
|
|
1238
|
+
Stderr:
|
|
1239
|
+
${$}
|
|
1240
|
+
`:"")+`
|
|
1241
|
+
Claude output:
|
|
1242
|
+
${w}`)}return b}reportProgress(e,n,s,o,i,a){let r=0,l=this.listDir(B(e,"css"));for(let p of l){if(s.has(p)||!p.endsWith(".css"))continue;let f=`css:${p}`;this.reported.has(f)||(this.reported.add(f),a("created",`Shared CSS (${p})`),r++)}let c=this.listDir(B(e,"js"));for(let p of c){if(o.has(p)||!p.endsWith(".js"))continue;let f=`js:${p}`;this.reported.has(f)||(this.reported.add(f),a("created",`Shared JS (${p})`),r++)}this.expectedModules===0&&(this.expectedModules=this.detectExpectedModules(e,i));let d=this.listModules(e);for(let p of d){if(n.has(p))continue;let f=`module:${p}`;if(!this.reported.has(f)){this.reported.add(f),this.moduleCount++;let h=this.expectedModules>0?`[${this.moduleCount}/${this.expectedModules}]`:`[${this.moduleCount}]`;a("created",`Module ${h}: ${p.replace(".module","")}`),r++}}let u=this.listDir(B(e,"templates"));for(let p of u){if(i.has(p)||!p.endsWith(".html"))continue;let f=`template:${p}`;this.reported.has(f)||(this.reported.add(f),a("created",`Page template (${p})`),r++)}if(r===0)if(this.moduleCount>0){let p=this.expectedModules>0?`/${this.expectedModules}`:"";a("status",`${this.moduleCount}${p} modules created, conversion continuing...`)}else this.reported.size>0?a("status","Shared assets created, building modules..."):a("status","Claude Code is analyzing source files...")}buildFullPrompt(e,n,s){return`You are converting a React landing page to native HubSpot CMS modules.
|
|
1243
|
+
|
|
1244
|
+
SOURCE DIRECTORY: ${e}
|
|
1245
|
+
THEME DIRECTORY: ${n}
|
|
1246
|
+
|
|
1247
|
+
IMPORTANT \u2014 YOU MUST CREATE REAL FILES:
|
|
1248
|
+
You have access to Write, Edit, Read, Glob, Grep, and Bash tools. You MUST use the Write tool to create each file. Do NOT just describe or list what files should be created \u2014 actually call the Write tool for every single file. If you do not call Write, no files will be created and the conversion will fail.
|
|
1249
|
+
|
|
1250
|
+
STEP-BY-STEP PROCESS:
|
|
1251
|
+
1. Use Glob to find all .tsx/.jsx files in ${e}/src/
|
|
1252
|
+
2. Use Read to read each component file and understand the page structure
|
|
1253
|
+
3. Use Write to create a shared CSS file at ${n}/css/<name>-theme.css
|
|
1254
|
+
- Include CSS custom properties, design system variables, utility classes
|
|
1255
|
+
- Add theme-override countermeasures (.body-wrapper:has(), scoped !important overrides)
|
|
1256
|
+
4. Use Write to create a shared JS file at ${n}/js/<name>-animations.js
|
|
1257
|
+
- Convert React hooks to vanilla JS (IntersectionObserver for scroll animations)
|
|
1258
|
+
- IIFE wrapper, DOMContentLoaded setup
|
|
1259
|
+
5. For EACH visual section of the page, use Write to create ALL FOUR files:
|
|
1260
|
+
a. ${n}/modules/<name>.module/fields.json
|
|
1261
|
+
- Editable fields for the section content
|
|
1262
|
+
- NEVER use "textarea" type (use "text" instead)
|
|
1263
|
+
- NEVER use "name" as a field name (use "item_name" instead)
|
|
1264
|
+
- Add a "styles" group with "tab": "STYLE" containing color pickers
|
|
1265
|
+
b. ${n}/modules/<name>.module/meta.json
|
|
1266
|
+
- Must include: host_template_types: ["PAGE"], is_available_for_new_content: true
|
|
1267
|
+
c. ${n}/modules/<name>.module/module.html
|
|
1268
|
+
- HubL template that renders the section (convert JSX to HubL)
|
|
1269
|
+
d. ${n}/modules/<name>.module/module.css
|
|
1270
|
+
- REQUIRED \u2014 complete vanilla CSS for this section
|
|
1271
|
+
- Must include: layout, spacing, colors, typography, backgrounds, gradients, shadows, borders, hover effects, responsive breakpoints
|
|
1272
|
+
- Convert ALL Tailwind classes to BEM-style CSS. Do NOT skip this file.
|
|
1273
|
+
6. Use Write to create a page template at ${n}/templates/lp-<name>.html
|
|
1274
|
+
- Annotation: templateType: page, isAvailableForNewContent: true
|
|
1275
|
+
- Extends "./layouts/base.html"
|
|
1276
|
+
- Sets template_css and template_js variables
|
|
1277
|
+
- Wraps modules in dnd_area with dnd_section containers
|
|
1278
|
+
7. Read ${n}/templates/layouts/base.html and ensure it supports template_css and template_js variables
|
|
1279
|
+
|
|
1280
|
+
CSS QUALITY: The converted page must visually match the original React page. Every module.css must be self-contained with complete styling for that section.
|
|
1281
|
+
|
|
1282
|
+
Do NOT run hs upload \u2014 I will handle that separately.
|
|
1283
|
+
|
|
1284
|
+
HUBSPOT CMS RULES:
|
|
1285
|
+
${Ze()}
|
|
1286
|
+
|
|
1287
|
+
CONVERSION GUIDE:
|
|
1288
|
+
${s}`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=B(e,"css");if(S(s)){for(let r of Fe(s))if(r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=I(B(s,r));break}}let o=B(e,"js");if(S(o)){for(let r of Fe(o))if(r.endsWith(".js")&&r!=="main.js"){n.sharedJs=I(B(o,r));break}}let i=B(e,"templates");if(S(i)){for(let r of Fe(i))if(r.startsWith("lp-")&&r.endsWith(".html")){n.template=I(B(i,r));break}if(!n.template){for(let r of Fe(i))if(r.endsWith(".html")&&!Tl.has(r)&&!r.startsWith("system")){let l=I(B(i,r));if(l.includes("dnd_area")){n.template=l;break}}}if(!n.template){for(let r of Fe(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=I(B(i,r));if(l.includes("dnd_area")){n.template=l;break}}}}let a=B(e,"modules");if(S(a))for(let r of Fe(a)){if(!r.endsWith(".module"))continue;let l=B(a,r);if(!ti(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=B(l,"fields.json");S(d)&&(c.fieldsJson=I(d));let u=B(l,"meta.json");S(u)&&(c.metaJson=I(u));let p=B(l,"module.html");S(p)&&(c.moduleHtml=I(p));let f=B(l,"module.css");S(f)&&(c.moduleCss=I(f));let h=B(l,"module.js");S(h)&&(c.moduleJs=I(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}listModules(e){let n=B(e,"modules");return S(n)?new Set(Fe(n).filter(s=>s.endsWith(".module"))):new Set}listDir(e){return S(e)?new Set(Fe(e)):new Set}detectExpectedModules(e,n){let s=B(e,"templates");if(!S(s))return 0;for(let o of Fe(s))if(!n.has(o)&&!(!o.endsWith(".html")||o==="base.html"||o.startsWith("system")))try{let i=I(B(s,o));if(i.includes("dnd_area")){let a=i.match(/dnd_module/g);return a?a.length:0}}catch{}return 0}countSourceComponents(e){let n=B(e,"src");return S(n)?this.countComponentsRecursive(n):0}countComponentsRecursive(e){let n=0;for(let s of Fe(e)){let o=B(e,s);try{ti(o).isDirectory()&&s!=="node_modules"&&s!==".git"?n+=this.countComponentsRecursive(o):/\.(tsx|jsx)$/.test(s)&&!s.includes(".test.")&&!s.includes(".spec.")&&n++}catch{}}return n}};g();Ve();Z();import El from"@anthropic-ai/sdk";import{join as Y,basename as Nl}from"path";import{readdirSync as ni}from"fs";var Nn=class{client;model="claude-sonnet-4-6";constructor(e){this.client=new El({apiKey:e||process.env.ANTHROPIC_API_KEY})}async convert(e){let{sourceDir:n,themePath:s,conversionGuide:o,onProgress:i}=e,a=qo(o),r=Nl(n)||"page",l=r.toLowerCase().replace(/[^a-z0-9]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,15);i("css","Analyzing design system...");let c=this.findAndReadCSS(n),d=this.findAndReadTailwind(n),u=await this.complete(a,Qo(c,d,l)),p=Y(s,"css",`${l}-theme.css`);H(p,u),i("css-done",`Created css/${l}-theme.css`),i("js","Creating shared JavaScript...");let f=this.findAndReadHooks(n),h=this.findInteractiveComponents(n),y=await this.complete(a,Zo(f,h,l)),b=Y(s,"js",`${l}-animations.js`);H(b,y),i("js-done",`Created js/${l}-animations.js`),i("modules","Building modules...");let A=this.findComponents(n),w=[];for(let N=0;N<A.length;N++){let L=A[N],ne=L.name.replace(/Section$/,"").replace(/([A-Z])/g," $1").trim();i("module",`Building ${ne}.module (${N+1}/${A.length})...`);let U=I(L.path),G=await this.complete(a,Xo(U,ne,`See css/${l}-theme.css`));try{let O=JSON.parse(G),z={moduleName:ne,fieldsJson:typeof O.fieldsJson=="string"?O.fieldsJson:JSON.stringify(O.fieldsJson,null,2),metaJson:typeof O.metaJson=="string"?O.metaJson:JSON.stringify(O.metaJson,null,2),moduleHtml:O.moduleHtml||"",moduleCss:O.moduleCss||"",moduleJs:O.moduleJs||void 0},ae=Y(s,"modules",`${ne}.module`);Ae(ae),H(Y(ae,"fields.json"),z.fieldsJson),H(Y(ae,"meta.json"),z.metaJson),H(Y(ae,"module.html"),z.moduleHtml),H(Y(ae,"module.css"),z.moduleCss),z.moduleJs&&H(Y(ae,"module.js"),z.moduleJs),w.push(z),i("module-done",`${ne}.module (${this.countFiles(z)} files)`)}catch{i("module-error",`Failed to parse ${ne} \u2014 skipping`)}}i("template","Creating page template...");let $=w.map(N=>N.moduleName),R=await this.complete(a,ei($,r,l)),P=Y(s,"templates",`lp-${l}.html`);return H(P,R),i("template-done",`Created templates/lp-${l}.html`),{sharedCss:u,sharedJs:y,template:R,modules:w}}async complete(e,n){return(await this.client.messages.create({model:this.model,max_tokens:8192,system:e,messages:[{role:"user",content:n}]})).content.find(i=>i.type==="text")?.text||""}findAndReadCSS(e){let n=[Y(e,"src/index.css"),Y(e,"src/globals.css"),Y(e,"src/app/globals.css"),Y(e,"app/globals.css")];for(let s of n)if(S(s))return I(s);return""}findAndReadTailwind(e){let n=[Y(e,"tailwind.config.ts"),Y(e,"tailwind.config.js"),Y(e,"tailwind.config.mjs")];for(let s of n)if(S(s))return I(s);return""}findAndReadHooks(e){let n=Y(e,"src/hooks");if(!S(n))return"";try{return ni(n).filter(s=>s.endsWith(".ts")||s.endsWith(".tsx")).map(s=>`// ${s}
|
|
1289
|
+
${I(Y(n,s))}`).join(`
|
|
1290
|
+
|
|
1291
|
+
`)}catch{return""}}findInteractiveComponents(e){let n=this.findComponents(e),s=[];for(let o of n){let i=I(o.path);/carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(i)&&s.push(`// ${o.name}
|
|
1292
|
+
${i}`)}return s.join(`
|
|
1293
|
+
|
|
1294
|
+
`)}findComponents(e){let n=[Y(e,"src/components/landing"),Y(e,"src/components/sections"),Y(e,"src/components")];for(let s of n)if(S(s))try{return ni(s).filter(o=>(o.endsWith(".tsx")||o.endsWith(".jsx"))&&!o.startsWith("ui")&&o!=="index.tsx"&&o!=="index.jsx").map(o=>({name:o.replace(/\.(tsx|jsx)$/,""),path:Y(s,o)}))}catch{continue}return[]}countFiles(e){let n=3;return e.moduleCss&&n++,e.moduleJs&&n++,n}};g();Ve();Z();import{spawn as Ml}from"child_process";import{join as we}from"path";import{readdirSync as Mn,statSync as Pl}from"fs";var Pn=class{async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||le(),a=this.buildFullPrompt(n,s,i);return o("convert","Running Gemini CLI (this may take a few minutes)..."),await new Promise((r,l)=>{let c=Ml("gemini",["-p",a],{cwd:s,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),d="",u="";c.stdout.on("data",p=>{d+=p.toString()}),c.stderr.on("data",p=>{u+=p.toString()}),c.on("error",p=>l(new Error(`Gemini CLI failed: ${p.message}`))),c.on("close",p=>{p!==0&&u&&!d?l(new Error(`Gemini CLI failed: ${u}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Gemini CLI timed out after 10 minutes"))},6e5)}),o("scan","Scanning generated files..."),this.scanGeneratedFiles(s)}buildFullPrompt(e,n,s){return`Read the conversion guide below, then convert the React landing page at ${e} into native HubSpot CMS modules for the theme at ${n}.
|
|
1295
|
+
|
|
1296
|
+
INSTRUCTIONS:
|
|
1297
|
+
1. Analyze all .tsx/.jsx components in the React source
|
|
1298
|
+
2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures
|
|
1299
|
+
3. Create a shared JS file in js/ for scroll animations and interactive features
|
|
1300
|
+
4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css
|
|
1301
|
+
5. Add a styles group with "tab": "STYLE" and color pickers to each module
|
|
1302
|
+
6. Create a page template in templates/ that assembles all modules
|
|
1303
|
+
7. Make sure base.html supports template_css and template_js variables
|
|
1304
|
+
|
|
1305
|
+
CONVERSION GUIDE:
|
|
1306
|
+
${s}
|
|
1307
|
+
|
|
1308
|
+
Do NOT run hs upload \u2014 I will handle that separately.
|
|
1309
|
+
Create all files directly in the theme directory.`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=we(e,"css");if(S(s)){for(let r of Mn(s))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=I(we(s,r));break}}let o=we(e,"js");if(S(o)){for(let r of Mn(o))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){n.sharedJs=I(we(o,r));break}}let i=we(e,"templates");if(S(i)){for(let r of Mn(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=I(we(i,r));if(l.includes("dnd_area")){n.template=l;break}}}let a=we(e,"modules");if(S(a))for(let r of Mn(a)){if(!r.endsWith(".module"))continue;let l=we(a,r);if(!Pl(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=we(l,"fields.json");S(d)&&(c.fieldsJson=I(d));let u=we(l,"meta.json");S(u)&&(c.metaJson=I(u));let p=we(l,"module.html");S(p)&&(c.moduleHtml=I(p));let f=we(l,"module.css");S(f)&&(c.moduleCss=I(f));let h=we(l,"module.js");S(h)&&(c.moduleJs=I(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}};g();Ve();Z();import{spawn as _l}from"child_process";import{join as xe}from"path";import{readdirSync as _n,statSync as Rl}from"fs";var Rn=class{async convert(e){let{sourceDir:n,themePath:s,onProgress:o}=e,i=e.conversionGuide||le(),a=this.buildFullPrompt(n,s,i);return o("convert","Running OpenAI Codex (this may take a few minutes)..."),await new Promise((r,l)=>{let c=_l("codex",["exec","--full-auto",a],{cwd:s,stdio:["pipe","pipe","pipe"],env:{...process.env},shell:!0}),d="",u="";c.stdout.on("data",p=>{d+=p.toString()}),c.stderr.on("data",p=>{u+=p.toString()}),c.on("error",p=>l(new Error(`Codex CLI failed: ${p.message}`))),c.on("close",p=>{p!==0&&u&&!d?l(new Error(`Codex CLI failed: ${u}`)):r()}),setTimeout(()=>{c.kill(),l(new Error("Codex CLI timed out after 10 minutes"))},6e5)}),o("scan","Scanning generated files..."),this.scanGeneratedFiles(s)}buildFullPrompt(e,n,s){return`Read the conversion guide below, then convert the React landing page at ${e} into native HubSpot CMS modules for the theme at ${n}.
|
|
1310
|
+
|
|
1311
|
+
INSTRUCTIONS:
|
|
1312
|
+
1. Analyze all .tsx/.jsx components in the React source
|
|
1313
|
+
2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures
|
|
1314
|
+
3. Create a shared JS file in js/ for scroll animations and interactive features
|
|
1315
|
+
4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css
|
|
1316
|
+
5. Add a styles group with "tab": "STYLE" and color pickers to each module
|
|
1317
|
+
6. Create a page template in templates/ that assembles all modules
|
|
1318
|
+
7. Make sure base.html supports template_css and template_js variables
|
|
1319
|
+
|
|
1320
|
+
CONVERSION GUIDE:
|
|
1321
|
+
${s}
|
|
1322
|
+
|
|
1323
|
+
Do NOT run hs upload \u2014 I will handle that separately.
|
|
1324
|
+
Create all files directly in the theme directory.`}scanGeneratedFiles(e){let n={sharedCss:"",sharedJs:"",template:"",modules:[]},s=xe(e,"css");if(S(s)){for(let r of _n(s))if((r.includes("theme")||r.includes("page"))&&r.endsWith(".css")&&r!=="theme-overrides.css"&&r!=="main.css"&&r!=="style.css"){n.sharedCss=I(xe(s,r));break}}let o=xe(e,"js");if(S(o)){for(let r of _n(o))if((r.includes("animation")||r.includes("page"))&&r.endsWith(".js")&&r!=="main.js"){n.sharedJs=I(xe(o,r));break}}let i=xe(e,"templates");if(S(i)){for(let r of _n(i))if(r.endsWith(".html")&&!r.startsWith("system")&&r!=="base.html"){let l=I(xe(i,r));if(l.includes("dnd_area")){n.template=l;break}}}let a=xe(e,"modules");if(S(a))for(let r of _n(a)){if(!r.endsWith(".module"))continue;let l=xe(a,r);if(!Rl(l).isDirectory())continue;let c={moduleName:r.replace(".module",""),fieldsJson:"",metaJson:"",moduleHtml:"",moduleCss:""},d=xe(l,"fields.json");S(d)&&(c.fieldsJson=I(d));let u=xe(l,"meta.json");S(u)&&(c.metaJson=I(u));let p=xe(l,"module.html");S(p)&&(c.moduleHtml=I(p));let f=xe(l,"module.css");S(f)&&(c.moduleCss=I(f));let h=xe(l,"module.js");S(h)&&(c.moduleJs=I(h)),c.fieldsJson&&c.moduleHtml&&n.modules.push(c)}return n}};Ve();Z();function Ol(t,e){switch(t){case"claude-code":return new En(e);case"gemini-cli":return new Pn;case"codex-cli":return new Rn;case"api":return new Nn}}async function On(t){await ce("Converting React to HubSpot Modules"),await je(`AI will now analyze your React code and create
|
|
1325
|
+
HubSpot-native modules. This takes 2-5 minutes.`,"AI Conversion");let e=Ol(t.aiEngine,t.model),n=le(),s=await ue();s.start("Starting AI conversion...");let o=Date.now(),i=await e.convert({sourceDir:t.sourceDir,themePath:t.themePath,conversionGuide:n,onProgress:(h,y)=>{h==="created"?F(y):s.message(y)}}),a=((Date.now()-o)/1e3).toFixed(0);s.stop(`AI conversion complete (${a}s)`);let r=jl(t.themePath);for(let h of r)F(`Auto-fixed: ${h}`);let l=Fl(t.themePath,i),c=[];for(let h of l){let y=h.passed?"\u2705":"\u274C",b=h.passed?"":h.critical?" (CRITICAL)":" (cosmetic)";c.push(`${y} ${h.label}${b}`)}let d=l.filter(h=>h.passed).length;c.push(`
|
|
1326
|
+
${d}/${l.length} checks passed`),await je(c.join(`
|
|
1327
|
+
`),"Conversion Checklist");let u=l.filter(h=>!h.passed&&h.critical),p=l.filter(h=>!h.passed&&!h.critical);if(u.length>0){if(W(`${u.length} critical issue(s) \u2014 upload will likely fail:
|
|
1328
|
+
`+u.map(y=>` - ${y.label}`).join(`
|
|
1329
|
+
`)),!await se({message:"Continue with upload anyway?",initialValue:!1}))throw new Error("Conversion aborted due to critical checklist failures.")}else p.length>0&&V(`${p.length} non-critical issue(s) \u2014 page will work but may look incomplete:
|
|
1330
|
+
`+p.map(h=>` - ${h.label}`).join(`
|
|
1331
|
+
`));let f=Ie(t.themePath,"..","vibespot-conversion.log");return S(f)&&(await se({message:"Keep conversion log file for debugging?",initialValue:!1})?F(`Log saved: ${f}`):si(f)),await de("Files ready for upload!"),i}function jl(t){let e=[];Jl(t),Dl(t);let n=Ie(t,"modules");if(S(n))for(let o of Vt(n)){if(!o.endsWith(".module"))continue;let i=Ie(n,o,"fields.json");if(!S(i))continue;let a=o.replace(".module",""),r=I(i),l=!1;r.includes('"textarea"')&&(r=r.replace(/"textarea"/g,'"text"'),l=!0,e.push(`${a}: "textarea" \u2192 "text"`)),/"name":\s*"name"/.test(r)&&(r=r.replace(/"name":\s*"name"/g,'"name": "item_name"'),l=!0,e.push(`${a}: reserved field name "name" \u2192 "item_name"`));try{let d=JSON.parse(r),u=!1;oi(d)&&(u=!0,e.push(`${a}: fixed choice field format`)),ii(d)&&(u=!0,e.push(`${a}: fixed link field default value`)),u&&(r=JSON.stringify(d,null,2)+`
|
|
1332
|
+
`,l=!0)}catch{e.push(`${a}: fields.json has invalid JSON \u2014 manual fix needed`)}l&&H(i,r);let c=Ie(n,o,"module.html");if(S(c)){let d=I(c);d.includes("now()")&&(d=d.replace(/now\(\)/g,"local_dt"),H(c,d),e.push(`${a}: now() \u2192 local_dt`))}}let s=Ie(t,"templates");if(S(s))for(let o of Vt(s)){if(!o.endsWith(".html"))continue;let i=Ie(s,o),a=I(i);(a.includes("hubdb_table")||a.includes("hubdb_table_rows"))&&(si(i),e.push(`Removed ${o} (HubDB requires CMS Hub Pro/Enterprise)`))}return e}function oi(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;s.type==="choice"&&Array.isArray(s.choices)&&s.choices.some(i=>typeof i=="string")&&(s.choices=s.choices.map(i=>{if(typeof i=="string"){let a=i.charAt(0).toUpperCase()+i.slice(1);return[i,a]}return i}),e=!0),Array.isArray(s.children)&&oi(s.children)&&(e=!0)}return e}function ii(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="link"){let o=s.default;if(typeof o=="string"||o===void 0||o===null||typeof o=="object"&&!o.url){let a=typeof o=="string"?o:"";s.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},e=!0}}Array.isArray(s.children)&&ii(s.children)&&(e=!0)}return e}function Fl(t,e){let n=[],s=e.modules.length;n.push({label:`Modules created (${s})`,passed:s>0,critical:!0});let o=!0;for(let u of e.modules)if(u.fieldsJson.includes('"textarea"')||/"name":\s*"name"/.test(u.fieldsJson)){o=!1;break}n.push({label:"fields.json valid (no textarea, no reserved names)",passed:s>0&&o,critical:!0});let i=e.modules.every(u=>u.moduleHtml.length>0);n.push({label:"module.html created for each module",passed:s>0&&i,critical:!0});let a=e.modules.filter(u=>!u.moduleCss).map(u=>u.moduleName),r=a.length===0;n.push({label:r?"module.css created for each module":`module.css missing for: ${a.join(", ")}`,passed:s>0&&r,critical:!1});let l=e.modules.some(u=>u.fieldsJson.includes('"STYLE"'));n.push({label:"Style tab fields (color pickers)",passed:l,critical:!1}),n.push({label:"Shared CSS with design system variables",passed:e.sharedCss.length>50,critical:!1}),n.push({label:"Shared JS for scroll animations",passed:e.sharedJs.length>50,critical:!1}),n.push({label:"Page template with dnd_area",passed:e.template.length>0&&e.template.includes("dnd_area"),critical:!0});let c=Ie(t,"templates"),d=!1;if(S(c))for(let u of Vt(c)){if(!u.endsWith(".html")||u==="base.html"||u.startsWith("system"))continue;let p=I(Ie(c,u));if(p.includes("dnd_area")&&/templateType\s*:\s*page/i.test(p)){d=!0;break}}return n.push({label:"Template annotations (templateType: page)",passed:d,critical:!0}),n}function Jl(t){let e=Ie(t,"templates");if(S(e))for(let n of Vt(e)){if(!n.endsWith(".html")||n==="base.html"||n.startsWith("system"))continue;let s=Ie(e,n),o=I(s);if(!o.includes("dnd_area")&&!o.includes("extends"))continue;let i=/templateType\s*:\s*page/i.test(o),a=/isAvailableForNewContent\s*:\s*true/i.test(o);if(i&&a)continue;let r=n.replace(".html","").replace(/[-_]/g," ").replace(/\b\w/g,l=>l.toUpperCase());if(o.includes("<!--")&&o.indexOf("-->")<200){let l=o.indexOf("-->"),c=o.slice(0,l);i||(c+=`
|
|
1333
|
+
templateType: page`),a||(c+=`
|
|
1334
|
+
isAvailableForNewContent: true`),/label\s*:/i.test(c)||(c+=`
|
|
1335
|
+
label: ${r}`),o=c+o.slice(l)}else o=`<!--
|
|
1336
|
+
templateType: page
|
|
1337
|
+
isAvailableForNewContent: true
|
|
1338
|
+
label: ${r}
|
|
1339
|
+
-->
|
|
1340
|
+
`+o;H(s,o),F(`Template "${n}" \u2014 annotations verified`)}}function Dl(t){let e=Ie(t,"modules");if(S(e))for(let n of Vt(e)){if(!n.endsWith(".module"))continue;let s=Ie(e,n,"meta.json");if(S(s))try{let o=JSON.parse(I(s)),i=!1;(!o.host_template_types||!o.host_template_types.includes("PAGE"))&&(o.host_template_types=["PAGE"],i=!0),o.is_available_for_new_content||(o.is_available_for_new_content=!0,i=!0),i&&H(s,JSON.stringify(o,null,2)+`
|
|
1341
|
+
`)}catch{}}}g();ct();import{join as hi,basename as zl}from"path";g();Z();import{join as oe}from"path";import{readdirSync as Ye,rmSync as Ll}from"fs";function jn(t){let e=[];for(let n of t){let s=`${n.message}${n.detail?` \u2014 ${n.detail}`:""}`,o=!1;/textarea|unknown.*field.*type/i.test(s)&&(o=!0),/reserved.*name|missing field name|field null/i.test(s)&&(o=!0),/could not resolve.*now/i.test(s)&&(o=!0),/hubdb|do not have access/i.test(s)&&(o=!0),/invalid default value|link.*invalid|deserializ/i.test(s)&&(o=!0),/color.*invalid/i.test(s)&&(o=!0),e.push({file:n.file||"unknown",message:s,fixable:o})}return e}function Fn(t){let e=[];if(/textarea.*not.*valid|unknown.*field.*type/i.test(t)){let n=t.match(/(?:in|file:?)\s+(\S+fields\.json)/i);e.push({file:n?.[1]||"fields.json",message:'"textarea" is not a valid field type',fixable:!0})}if(/missing field name|field null/i.test(t)){let n=t.match(/(?:in|file:?)\s+(\S+fields\.json)/i);e.push({file:n?.[1]||"fields.json",message:'"name" is a reserved field name',fixable:!0})}if(/could not resolve.*now/i.test(t)&&e.push({file:"module.html",message:"now() is not a valid HubL function",fixable:!0}),/hubdb|do not have access to hubdb/i.test(t)&&e.push({file:"templates",message:"HubDB requires CMS Hub Pro/Enterprise",fixable:!0}),/invalid default value|link.*field.*invalid/i.test(t)){let n=t.match(/field.*?(\w+)\s+has an invalid/i);e.push({file:n?.[1]||"fields.json",message:"Link field has invalid default value",fixable:!0})}if(/failed to deserialize/i.test(t)){let n=t.match(/file '([^']+)'/i);e.push({file:n?.[1]||"fields.json",message:"fields.json deserialization error",fixable:!0})}return/format for the color value is invalid/i.test(t)&&e.push({file:"fields.json",message:"Color field has invalid format (rgba/rgb/named \u2014 must be hex)",fixable:!0}),e}function Jn(t){let e=[];return ai(t)&&e.push("textarea \u2192 text"),li(t)&&e.push("name \u2192 item_name"),ci(t)&&e.push("now() \u2192 local_dt"),di(t)&&e.push("Removed HubDB templates"),ui(t)&&e.push("Fixed link field defaults"),mi(t)&&e.push("Fixed rgba/invalid color values \u2192 hex"),Hl(t)&&e.push("Stripped CDN @import statements"),e}function ri(t,e){return e.message.includes("textarea")?ai(t):e.message.includes("reserved field name")?li(t):e.message.includes("now()")?ci(t):e.message.includes("HubDB")?di(t):e.message.includes("invalid default value")||e.message.includes("deserialization")?ui(t):e.message.includes("invalid format")&&e.message.includes("color")?mi(t):!1}function ai(t){let e=!1,n=oe(t,"modules");if(!S(n))return!1;for(let s of Ye(n)){if(!s.endsWith(".module"))continue;let o=oe(n,s,"fields.json");if(!S(o))continue;let i=I(o);i.includes('"textarea"')&&(i=i.replace(/"textarea"/g,'"text"'),H(o,i),e=!0)}return e}function li(t){let e=!1,n=oe(t,"modules");if(!S(n))return!1;for(let s of Ye(n)){if(!s.endsWith(".module"))continue;let o=oe(n,s,"fields.json");if(!S(o))continue;let i=I(o);/"name":\s*"name"/g.test(i)&&(i=i.replace(/"name":\s*"name"/g,'"name": "item_name"'),H(o,i),e=!0)}return e}function ci(t){let e=!1,n=oe(t,"modules");if(!S(n))return!1;for(let s of Ye(n)){if(!s.endsWith(".module"))continue;let o=oe(n,s,"module.html");if(!S(o))continue;let i=I(o);i.includes("now()")&&(i=i.replace(/now\(\)/g,"local_dt"),H(o,i),e=!0)}return e}function di(t){let e=!1,n=oe(t,"templates");if(!S(n))return!1;for(let s of Ye(n)){if(!s.endsWith(".html"))continue;let o=oe(n,s),i=I(o);(i.includes("hubdb_table")||i.includes("hubdb_table_rows"))&&(Ll(o),e=!0)}return e}function ui(t){let e=!1,n=oe(t,"modules");if(!S(n))return!1;for(let s of Ye(n)){if(!s.endsWith(".module"))continue;let o=oe(n,s,"fields.json");if(S(o))try{let i=JSON.parse(I(o));fi(i)&&(H(o,JSON.stringify(i,null,2)+`
|
|
1342
|
+
`),e=!0)}catch{}}return e}function Hl(t){let e=!1,n=oe(t,"css");if(S(n))for(let o of Ye(n)){if(!o.endsWith(".css"))continue;let i=oe(n,o),a=I(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(H(i,r),e=!0)}let s=oe(t,"modules");if(S(s))for(let o of Ye(s)){if(!o.endsWith(".module"))continue;let i=oe(s,o,"module.css");if(!S(i))continue;let a=I(i),r=a.replace(/@import\s+url\(['"]?https?:\/\/[^)]+['"]?\)\s*;?/gi,"");r!==a&&(H(i,r),e=!0)}if(S(s))for(let o of Ye(s)){if(!o.endsWith(".module"))continue;let i=oe(s,o,"module.html");if(!S(i))continue;let a=I(i),r=a.replace(/<link[^>]+href=['"]https?:\/\/[^'"]+['"][^>]*>/gi,"");r!==a&&(H(i,r),e=!0)}return e}function mi(t){let e=!1,n=oe(t,"modules");if(!S(n))return!1;for(let s of Ye(n)){if(!s.endsWith(".module"))continue;let o=oe(n,s,"fields.json");if(S(o))try{let i=JSON.parse(I(o));pi(i)&&(H(o,JSON.stringify(i,null,2)+`
|
|
1343
|
+
`),e=!0)}catch{}}return e}function pi(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="color"&&s.default&&typeof s.default=="object"){let o=s.default,i=o.color;if(typeof i=="string"&&!Gl(i)){let a=Ul(i);a&&(o.color=a.hex,a.opacity!==void 0&&(o.opacity=a.opacity),e=!0)}}Array.isArray(s.children)&&pi(s.children)&&(e=!0)}return e}function Gl(t){return/^#[0-9a-fA-F]{6}$/.test(t)}function Ul(t){let e=t.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);if(e)return{hex:`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`};let n=t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/i);if(n){let i=Math.min(255,parseInt(n[1])),a=Math.min(255,parseInt(n[2])),r=Math.min(255,parseInt(n[3])),l=`#${i.toString(16).padStart(2,"0")}${a.toString(16).padStart(2,"0")}${r.toString(16).padStart(2,"0")}`,c=n[4]!==void 0?Math.round(parseFloat(n[4])*100):void 0;return{hex:l,opacity:c}}let s={white:"#ffffff",black:"#000000",red:"#ff0000",green:"#008000",blue:"#0000ff",yellow:"#ffff00",orange:"#ffa500",purple:"#800080",gray:"#808080",grey:"#808080",transparent:"#000000"},o=t.toLowerCase().trim();return s[o]?{hex:s[o],opacity:o==="transparent"?0:void 0}:null}function fi(t){let e=!1;for(let n of t){if(typeof n!="object"||n===null)continue;let s=n;if(s.type==="link"){let o=s.default;if(typeof o=="string"||o===void 0||o===null||typeof o=="object"&&!o.url){let a=typeof o=="string"?o:"";s.default={url:{href:a,type:"EXTERNAL"},open_in_new_tab:!1,no_follow:!1},e=!0}}Array.isArray(s.children)&&fi(s.children)&&(e=!0)}return e}ee();g();ut();ut();import{readdirSync as Wl}from"fs";import{join as Bl,relative as Kl}from"path";var Vl=new Set([".git","node_modules",".vibespot",".DS_Store"]);function gi(t){let e=[];for(let n of Wl(t,{withFileTypes:!0})){if(Vl.has(n.name)||n.name.startsWith(".")&&n.name!==".gitkeep")continue;let s=Bl(t,n.name);n.isDirectory()?e.push(...gi(s)):n.isFile()&&e.push(s)}return e}async function Yl(t,e,n){let s=0;async function o(){for(;s<t.length;){let a=s++;await n(t[a])}}let i=Array.from({length:Math.min(e,t.length)},()=>o());await Promise.all(i)}async function Dn(t,e,n,s={}){let o=s.concurrency??5,i=gi(e),a=i.length,r=0,l=0,c=[];return await Yl(i,o,async d=>{let u=Kl(e,d).replace(/\\/g,"/"),p=`${n}/${u}`;s.onFileStart?.(u);let f=await jo(t,p,d);if(f.success)r++,s.onFileComplete?.(u);else{l++;let h={file:u,status:f.error?.status||0,message:f.error?.message||"Unknown error",category:f.error?.category,detail:f.error?.detail};c.push(h),s.onFileError?.(u,h)}s.onProgress?.(r+l,a)}),{success:l===0,uploaded:r,failed:l,total:a,errors:c}}function ql(t){return(t.match(/^Uploaded file /gm)||[]).length}async function Ct(t){await ce("Uploading to HubSpot");let e=zl(t)||t,n=M(),s=he(),o=n.hubspotUploadMode!=="cli"&&!!s,i=await ue(),a=3;for(let r=1;r<=a;r++){i.start(r===1?"Uploading theme...":`Retrying upload (attempt ${r}/${a})...`);let l=[],c=0,d=!1;if(o){let p=await Dn(s,t,e,{onFileComplete:()=>{c++}});d=p.success,d?c=p.uploaded:l=jn(p.errors)}else{let p=T(`hs cms upload "${t}" "${e}"`,{cwd:hi(t,"..")}),f=[p.stdout,p.stderr].filter(Boolean).join(`
|
|
1344
|
+
`);c=ql(f),d=p.success,d||(l=Fn(f))}if(d)return i.stop(`All files uploaded! (${c} files)`),await de("Upload complete!"),!0;if(c>0?i.stop(`${c} files uploaded, but some errors occurred`):i.stop("Upload failed"),l.length===0){if(W("Upload failed with unknown error."),c>0&&(V(`Most files uploaded successfully. The theme may already be usable in HubSpot.
|
|
1345
|
+
You can check your HubSpot Design Manager to verify.`),await se({message:"Continue anyway (theme is likely uploaded)?",initialValue:!0})))return!0;if(r<a){if(!await se({message:"Try uploading again?"}))break;continue}break}let u=!1;for(let p of l)p.fixable?ri(t,p)?(F(`Auto-fixed: ${p.message}`),u=!0):V(`Could not auto-fix: ${p.message}`):W(p.message);if(!(u&&r<a)){if(c>0&&(V(`${c} files uploaded successfully despite errors.
|
|
1346
|
+
The theme may work \u2014 check HubSpot Design Manager.`),await se({message:"Continue anyway?",initialValue:!0})))return!0;if(!u){if(i.start("Cleaning up stuck modules..."),o)try{await xs(s,`${e}/modules`)}catch{}else T(`hs cms delete "${e}/modules"`,{cwd:hi(t,"..")});i.stop("Cleaned up modules, retrying...")}}}return W("Upload failed after multiple attempts."),!1}g();import{execFileSync as $s}from"child_process";import{rmSync as Xl}from"fs";import{basename as yi}from"path";Z();async function bi(t){let{portalId:e,sourceDir:n,themePath:s,wasCloned:o}=t;await ce("You're all set!");let a=Lt(e)==="eu1"?"app-eu1.hubspot.com":"app.hubspot.com";if(await je(`Your React page has been converted and uploaded to HubSpot.
|
|
1347
|
+
The theme and modules are now in your account, but you still
|
|
1348
|
+
need to ${k.bold("create a new landing page")} that uses them.
|
|
1349
|
+
|
|
1350
|
+
Next steps:
|
|
1351
|
+
|
|
1352
|
+
${k.bold("1.")} Go to HubSpot ${k.muted("\u2192")} Content ${k.muted("\u2192")} Landing Pages ${k.muted("\u2192")} Create
|
|
1353
|
+
${k.bold("2.")} Choose your uploaded theme from the theme picker
|
|
1354
|
+
${k.bold("3.")} Select the landing page template that was just created
|
|
1355
|
+
${k.bold("4.")} Your converted modules will appear \u2014 drag them onto the page
|
|
1356
|
+
${k.bold("5.")} Click each section to edit text, images, and colors
|
|
1357
|
+
${k.bold("6.")} Upload images via File Manager ${k.muted("(Settings \u2192 Files)")}
|
|
1358
|
+
${k.bold("7.")} Preview and publish!`,"What's next"),await se({message:"Open HubSpot Landing Pages in your browser?"})){let c=e?`https://${a}/page-ui/${e}/management/pages/landing`:`https://${a}`;try{let d=process.platform;d==="darwin"?$s("open",[c],{stdio:"ignore"}):d==="win32"?$s("cmd",["/c","start","",c],{stdio:"ignore"}):$s("xdg-open",[c],{stdio:"ignore"}),F("Opening HubSpot Landing Pages...")}catch{X(`Open this URL in your browser: ${k.info(c)}`)}}let l=[];if(o&&S(n)&&l.push({path:n,label:`Cloned source (${yi(n)})`}),S(s)&&l.push({path:s,label:`Theme directory (${yi(s)})`}),l.length>0&&await se({message:"Clean up local working directories?"}))for(let d of l)try{Xl(d.path,{recursive:!0,force:!0}),F(`Removed ${d.label}`)}catch{V(`Could not remove ${d.label} \u2014 delete manually if needed.`)}await de(`Thanks for using hub${k.vibes("Vibes")}! ${k.vibes("~")}`)}ee();async function Si(){_e();let t=await Cn(),e=await An();q({lastSourcePath:e.sourceDir});let n=await Tn();q({lastThemePath:n.themePath}),await On({aiEngine:t.aiEngine,model:t.model,sourceDir:e.sourceDir,themePath:n.themePath}),await Ct(n.themePath),await bi({portalId:t.portalId,sourceDir:e.sourceDir,themePath:n.themePath,wasCloned:e.wasCloned})}g();async function vi(){_e(),await Cn()}g();ee();async function wi(){_e();let t=M();t.aiEngine||(W("AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`."),process.exit(1));let e=await An(),n=await Tn();await On({aiEngine:t.aiEngine,sourceDir:e.sourceDir,themePath:n.themePath})}g();ee();async function xi(){_e();let t=M();if(t.lastThemePath)if(await se({message:`Upload from ${t.lastThemePath}?`}))await Ct(t.lastThemePath);else{let n=await $e({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme"});await Ct(n)}else{let e=await $e({message:"Path to your HubSpot theme directory:",placeholder:"./my-theme",validate:n=>n.trim()?void 0:"Path is required"});await Ct(e)}}g();ee();async function Ci(){_e(),await ce("Environment Diagnostics");let t=0,e=Ft();e.found?bn(e.version)?F(`Node.js v${e.version}`):(V(`Node.js v${e.version} \u2014 too old (need 18+)`),X(" Update at https://nodejs.org"),t++):(W("Node.js \u2014 not installed"),X(" Install from https://nodejs.org"),t++);let n=Jt();n.found?F(`Git ${n.version}`):(W("Git \u2014 not installed"),X(" Install from https://git-scm.com"),t++);let s=Re();if(!s.found)V("HubSpot CLI \u2014 not installed (only needed for deployment)"),X(" Install: npm install -g @hubspot/cli");else if(!_o(s.version))V(`HubSpot CLI v${s.version} \u2014 too old (need v8+)`),X(" Update: npm install -g @hubspot/cli@latest"),t++;else{F(`HubSpot CLI v${s.version}`);let p=Oe();p.authenticated?F(`HubSpot portal${p.portalName?`: ${p.portalName}`:""} (ID: ${p.portalId})`):(V("HubSpot \u2014 not authenticated"),X(" Run: hs init"))}let o=Dt();o.found?F(`Claude Code ${o.version} at ${o.path}`):X(k.muted("Claude Code \u2014 not installed"));let i=Ht();i.found?F(`Gemini CLI ${i.version} at ${i.path}`):X(k.muted("Gemini CLI \u2014 not installed"));let a=Gt();a.found?F(`OpenAI Codex ${a.version} at ${a.path}`):X(k.muted("OpenAI Codex \u2014 not installed"));let r=M(),l=!!(r.anthropicApiKey||process.env.ANTHROPIC_API_KEY),c=!!(r.openaiApiKey||process.env.OPENAI_API_KEY),d=!!(r.geminiApiKey||process.env.GEMINI_API_KEY||process.env.GOOGLE_AI_API_KEY);l?F("Anthropic API key configured"):X(k.muted("Anthropic API key \u2014 not set")),c?F("OpenAI API key configured"):X(k.muted("OpenAI API key \u2014 not set")),d?F("Google AI API key configured"):X(k.muted("Google AI API key \u2014 not set"));let u={"claude-code":"Claude Code",api:"Anthropic API","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-api":"Gemini API","gemini-cli":"Gemini CLI","codex-cli":"OpenAI Codex"};r.aiEngine&&F(`AI engine: ${u[r.aiEngine]||r.aiEngine}`),r.lastThemePath&&X(k.muted(`Last theme: ${r.lastThemePath}`)),!o.found&&!i.found&&!a.found&&!l&&!c&&!d&&(V("No AI engine available"),X(" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)"),X(" Or install: Claude Code \u2014 https://claude.ai/code"),X(" Gemini CLI \u2014 https://github.com/google-gemini/gemini-cli"),X(" Codex CLI \u2014 https://github.com/openai/codex"),t++),console.log(),t===0?await de("Everything looks good!"):await de(k.warn(`${t} issue${t>1?"s":""} found \u2014 see above`))}g();import{join as ps}from"path";import{existsSync as pu}from"fs";import{execFileSync as wo}from"child_process";import fs from"chalk";g();Se();Yt();zn();ns();ee();import{createServer as iu}from"http";import{readFileSync as vo,existsSync as cn}from"fs";import{join as at,extname as Qa}from"path";import{createHash as ru}from"crypto";import{WebSocketServer as au}from"ws";g();import{spawn as fo}from"child_process";var rt=new Map;function Vr(t,e,n){t.stdout?.on("data",o=>{e.output+=o.toString()}),t.stderr?.on("data",o=>{e.output+=o.toString()}),t.on("close",o=>{e.status=o===0?"completed":"failed",e.exitCode=o,e.completedAt=Date.now()}),t.on("error",o=>{e.status="failed",e.output+=`
|
|
1305
1359
|
Process error: ${o.message}`,e.completedAt=Date.now()}),setTimeout(()=>{e.status==="running"&&(t.kill(),e.status="failed",e.output+=`
|
|
1306
|
-
Process timed out`,e.completedAt=Date.now())},n||3e5)}function
|
|
1360
|
+
Process timed out`,e.completedAt=Date.now())},n||3e5)}function rn(t,e,n,s){let o=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,i={id:o,command:`${t} ${e.join(" ")}`,description:n,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null};rt.set(o,i);let a=fo(t,e,{cwd:s?.cwd,stdio:[s?.stdin?"pipe":"ignore","pipe","pipe"],env:{...process.env,...s?.env},shell:process.platform==="win32"});return s?.stdin&&a.stdin&&(a.stdin.write(s.stdin),a.stdin.end()),Vr(a,i,s?.timeout),o}function ht(t,e,n){let s=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,o={id:s,command:t,description:e,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null};rt.set(s,o);let i=t.split(" "),a=fo(i[0],i.slice(1),{cwd:n?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...n?.env},shell:!0});return Vr(a,o,n?.timeout),s}function ss(t){return rt.get(t)}function Nd(){let t=Date.now()-18e5;for(let[e,n]of rt)n.completedAt&&n.completedAt<t&&rt.delete(e)}setInterval(Nd,600*1e3);function os(t,e,n){let s=`job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,6)}`,o={id:s,command:t,description:e,status:"running",output:"",exitCode:null,startedAt:Date.now(),completedAt:null,listeners:new Set};rt.set(s,o);let i=t.split(" "),a=fo(i[0],i.slice(1),{cwd:n?.cwd,stdio:["ignore","pipe","pipe"],env:{...process.env,...n?.env},shell:!0}),r=c=>{for(let d of o.listeners)try{d(c)}catch{}};a.stdout?.on("data",c=>{let d=c.toString();o.output+=d,r(d)}),a.stderr?.on("data",c=>{let d=c.toString();o.output+=d,r(d)}),a.on("close",c=>{o.status=c===0?"completed":"failed",o.exitCode=c,o.completedAt=Date.now(),o.listeners.clear()}),a.on("error",c=>{o.status="failed",o.output+=`
|
|
1307
1361
|
Process error: ${c.message}`,o.completedAt=Date.now(),o.listeners.clear()});let l=n?.timeout||3e5;return setTimeout(()=>{o.status==="running"&&(a.kill(),o.status="failed",o.output+=`
|
|
1308
|
-
Process timed out`,o.completedAt=Date.now(),o.listeners.clear())},l),s}function mr(t,e){let n=Qe.get(t);if(!n||!("listeners"in n))return;let s=n;if(s.output)try{e(s.output)}catch{}s.listeners.add(e)}function pr(t,e){let n=Qe.get(t);!n||!("listeners"in n)||n.listeners.delete(e)}Q();g();import{existsSync as Ct,readdirSync as fr,rmSync as Bc}from"fs";import{join as At,basename as Vc}from"path";import{homedir as Kc}from"os";import{execFileSync as gr}from"child_process";te();pn();tt();te();Q();var hr=process.platform==="win32"?{shell:!0}:{},$e=At(Kc(),"vibespot-themes"),Hn=null,Yc=5e3;function Ln(){if(Hn&&Date.now()-Hn.ts<Yc)return Hn.data;let t=[];if(Ct($e))try{for(let e of fr($e,{withFileTypes:!0}))if(e.isDirectory()){let n=At($e,e.name,"theme.json");if(Ct(n)){let s=0,o=At($e,e.name,"modules");if(Ct(o))try{s=fr(o,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}t.push({name:e.name,moduleCount:s})}}}catch{}return Hn={data:t,ts:Date.now()},t}function yr(t){let e=v(),n=on(),s=!1;try{gr("hs",["--version"],{encoding:"utf-8",stdio:"pipe",...hr}),s=!0}catch{}let o=bt().sort((a,r)=>r.updatedAt-a.updatedAt).slice(0,10),i=Ln();m(t,200,{hasActiveSession:!!e,activeSession:e?{id:e.id,themeName:e.themeName,moduleCount:e.modules.length}:null,hsInstalled:s,aiAvailable:n.availableEngines.length>0,availableEngines:n.availableEngines,activeEngine:n.activeEngine,sessions:o,localThemes:i})}function br(t,e){j(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=s.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,""),i=At($e,o);we($e),Ct(i)&&Bc(i,{recursive:!0,force:!0}),mn(i,o),Ft(i,o),D(),m(e,200,{ok:!0,themeName:o,themePath:i})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Sr(t,e){j(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=s.replace(/^\/+|\/+$/g,"");if(!o){m(e,400,{error:"Theme name is required"});return}let i=he(),a=_(),r=o.includes("/")||o.includes("@")?o.replace(/[@/]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""):o,l=At($e,r);we($e),a.hubspotUploadMode==="cli"||!i?(gr("hs",["cms","fetch",o,l],{encoding:"utf-8",stdio:"pipe",...hr}),Ft(l,r),Ht(l),D(),m(e,200,{ok:!0,themeName:r,themePath:l,moduleCount:v()?.modules.length||0})):Rt(i,o,l).then(()=>{Ft(l,r),Ht(l),D(),m(e,200,{ok:!0,themeName:r,themePath:l,moduleCount:v()?.modules.length||0})}).catch(c=>{m(e,500,{error:c instanceof Error?c.message:String(c)})})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function vr(t,e){j(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{path:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme path is required"});return}let o=s;if(Ct(o)||(o=At($e,s)),!Ct(o)){m(e,400,{error:`Theme folder not found: ${s}`});return}let i=Vc(o);Ft(o,i),Ht(o),D(),m(e,200,{ok:!0,themeName:i,themePath:o,moduleCount:v()?.modules.length||0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function wr(t,e){j(t,n=>{try{if(Wt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{sessionId:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Session ID is required"});return}let o=_n(s);if(!o){m(e,404,{error:"Session not found"});return}m(e,200,{ok:!0,themeName:o.themeName,themePath:o.themePath,moduleCount:o.modules.length,messageCount:o.messages.length})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function xr(t,e){j(t,n=>{try{let{apiKey:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"API key is required"});return}z({anthropicApiKey:s}),m(e,200,{ok:!0})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Cr(t){let e=he();if(!e){m(t,200,{themes:[],error:"No HubSpot account connected"});return}(async()=>{let n=await uo(e);if(n.length===0){m(t,200,{themes:[]});return}let s=[],o=n.map(async r=>{let l=r.path||r.name;try{let c=await ln(e,`${l}/theme.json`);c&&!c.folder&&s.push({name:r.name,path:l})}catch{}});await Promise.all(o),s.sort((r,l)=>r.name.localeCompare(l.name));let i=Ln(),a=new Set(i.map(r=>r.name));m(t,200,{themes:s.map(r=>({...r,existsLocally:a.has(r.name)}))})})().catch(n=>{m(t,200,{themes:[],error:n instanceof Error?n.message:String(n)})})}g();import{existsSync as zc,readFileSync as qc,appendFileSync as Xc}from"fs";import{join as Ar}from"path";import{homedir as Ir}from"os";te();tt();Q();var Vt={data:{},ts:0},Qc=600*1e3,kr={"claude-code":[{id:"sonnet",label:"Claude Sonnet (default)"},{id:"opus",label:"Claude Opus"},{id:"haiku",label:"Claude Haiku"}],"codex-cli":[{id:"o4-mini",label:"o4 Mini (default)"},{id:"o3",label:"o3"},{id:"gpt-4o",label:"GPT-4o"}]};async function Zc(t){let e=await fetch("https://api.anthropic.com/v1/models",{headers:{"x-api-key":t,"anthropic-version":"2023-06-01"}});return e.ok?(await e.json()).data.filter(s=>!s.id.startsWith("claude-3-")&&!s.id.startsWith("claude-2")).map(s=>({id:s.id,label:s.display_name})):[]}async function ed(t){let e=await fetch("https://api.openai.com/v1/models",{headers:{Authorization:`Bearer ${t}`}});if(!e.ok)return[];let n=await e.json(),s=/^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;return n.data.filter(o=>s.test(o.id)).sort((o,i)=>o.id.localeCompare(i.id)).map(o=>({id:o.id,label:o.id}))}async function td(t){let e=await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${t}`);return e.ok?(await e.json()).models.filter(s=>s.name.includes("gemini-2")).map(s=>({id:s.name.replace("models/",""),label:s.displayName})):[]}async function nd(){if(Date.now()-Vt.ts<Qc&&Object.keys(Vt.data).length>0)return Vt.data;let t=_(),e={...kr},n=[],s=ge("anthropic-api",t);s&&n.push(Zc(s).then(a=>{a.length&&(e["anthropic-api"]=a)}).catch(()=>{}));let o=ge("openai-api",t);o&&n.push(ed(o).then(a=>{a.length&&(e["openai-api"]=a)}).catch(()=>{}));let i=ge("gemini-api",t);return i&&n.push(td(i).then(a=>{a.length&&(e["gemini-api"]=a,e["gemini-cli"]=a)}).catch(()=>{})),await Promise.all(n),Vt.data=e,Vt.ts=Date.now(),e}function $r(t){let e=on(),n=_(),s={aiEngine:n.aiEngine||null,claudeCodeModel:n.claudeCodeModel||null,anthropicApiModel:n.anthropicApiModel||null,openaiApiModel:n.openaiApiModel||null,hubspotUploadMode:n.hubspotUploadMode||"api",hubspotAccounts:(n.hubspotAccounts||[]).map(r=>({portalId:r.portalId,portalName:r.portalName,dataCenter:r.dataCenter})),activeHubSpotAccount:n.activeHubSpotAccount||null,enabledCLITools:n.enabledCLITools||[],agenticMode:n.agenticMode,agenticConcurrency:n.agenticConcurrency},o=bt().length,i=Ln().length,a=ut();nd().then(r=>{m(t,200,{version:a,environment:e,config:s,models:r,sessionCount:o,localThemeCount:i})}).catch(()=>{m(t,200,{version:a,environment:e,config:s,models:kr,sessionCount:o,localThemeCount:i})})}function Tr(t,e){j(t,n=>{try{let{engine:s,model:o}=JSON.parse(n);if(!["claude-code","anthropic-api","openai-api","gemini-cli","gemini-api","codex-cli"].includes(s)){m(e,400,{error:`Invalid engine: ${s}`});return}let a={aiEngine:s};if(o)switch(s){case"claude-code":a.claudeCodeModel=o;break;case"anthropic-api":a.anthropicApiModel=o;break;case"openai-api":a.openaiApiModel=o;break}z(a),m(e,200,{ok:!0,engine:s})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Er(t,e){j(t,n=>{try{let{provider:s,apiKey:o}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"provider is required"});return}if(!o){let l={};switch(s){case"anthropic":l.anthropicApiKey="";break;case"openai":l.openaiApiKey="";break;case"gemini":l.geminiApiKey="";break;default:m(e,400,{error:`Unknown provider: ${s}`});return}z(l),m(e,200,{ok:!0,provider:s,deleted:!0});return}let i={};switch(s){case"anthropic":i.anthropicApiKey=o;break;case"openai":i.openaiApiKey=o;break;case"gemini":i.geminiApiKey=o;break;default:m(e,400,{error:`Unknown provider: ${s}`});return}z(i);let a=null;if(!_().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[s];c&&(z({aiEngine:c}),a=c)}m(e,200,{ok:!0,provider:s,autoSelectedEngine:a})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Mr(t,e){j(t,n=>{try{let{tool:s}=JSON.parse(n),o={hubspot:{cmd:"npm install -g @hubspot/cli",desc:"Installing HubSpot CLI"},claude:{cmd:"npm install -g @anthropic-ai/claude-code",desc:"Installing Claude Code"},gemini:{cmd:"npm install -g @google/gemini-cli",desc:"Installing Gemini CLI"},codex:{cmd:process.platform==="darwin"?"brew install --cask codex":"npm install -g @openai/codex",desc:"Installing OpenAI Codex"},gh:{cmd:process.platform==="darwin"?"brew install gh":"npm install -g @cli/gh",desc:"Installing GitHub CLI"}},i=o[s];if(!i){m(e,400,{error:`Unknown tool: ${s}. Valid: ${Object.keys(o).join(", ")}`});return}let a=at(i.cmd,i.desc,{timeout:12e4});m(e,200,{ok:!0,jobId:a})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Nr(t,e){j(t,n=>{try{let s=JSON.parse(n||"{}"),o=_(),i=o.hubspotUploadMode||"api";if(s.personalAccessKey)if(i==="api"){an(s.personalAccessKey).then(a=>{Qt(s.personalAccessKey,a.portalId,a.portalName,a.dataCenter),m(e,200,{ok:!0,portalName:a.portalName,portalId:a.portalId,dataCenter:a.dataCenter})}).catch(a=>{m(e,400,{error:a instanceof Error?a.message:String(a)})});return}else{if(!Me().found){m(e,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Bt("hs",["auth",`--pak=${s.personalAccessKey}`],"Authenticating with HubSpot",{timeout:3e4});m(e,200,{ok:!0,jobId:r});return}if(i==="api"){let a=o.hubspotAccounts||[];if(a.length>0&&!s.force){let r=a.find(l=>l.portalId===o.activeHubSpotAccount)||a[0];m(e,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}else{if(!Me().found){m(e,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Ne();if(r.authenticated&&!s.force){m(e,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}m(e,200,{needsKey:!0,instructions:"Create a personal access key in HubSpot",url:"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key",steps:["Click the link above to open HubSpot","Select your account","Create a Personal Access Key with CMS permissions","Copy the key and paste it below"]})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function _r(t,e){j(t,n=>{try{let s=JSON.parse(n||"{}");if(!Qn().found){m(e,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=Zn();if(i.authenticated&&!s.force){m(e,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(s.token){let r=Bt("gh",["auth","login","--with-token"],"Authenticating with GitHub",{timeout:3e4,stdin:s.token});m(e,200,{ok:!0,jobId:r});return}let a=at("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});m(e,200,{ok:!0,jobId:a,browserAuthRequired:!0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Pr(t,e){j(t,n=>{try{let{portalId:s,action:o}=JSON.parse(n);if((_().hubspotUploadMode||"api")==="api"){if(o==="remove"&&s){eo(s),m(e,200,{ok:!0});return}if(s){to(s),m(e,200,{ok:!0});return}}else{if(!Me().found){m(e,400,{error:"HubSpot CLI not installed"});return}let l=String(s).replace(/[^0-9]/g,"");if(!l){m(e,400,{error:"Invalid portalId"});return}if(o==="remove"){let c=Bt("hs",["accounts","remove",l],`Removing HubSpot account ${l}`,{timeout:15e3});m(e,200,{ok:!0,jobId:c});return}if(l){let c=Bt("hs",["accounts","use",l],`Switching to HubSpot account ${l}`,{timeout:15e3});m(e,200,{ok:!0,jobId:c});return}}m(e,400,{error:"portalId required"})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Rr(t){let e=at("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});m(t,200,{ok:!0,jobId:e})}function Or(t,e){j(t,n=>{try{let{cli:s,apiKey:o}=JSON.parse(n||"{}");switch(s){case"claude":{let i=at("CLAUDECODE= claude --print -p 'reply OK'","Authenticating Claude Code (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"If Claude Code opens a browser window, complete the sign-in there."});break}case"gemini":{let i=at("gemini -p 'reply OK'","Authenticating Gemini CLI (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"If Gemini opens a browser window, complete the sign-in there."});break}case"codex":{if(o&&o.trim()){let i=o.trim();if(process.env.OPENAI_API_KEY=i,z({openaiApiKey:i}),process.platform!=="win32"){let a=/^[A-Za-z0-9_\-.:]+$/.test(i)?i:"";if(a){let r=`export OPENAI_API_KEY="${a}"`,l=process.env.SHELL?.includes("zsh")?Ar(Ir(),".zshrc"):Ar(Ir(),".bashrc");try{(zc(l)?qc(l,"utf-8"):"").includes("OPENAI_API_KEY")||Xc(l,`
|
|
1362
|
+
Process timed out`,o.completedAt=Date.now(),o.listeners.clear())},l),s}function Yr(t,e){let n=rt.get(t);if(!n||!("listeners"in n))return;let s=n;if(s.output)try{e(s.output)}catch{}s.listeners.add(e)}function zr(t,e){let n=rt.get(t);!n||!("listeners"in n)||n.listeners.delete(e)}ot();Z();g();ot();ee();import{existsSync as Pt,readdirSync as qr,rmSync as Md}from"fs";import{join as _t,basename as Pd}from"path";import{homedir as _d}from"os";import{execFileSync as Xr}from"child_process";$n();ut();Se();ns();ee();Z();var Qr=process.platform==="win32"?{shell:!0}:{},Me=_t(_d(),"vibespot-themes"),is=null,Rd=5e3;function rs(){if(is&&Date.now()-is.ts<Rd)return is.data;let t=[];if(Pt(Me))try{for(let e of qr(Me,{withFileTypes:!0}))if(e.isDirectory()){let n=_t(Me,e.name,"theme.json");if(Pt(n)){let s=0,o=_t(Me,e.name,"modules");if(Pt(o))try{s=qr(o,{withFileTypes:!0}).filter(i=>i.isDirectory()).length}catch{}t.push({name:e.name,moduleCount:s})}}}catch{}return is={data:t,ts:Date.now()},t}function Zr(t){let e=v(),n=Sn(),s=!1;try{Xr("hs",["--version"],{encoding:"utf-8",stdio:"pipe",...Qr}),s=!0}catch{}let o=kt().sort((a,r)=>r.updatedAt-a.updatedAt).slice(0,10),i=rs();m(t,200,{hasActiveSession:!!e,activeSession:e?{id:e.id,themeName:e.themeName,moduleCount:e.modules.length}:null,hsInstalled:s,aiAvailable:n.availableEngines.length>0,availableEngines:n.availableEngines,activeEngine:n.activeEngine,sessions:o,localThemes:i})}function ea(t,e){j(t,n=>{try{if(Mt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=s.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,""),i=_t(Me,o);Ae(Me),Pt(i)&&Md(i,{recursive:!0,force:!0}),kn(i,o),Xt(i,o),D(),m(e,200,{ok:!0,themeName:o,themePath:i})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function ta(t,e){j(t,n=>{try{if(Mt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{name:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=s.replace(/^\/+|\/+$/g,"");if(!o){m(e,400,{error:"Theme name is required"});return}let i=he(),a=M(),r=o.includes("/")||o.includes("@")?o.replace(/[@/]/g,"_").replace(/_+/g,"_").replace(/^_|_$/g,""):o,l=_t(Me,r);Ae(Me),a.hubspotUploadMode==="cli"||!i?(Xr("hs",["cms","fetch",o,l],{encoding:"utf-8",stdio:"pipe",...Qr}),Xt(l,r),en(l),D(),m(e,200,{ok:!0,themeName:r,themePath:l,moduleCount:v()?.modules.length||0})):Bt(i,o,l).then(()=>{Xt(l,r),en(l),D(),m(e,200,{ok:!0,themeName:r,themePath:l,moduleCount:v()?.modules.length||0})}).catch(c=>{m(e,500,{error:c instanceof Error?c.message:String(c)})})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function na(t,e){j(t,n=>{try{if(Mt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{path:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme path is required"});return}let o=s;if(Pt(o)||(o=_t(Me,s)),!Pt(o)){m(e,400,{error:`Theme folder not found: ${s}`});return}let i=Pd(o);Xt(o,i),en(o),D(),m(e,200,{ok:!0,themeName:i,themePath:o,moduleCount:v()?.modules.length||0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function sa(t,e){j(t,n=>{try{if(Mt()){m(e,409,{error:"Cannot switch projects while AI is generating.",generating:!0});return}let{sessionId:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Session ID is required"});return}let o=Vn(s);if(!o){m(e,404,{error:"Session not found"});return}m(e,200,{ok:!0,themeName:o.themeName,themePath:o.themePath,moduleCount:o.modules.length,messageCount:o.messages.length})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function oa(t,e){j(t,n=>{try{let{apiKey:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"API key is required"});return}q({anthropicApiKey:s}),m(e,200,{ok:!0})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function ia(t){let e=he();if(!e){m(t,200,{themes:[],error:"No HubSpot account connected"});return}(async()=>{let n=await Jo(e);if(n.length===0){m(t,200,{themes:[]});return}let s=[],o=n.map(async r=>{let l=r.path||r.name;try{let c=await xn(e,`${l}/theme.json`);c&&!c.folder&&s.push({name:r.name,path:l})}catch{}});await Promise.all(o),s.sort((r,l)=>r.name.localeCompare(l.name));let i=rs(),a=new Set(i.map(r=>r.name));m(t,200,{themes:s.map(r=>({...r,existsLocally:a.has(r.name)}))})})().catch(n=>{m(t,200,{themes:[],error:n instanceof Error?n.message:String(n)})})}g();ot();ee();Se();import{existsSync as Od,readFileSync as jd,appendFileSync as Fd}from"fs";import{join as ra}from"path";import{homedir as aa}from"os";ut();Z();var an={data:{},ts:0},Jd=600*1e3,la={"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 Dd(t){let e=await fetch("https://api.anthropic.com/v1/models",{headers:{"x-api-key":t,"anthropic-version":"2023-06-01"}});return e.ok?(await e.json()).data.filter(s=>!s.id.startsWith("claude-3-")&&!s.id.startsWith("claude-2")).map(s=>({id:s.id,label:s.display_name})):[]}async function Ld(t){let e=await fetch("https://api.openai.com/v1/models",{headers:{Authorization:`Bearer ${t}`}});if(!e.ok)return[];let n=await e.json(),s=/^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;return n.data.filter(o=>s.test(o.id)).sort((o,i)=>o.id.localeCompare(i.id)).map(o=>({id:o.id,label:o.id}))}async function Hd(t){let e=await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${t}`);return e.ok?(await e.json()).models.filter(s=>s.name.includes("gemini-2")).map(s=>({id:s.name.replace("models/",""),label:s.displayName})):[]}async function Gd(){if(Date.now()-an.ts<Jd&&Object.keys(an.data).length>0)return an.data;let t=M(),e={...la},n=[],s=ge("anthropic-api",t);s&&n.push(Dd(s).then(a=>{a.length&&(e["anthropic-api"]=a)}).catch(()=>{}));let o=ge("openai-api",t);o&&n.push(Ld(o).then(a=>{a.length&&(e["openai-api"]=a)}).catch(()=>{}));let i=ge("gemini-api",t);return i&&n.push(Hd(i).then(a=>{a.length&&(e["gemini-api"]=a,e["gemini-cli"]=a)}).catch(()=>{})),await Promise.all(n),an.data=e,an.ts=Date.now(),e}function ca(t){let e=Sn(),n=M(),s={aiEngine:n.aiEngine||null,claudeCodeModel:n.claudeCodeModel||null,anthropicApiModel:n.anthropicApiModel||null,openaiApiModel:n.openaiApiModel||null,hubspotUploadMode:n.hubspotUploadMode||"api",hubspotAccounts:(n.hubspotAccounts||[]).map(r=>({portalId:r.portalId,portalName:r.portalName,dataCenter:r.dataCenter})),activeHubSpotAccount:n.activeHubSpotAccount||null,enabledCLITools:n.enabledCLITools||[],agenticMode:n.agenticMode,agenticConcurrency:n.agenticConcurrency},o=kt().length,i=rs().length,a=St();Gd().then(r=>{m(t,200,{version:a,environment:e,config:s,models:r,sessionCount:o,localThemeCount:i})}).catch(()=>{m(t,200,{version:a,environment:e,config:s,models:la,sessionCount:o,localThemeCount:i})})}function da(t,e){j(t,n=>{try{let{engine:s,model:o}=JSON.parse(n);if(!["claude-code","anthropic-api","openai-api","gemini-cli","gemini-api","codex-cli"].includes(s)){m(e,400,{error:`Invalid engine: ${s}`});return}let a={aiEngine:s};if(o)switch(s){case"claude-code":a.claudeCodeModel=o;break;case"anthropic-api":a.anthropicApiModel=o;break;case"openai-api":a.openaiApiModel=o;break}q(a),m(e,200,{ok:!0,engine:s})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function ua(t,e){j(t,n=>{try{let{provider:s,apiKey:o}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"provider is required"});return}if(!o){let l={};switch(s){case"anthropic":l.anthropicApiKey="";break;case"openai":l.openaiApiKey="";break;case"gemini":l.geminiApiKey="";break;default:m(e,400,{error:`Unknown provider: ${s}`});return}q(l),m(e,200,{ok:!0,provider:s,deleted:!0});return}let i={};switch(s){case"anthropic":i.anthropicApiKey=o;break;case"openai":i.openaiApiKey=o;break;case"gemini":i.geminiApiKey=o;break;default:m(e,400,{error:`Unknown provider: ${s}`});return}q(i);let a=null;if(!M().aiEngine){let c={anthropic:"anthropic-api",openai:"openai-api",gemini:"gemini-api"}[s];c&&(q({aiEngine:c}),a=c)}m(e,200,{ok:!0,provider:s,autoSelectedEngine:a})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function ma(t,e){j(t,n=>{try{let{tool:s}=JSON.parse(n),o={hubspot:{cmd:"npm install -g @hubspot/cli",desc:"Installing HubSpot CLI"},claude:{cmd:"npm install -g @anthropic-ai/claude-code",desc:"Installing Claude Code"},gemini:{cmd:"npm install -g @google/gemini-cli",desc:"Installing Gemini CLI"},codex:{cmd:process.platform==="darwin"?"brew install --cask codex":"npm install -g @openai/codex",desc:"Installing OpenAI Codex"},gh:{cmd:process.platform==="darwin"?"brew install gh":"npm install -g @cli/gh",desc:"Installing GitHub CLI"}},i=o[s];if(!i){m(e,400,{error:`Unknown tool: ${s}. Valid: ${Object.keys(o).join(", ")}`});return}let a=ht(i.cmd,i.desc,{timeout:12e4});m(e,200,{ok:!0,jobId:a})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function pa(t,e){j(t,n=>{try{let s=JSON.parse(n||"{}"),o=M(),i=o.hubspotUploadMode||"api";if(s.personalAccessKey)if(i==="api"){wn(s.personalAccessKey).then(a=>{Ot(s.personalAccessKey,a.portalId,a.portalName,a.dataCenter),m(e,200,{ok:!0,portalName:a.portalName,portalId:a.portalId,dataCenter:a.dataCenter})}).catch(a=>{m(e,400,{error:a instanceof Error?a.message:String(a)})});return}else{if(!Re().found){m(e,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=rn("hs",["auth",`--pak=${s.personalAccessKey}`],"Authenticating with HubSpot",{timeout:3e4});m(e,200,{ok:!0,jobId:r});return}if(i==="api"){let a=o.hubspotAccounts||[];if(a.length>0&&!s.force){let r=a.find(l=>l.portalId===o.activeHubSpotAccount)||a[0];m(e,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}else{if(!Re().found){m(e,400,{error:"HubSpot CLI not installed",needsInstall:!0});return}let r=Oe();if(r.authenticated&&!s.force){m(e,200,{ok:!0,alreadyAuthenticated:!0,portalName:r.portalName,portalId:r.portalId});return}}m(e,200,{needsKey:!0,instructions:"Create a personal access key in HubSpot",url:"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key",steps:["Click the link above to open HubSpot","Select your account","Create a Personal Access Key with CMS permissions","Copy the key and paste it below"]})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function fa(t,e){j(t,n=>{try{let s=JSON.parse(n||"{}");if(!vs().found){m(e,400,{error:"GitHub CLI not installed",needsInstall:!0});return}let i=ws();if(i.authenticated&&!s.force){m(e,200,{ok:!0,alreadyAuthenticated:!0,username:i.username});return}if(s.token){let r=rn("gh",["auth","login","--with-token"],"Authenticating with GitHub",{timeout:3e4,stdin:s.token});m(e,200,{ok:!0,jobId:r});return}let a=ht("gh auth login --web --git-protocol https","GitHub authentication (check your browser)",{timeout:3e5});m(e,200,{ok:!0,jobId:a,browserAuthRequired:!0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function ga(t,e){j(t,n=>{try{let{portalId:s,action:o}=JSON.parse(n);if((M().hubspotUploadMode||"api")==="api"){if(o==="remove"&&s){hs(s),m(e,200,{ok:!0});return}if(s){ys(s),m(e,200,{ok:!0});return}}else{if(!Re().found){m(e,400,{error:"HubSpot CLI not installed"});return}let l=String(s).replace(/[^0-9]/g,"");if(!l){m(e,400,{error:"Invalid portalId"});return}if(o==="remove"){let c=rn("hs",["accounts","remove",l],`Removing HubSpot account ${l}`,{timeout:15e3});m(e,200,{ok:!0,jobId:c});return}if(l){let c=rn("hs",["accounts","use",l],`Switching to HubSpot account ${l}`,{timeout:15e3});m(e,200,{ok:!0,jobId:c});return}}m(e,400,{error:"portalId required"})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function ha(t){let e=ht("gh auth logout --hostname github.com -y","Logging out of GitHub",{timeout:15e3});m(t,200,{ok:!0,jobId:e})}function ya(t,e){j(t,n=>{try{let{cli:s,apiKey:o}=JSON.parse(n||"{}");switch(s){case"claude":{let i=ht("CLAUDECODE= claude --print -p 'reply OK'","Authenticating Claude Code (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"If Claude Code opens a browser window, complete the sign-in there."});break}case"gemini":{let i=ht("gemini -p 'reply OK'","Authenticating Gemini CLI (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"If Gemini opens a browser window, complete the sign-in there."});break}case"codex":{if(o&&o.trim()){let i=o.trim();if(process.env.OPENAI_API_KEY=i,q({openaiApiKey:i}),process.platform!=="win32"){let a=/^[A-Za-z0-9_\-.:]+$/.test(i)?i:"";if(a){let r=`export OPENAI_API_KEY="${a}"`,l=process.env.SHELL?.includes("zsh")?ra(aa(),".zshrc"):ra(aa(),".bashrc");try{(Od(l)?jd(l,"utf-8"):"").includes("OPENAI_API_KEY")||Fd(l,`
|
|
1309
1363
|
# Added by vibeSpot
|
|
1310
1364
|
${r}
|
|
1311
|
-
`)}catch{}}}m(e,200,{ok:!0,message:"API key saved"})}else{let i=at("codex login","Authenticating Codex CLI (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"Complete the sign-in in your browser."})}break}default:m(e,400,{error:`Unknown CLI: ${s}`})}}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function jr(t,e){j(t,n=>{try{let{mode:s}=JSON.parse(n);if(s!=="api"&&s!=="cli"){m(e,400,{error:`Invalid mode: ${s}. Must be "api" or "cli".`});return}z({hubspotUploadMode:s}),m(e,200,{ok:!0,mode:s})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Fr(t,e){j(t,n=>{try{let{toolId:s,enabled:o}=JSON.parse(n);if(!s||typeof o!="boolean"){m(e,400,{error:"toolId (string) and enabled (boolean) required"});return}no(s,o),m(e,200,{ok:!0,toolId:s,enabled:o})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Jr(t,e){j(t,n=>{try{let s=JSON.parse(n),o=["agenticMode","agenticConcurrency"],i={};for(let a of o)a in s&&(i[a]=s[a]);if(Object.keys(i).length===0){m(e,400,{error:"No valid settings fields provided"});return}z(i),m(e,200,{ok:!0,updated:Object.keys(i)})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Dr(t,e){let n=t.replace("/api/settings/job/","");if(!n){m(e,400,{error:"Job ID required"});return}let s=Jn(n);if(!s){m(e,404,{error:"Job not found"});return}m(e,200,{id:s.id,status:s.status,description:s.description,output:s.output,exitCode:s.exitCode,startedAt:s.startedAt,completedAt:s.completedAt})}g();import{existsSync as sd,rmSync as od}from"fs";import{join as id}from"path";function Hr(t,e,n){if(t==="GET"){let s=v(),o=bt().sort((i,a)=>a.updatedAt-i.updatedAt);m(n,200,{activeTheme:s?{id:s.id,themeName:s.themeName}:null,sessions:o});return}if(t==="DELETE"){j(e,s=>{try{let{sessionId:o,deleteFiles:i}=JSON.parse(s);gi(o,i),m(n,200,{ok:!0})}catch(o){m(n,500,{error:o instanceof Error?o.message:String(o)})}});return}m(n,405,{error:"Method not allowed"})}function Lr(t,e){j(t,n=>{try{let{sessionId:s}=JSON.parse(n),o=_n(s);if(!o){m(e,404,{error:"Session not found"});return}m(e,200,{ok:!0,themeName:o.themeName,themePath:o.themePath})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Gr(t,e){j(t,n=>{try{let{themeName:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=id($e,s);if(!sd(o)){m(e,404,{error:"Theme not found on disk"});return}od(o,{recursive:!0,force:!0}),m(e,200,{ok:!0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Ur(t,e){j(t,n=>{try{let{sessionId:s,newName:o}=JSON.parse(n);if(!s||!o||typeof o!="string"){m(e,400,{error:"sessionId and newName are required"});return}let i=o.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-|-$/g,"").replace(/-{2,}/g,"-");if(!i){m(e,400,{error:"Invalid name"});return}let a=hi(s,i);a.ok?m(e,200,{ok:!0,newName:i}):m(e,400,{error:a.error})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}g();import{existsSync as Bn,readFileSync as md,rmSync as Gs}from"fs";import{join as Je,basename as pd}from"path";import{execFileSync as fd}from"child_process";te();Q();var gd=process.platform==="win32"?{shell:!0}:{};function Br(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}let n=qe();m(t,200,{themeName:e.themeName,themePath:e.themePath,templates:e.templates.map(s=>({id:s.id,label:s.label,pageType:s.pageType,moduleCount:s.modules.length,messageCount:s.messages.length})),activeTemplateId:e.activeTemplateId,moduleLibrary:n.map(s=>({moduleName:s.module.moduleName,usedIn:s.usedIn})),brandAssets:{hasStyleguide:!!e.brandAssets?.styleguide,hasBrandvoice:!!e.brandAssets?.brandvoice,humanify:e.brandAssets?.humanify!==!1}})}function Vr(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}let n=e.themePath;if(!Bn(n)){m(t,404,{error:"Theme directory not found"});return}let s=e.themeName||"theme",o=Je(n,".."),i=pd(n);try{let a=`${s}.zip`,r=Je(o,a);Bn(r)&&Gs(r),fd("zip",["-r",a,i,"-x",`${i}/.git/*`,`${i}/.vibespot/*`,`${i}/node_modules/*`],{cwd:o,timeout:3e4,...gd});let l=md(r);Gs(r),t.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${a}"`,"Content-Length":l.length}),t.end(l)}catch(a){N.error("download-zip","Failed to create zip archive",a),m(t,500,{error:"Failed to create zip archive"})}}function Kr(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){m(n,200,{templates:s.templates.map(o=>({id:o.id,label:o.label,pageType:o.pageType,moduleCount:o.modules.length})),activeTemplateId:s.activeTemplateId});return}if(t==="POST"){j(e,o=>{try{let{pageType:i,label:a}=JSON.parse(o);if(!i||!a){m(n,400,{error:"pageType and label are required"});return}if(!["landing_page","blog_post","website_page","module_only"].includes(i)){m(n,400,{error:`Invalid pageType: ${i}`});return}let l=di(i,a);D(),m(n,200,{ok:!0,template:{id:l.id,label:l.label,pageType:l.pageType}})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}if(t==="DELETE"){j(e,o=>{try{let{templateId:i}=JSON.parse(o);if(!i){m(n,400,{error:"templateId is required"});return}if(!pi(i)){m(n,404,{error:"Template not found"});return}D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}m(n,405,{error:"Method not allowed"})}function Yr(t,e){j(t,n=>{try{let{templateId:s}=JSON.parse(n);if(!s){m(e,400,{error:"templateId is required"});return}if(!ls(s)){m(e,404,{error:"Template not found"});return}D();let i=v();m(e,200,{ok:!0,modules:ue().map(a=>a.moduleName),messageCount:i?.messages.length||0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function zr(t,e){j(t,n=>{try{let{templateId:s,newLabel:o}=JSON.parse(n);if(!s||!o||typeof o!="string"){m(e,400,{error:"templateId and newLabel are required"});return}if(!mi(s,o.trim())){m(e,404,{error:"Template not found"});return}D(),m(e,200,{ok:!0,newLabel:o.trim()})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function qr(t,e){j(t,n=>{try{let{templateId:s,label:o}=JSON.parse(n);if(!s){m(e,400,{error:"templateId is required"});return}let i=ui(s,o);if(!i){m(e,404,{error:"Template not found"});return}D(),m(e,200,{ok:!0,template:{id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Xr(t){let e=qe();m(t,200,{modules:e.map(n=>({moduleName:n.module.moduleName,usedIn:n.usedIn,fieldsJson:n.module.fieldsJson}))})}function Qr(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}j(e,o=>{try{let{moduleName:i}=JSON.parse(o);if(!i){m(n,400,{error:"moduleName is required"});return}let r=qe().find(d=>d.module.moduleName===i);if(!r){m(n,404,{error:`Module "${i}" not found in library`});return}let l={...r.module};s.modules.find(d=>d.moduleName===l.moduleName)||(s.modules.push(l),s.moduleOrder.push(l.moduleName),s.updatedAt=Date.now()),D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}})}function Zr(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){m(n,200,{styleguide:s.brandAssets?.styleguide||null,brandvoice:s.brandAssets?.brandvoice||null});return}if(t==="POST"){j(e,o=>{try{let{type:i,content:a}=JSON.parse(o);if(!i){m(n,400,{error:"type is required"});return}if(s.brandAssets||(s.brandAssets={}),i==="humanify"){s.brandAssets.humanify=a==="on",s.updatedAt=Date.now(),D(),m(n,200,{ok:!0});return}if(!a){m(n,400,{error:"content is required"});return}if(i!=="styleguide"&&i!=="brandvoice"){m(n,400,{error:`Invalid type: ${i}. Must be "styleguide" or "brandvoice"`});return}s.brandAssets[i]=a,s.updatedAt=Date.now();let r=Je(s.themePath,".vibespot");we(r),H(Je(r,`${i}.md`),a),D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}if(t==="DELETE"){j(e,o=>{try{let{type:i}=JSON.parse(o);if(i!=="styleguide"&&i!=="brandvoice"){m(n,400,{error:`Invalid type: ${i}`});return}s.brandAssets&&delete s.brandAssets[i],s.updatedAt=Date.now();let a=Je(s.themePath,".vibespot",`${i}.md`);Bn(a)&&Gs(a),D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}m(n,405,{error:"Method not allowed"})}function ea(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}j(t,s=>{(async()=>{try{let{sourcePath:o}=s?JSON.parse(s):{},i=o||n.themePath,{extractDesignContext:a}=await Promise.resolve().then(()=>(Ls(),Hs)),r=await a(i);n.brandAssets||(n.brandAssets={}),n.brandAssets.styleguide=r,n.updatedAt=Date.now();let l=Je(n.themePath,".vibespot");we(l),H(Je(l,"styleguide.md"),r),D(),m(e,200,{ok:!0,styleguide:r})}catch(o){m(e,500,{error:o instanceof Error?o.message:String(o)})}})()})}function ta(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}j(t,s=>{(async()=>{try{let{source:o,themeName:i,localPath:a}=JSON.parse(s),r;if(o==="hubspot"){if(!i){m(e,400,{error:"themeName is required for HubSpot import"});return}let u=he();if(!u){m(e,400,{error:"No HubSpot account connected"});return}let p=i.replace(/^\/+|\/+$/g,"");if(!p){m(e,400,{error:"Invalid theme name"});return}let f=p.replace(/[@/]/g,"_").replace(/_+/g,"_"),{homedir:h}=await import("os"),y=Je(h(),"vibespot-themes",".references",f);we(y);let{fetchTheme:b}=await Promise.resolve().then(()=>(pn(),yo));await b(u,p,y),r=y}else if(o==="local"){if(!a){m(e,400,{error:"localPath is required for local import"});return}if(!Bn(a)){m(e,400,{error:`Path not found: ${a}`});return}r=a}else{m(e,400,{error:"source must be 'hubspot' or 'local'"});return}let{extractDesignContext:l}=await Promise.resolve().then(()=>(Ls(),Hs)),c=await l(r);n.brandAssets||(n.brandAssets={}),n.brandAssets.styleguide=c,n.updatedAt=Date.now();let d=Je(n.themePath,".vibespot");we(d),H(Je(d,"styleguide.md"),c),D(),m(e,200,{ok:!0,styleguide:c,source:r})}catch(o){m(e,500,{error:o instanceof Error?o.message:String(o)})}})()})}g();import{join as hd}from"path";function na(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}m(e,200,{id:n.id,themeName:n.themeName,themePath:n.themePath,messageCount:n.messages.length,moduleCount:n.modules.length,moduleOrder:n.moduleOrder})}function sa(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){let o=ue();m(n,200,{modules:o.map(i=>({moduleName:i.moduleName,fieldsJson:i.fieldsJson,moduleHtml:i.moduleHtml,moduleCss:i.moduleCss,moduleJs:i.moduleJs||null})),sharedCss:s.sharedCss,sharedJs:s.sharedJs});return}if(t==="DELETE"){$s(e,n,o=>{o.deleteEntirely?ii(o.moduleName):ri(o.moduleName),D(),m(n,200,{ok:!0})});return}m(n,405,{error:"Method not allowed"})}function oa(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}j(t,s=>{try{let o=JSON.parse(s);if(o.shared){if(o.shared==="css")n.sharedCss=o.content;else if(o.shared==="js")n.sharedJs=o.content;else{m(e,400,{error:"Invalid shared type"});return}let c=Se();c&&(o.shared==="css"?c.sharedCss=o.content:c.sharedJs=o.content),n.updatedAt=Date.now(),D(),Xe(),m(e,200,{ok:!0});return}let{moduleName:i,fileType:a,content:r}=o;if(!i||!a){m(e,400,{error:"moduleName and fileType required"});return}let l=n.modules.find(c=>c.moduleName===i);if(!l){m(e,404,{error:`Module "${i}" not found`});return}switch(a){case"html":l.moduleHtml=r;break;case"css":l.moduleCss=r;break;case"js":l.moduleJs=r||void 0;break;case"fields":try{JSON.parse(r)}catch{m(e,400,{error:"Invalid JSON in fields.json"});return}l.fieldsJson=r;break;default:m(e,400,{error:`Invalid fileType: ${a}`});return}n.updatedAt=Date.now(),D(),Xe(),m(e,200,{ok:!0})}catch(o){m(e,400,{error:String(o)})}})}function ia(t,e){$s(t,e,n=>{Array.isArray(n.order)?(ht(n.order),D(),m(e,200,{ok:!0})):m(e,400,{error:"order must be an array"})})}async function ra(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}try{Xe();let n=An(e.themePath),s=Dn(`hs cms upload "${e.themePath}" "${e.themeName}"`,"Uploading to HubSpot",{cwd:hd(e.themePath,".."),timeout:18e4});m(t,200,{ok:!0,jobId:s,fixes:n})}catch(n){m(t,500,{error:String(n)})}}function aa(t,e){j(t,n=>{try{let{moduleName:s,fieldPath:o,value:i}=JSON.parse(n);ai(s,o,i),D(),m(e,200,{ok:!0})}catch(s){m(e,400,{error:String(s)})}})}function la(t,e){j(t,n=>{try{let{url:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"url is required"});return}let o=go(s),i=o.components.map(r=>`- ${r.name}: ${r.description}`).join(`
|
|
1365
|
+
`)}catch{}}}m(e,200,{ok:!0,message:"API key saved"})}else{let i=ht("codex login","Authenticating Codex CLI (check your browser if prompted)",{timeout:12e4});m(e,200,{ok:!0,jobId:i,hint:"Complete the sign-in in your browser."})}break}default:m(e,400,{error:`Unknown CLI: ${s}`})}}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function ba(t,e){j(t,n=>{try{let{mode:s}=JSON.parse(n);if(s!=="api"&&s!=="cli"){m(e,400,{error:`Invalid mode: ${s}. Must be "api" or "cli".`});return}q({hubspotUploadMode:s}),m(e,200,{ok:!0,mode:s})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function Sa(t,e){j(t,n=>{try{let{toolId:s,enabled:o}=JSON.parse(n);if(!s||typeof o!="boolean"){m(e,400,{error:"toolId (string) and enabled (boolean) required"});return}bs(s,o),m(e,200,{ok:!0,toolId:s,enabled:o})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function va(t,e){j(t,n=>{try{let s=JSON.parse(n),o=["agenticMode","agenticConcurrency"],i={};for(let a of o)a in s&&(i[a]=s[a]);if(Object.keys(i).length===0){m(e,400,{error:"No valid settings fields provided"});return}q(i),m(e,200,{ok:!0,updated:Object.keys(i)})}catch(s){m(e,400,{error:s instanceof Error?s.message:String(s)})}})}function wa(t,e){let n=t.replace("/api/settings/job/","");if(!n){m(e,400,{error:"Job ID required"});return}let s=ss(n);if(!s){m(e,404,{error:"Job not found"});return}m(e,200,{id:s.id,status:s.status,description:s.description,output:s.output,exitCode:s.exitCode,startedAt:s.startedAt,completedAt:s.completedAt})}g();ot();Se();import{existsSync as Ud,rmSync as Wd}from"fs";import{join as Bd}from"path";function xa(t,e,n){if(t==="GET"){let s=v(),o=kt().sort((i,a)=>a.updatedAt-i.updatedAt);m(n,200,{activeTheme:s?{id:s.id,themeName:s.themeName}:null,sessions:o});return}if(t==="DELETE"){j(e,s=>{try{let{sessionId:o,deleteFiles:i}=JSON.parse(s);Ui(o,i),m(n,200,{ok:!0})}catch(o){m(n,500,{error:o instanceof Error?o.message:String(o)})}});return}m(n,405,{error:"Method not allowed"})}function Ca(t,e){j(t,n=>{try{let{sessionId:s}=JSON.parse(n),o=Vn(s);if(!o){m(e,404,{error:"Session not found"});return}m(e,200,{ok:!0,themeName:o.themeName,themePath:o.themePath})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Aa(t,e){j(t,n=>{try{let{themeName:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"Theme name is required"});return}let o=Bd(Me,s);if(!Ud(o)){m(e,404,{error:"Theme not found on disk"});return}Wd(o,{recursive:!0,force:!0}),m(e,200,{ok:!0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Ia(t,e){j(t,n=>{try{let{sessionId:s,newName:o}=JSON.parse(n);if(!s||!o||typeof o!="string"){m(e,400,{error:"sessionId and newName are required"});return}let i=o.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-|-$/g,"").replace(/-{2,}/g,"-");if(!i){m(e,400,{error:"Invalid name"});return}let a=Wi(s,i);a.ok?m(e,200,{ok:!0,newName:i}):m(e,400,{error:a.error})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}g();ot();ve();ee();Se();Z();import{existsSync as ms,readFileSync as eu,rmSync as So}from"fs";import{join as Ge,basename as tu}from"path";import{execFileSync as nu}from"child_process";var su=process.platform==="win32"?{shell:!0}:{};function Ma(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}let n=nt();m(t,200,{themeName:e.themeName,themePath:e.themePath,templates:e.templates.map(s=>({id:s.id,label:s.label,pageType:s.pageType,moduleCount:s.modules.length,messageCount:s.messages.length})),activeTemplateId:e.activeTemplateId,moduleLibrary:n.map(s=>({moduleName:s.module.moduleName,usedIn:s.usedIn})),brandAssets:{hasStyleguide:!!e.brandAssets?.styleguide,hasBrandvoice:!!e.brandAssets?.brandvoice,hasThemeContext:!!e.brandAssets?.themeContext,humanify:e.brandAssets?.humanify!==!1}})}function Pa(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}let n=e.themePath;if(!ms(n)){m(t,404,{error:"Theme directory not found"});return}let s=e.themeName||"theme",o=Ge(n,".."),i=tu(n);try{let a=`${s}.zip`,r=Ge(o,a);ms(r)&&So(r),nu("zip",["-r",a,i,"-x",`${i}/.git/*`,`${i}/.vibespot/*`,`${i}/node_modules/*`],{cwd:o,timeout:3e4,...su});let l=eu(r);So(r),t.writeHead(200,{"Content-Type":"application/zip","Content-Disposition":`attachment; filename="${a}"`,"Content-Length":l.length}),t.end(l)}catch(a){E.error("download-zip","Failed to create zip archive",a),m(t,500,{error:"Failed to create zip archive"})}}function _a(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){m(n,200,{templates:s.templates.map(o=>({id:o.id,label:o.label,pageType:o.pageType,moduleCount:o.modules.length})),activeTemplateId:s.activeTemplateId});return}if(t==="POST"){j(e,o=>{try{let{pageType:i,label:a}=JSON.parse(o);if(!i||!a){m(n,400,{error:"pageType and label are required"});return}if(!["landing_page","blog_post","website_page","module_only"].includes(i)){m(n,400,{error:`Invalid pageType: ${i}`});return}let l=Ji(i,a);D(),m(n,200,{ok:!0,template:{id:l.id,label:l.label,pageType:l.pageType}})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}if(t==="DELETE"){j(e,o=>{try{let{templateId:i}=JSON.parse(o);if(!i){m(n,400,{error:"templateId is required"});return}if(!Hi(i)){m(n,404,{error:"Template not found"});return}D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}m(n,405,{error:"Method not allowed"})}function Ra(t,e){j(t,n=>{try{let{templateId:s}=JSON.parse(n);if(!s){m(e,400,{error:"templateId is required"});return}if(!Ns(s)){m(e,404,{error:"Template not found"});return}D();let i=v();m(e,200,{ok:!0,modules:me().map(a=>a.moduleName),messageCount:i?.messages.length||0})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Oa(t,e){j(t,n=>{try{let{templateId:s,newLabel:o}=JSON.parse(n);if(!s||!o||typeof o!="string"){m(e,400,{error:"templateId and newLabel are required"});return}if(!Li(s,o.trim())){m(e,404,{error:"Template not found"});return}D(),m(e,200,{ok:!0,newLabel:o.trim()})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function ja(t,e){j(t,n=>{try{let{templateId:s,label:o}=JSON.parse(n);if(!s){m(e,400,{error:"templateId is required"});return}let i=Di(s,o);if(!i){m(e,404,{error:"Template not found"});return}D(),m(e,200,{ok:!0,template:{id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function Fa(t){let e=nt();m(t,200,{modules:e.map(n=>({moduleName:n.module.moduleName,usedIn:n.usedIn,fieldsJson:n.module.fieldsJson}))})}function Ja(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}j(e,o=>{try{let{moduleName:i}=JSON.parse(o);if(!i){m(n,400,{error:"moduleName is required"});return}let r=nt().find(d=>d.module.moduleName===i);if(!r){m(n,404,{error:`Module "${i}" not found in library`});return}let l={...r.module};s.modules.find(d=>d.moduleName===l.moduleName)||(s.modules.push(l),s.moduleOrder.push(l.moduleName),s.updatedAt=Date.now()),D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}})}function Da(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){m(n,200,{styleguide:s.brandAssets?.styleguide||null,brandvoice:s.brandAssets?.brandvoice||null,themeContext:s.brandAssets?.themeContext||null});return}if(t==="POST"){j(e,o=>{try{let{type:i,content:a}=JSON.parse(o);if(!i){m(n,400,{error:"type is required"});return}if(s.brandAssets||(s.brandAssets={}),i==="humanify"){s.brandAssets.humanify=a==="on",s.updatedAt=Date.now(),D(),m(n,200,{ok:!0});return}if(!a){m(n,400,{error:"content is required"});return}if(i!=="styleguide"&&i!=="brandvoice"&&i!=="themeContext"){m(n,400,{error:`Invalid type: ${i}. Must be "styleguide", "brandvoice", or "themeContext"`});return}let r=i==="themeContext"?"theme-context.md":`${i}.md`;s.brandAssets[i]=a,s.updatedAt=Date.now();let l=Ge(s.themePath,".vibespot");Ae(l),H(Ge(l,r),a),D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}if(t==="DELETE"){j(e,o=>{try{let{type:i}=JSON.parse(o);if(i!=="styleguide"&&i!=="brandvoice"&&i!=="themeContext"){m(n,400,{error:`Invalid type: ${i}`});return}s.brandAssets&&delete s.brandAssets[i],s.updatedAt=Date.now();let a=i==="themeContext"?"theme-context.md":`${i}.md`,r=Ge(s.themePath,".vibespot",a);ms(r)&&So(r),D(),m(n,200,{ok:!0})}catch(i){m(n,500,{error:i instanceof Error?i.message:String(i)})}});return}m(n,405,{error:"Method not allowed"})}function Ea(t,e,n){if(!t)return;t.brandAssets||(t.brandAssets={}),t.brandAssets[e]=n,t.updatedAt=Date.now();let s=e==="themeContext"?"theme-context.md":`${e}.md`,o=Ge(t.themePath,".vibespot");Ae(o),H(Ge(o,s),n)}async function Na(t,e,n){if(e==="styleguide"){let{extractDesignContext:p}=await Promise.resolve().then(()=>(us(),ds));return p(n||t.themePath)}let{resolveAgenticEngine:s}=await Promise.resolve().then(()=>(ns(),Kr)),{loadConfig:o}=await Promise.resolve().then(()=>(ee(),No)),i=o(),{engine:a,apiKey:r,model:l}=s(i),{buildPreviewHtml:c}=await Promise.resolve().then(()=>(zn(),Gs)),d=c();if(!d||d.length<50)return null;if(e==="brandvoice"){let{extractBrandvoice:p}=await Promise.resolve().then(()=>(Ta(),$a));return p(d,a,r,l)}let{extractThemeContext:u}=await Promise.resolve().then(()=>(bo(),yo));return u(d,t.brandAssets?.themeContext,a,r,l)}function La(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}j(t,s=>{(async()=>{try{let o=s?JSON.parse(s):{},i=o.type||"styleguide",a=o.sourcePath;if(i==="all"){let l=["styleguide","brandvoice","themeContext"],c=await Promise.allSettled(l.map(u=>Na(n,u,a))),d={};for(let u=0;u<l.length;u++){let p=c[u],f=p.status==="fulfilled"?p.value:null;f&&Ea(n,l[u],f),d[l[u]]=f}D(),m(e,200,{ok:!0,type:"all",extracted:d});return}if(i!=="styleguide"&&i!=="brandvoice"&&i!=="themeContext"){m(e,400,{error:`Invalid type: ${i}`});return}let r=await Na(n,i,a);if(!r){m(e,200,{ok:!1,type:i,error:"No content to extract from"});return}Ea(n,i,r),D(),m(e,200,{ok:!0,type:i,content:r})}catch(o){m(e,500,{error:o instanceof Error?o.message:String(o)})}})()})}function Ha(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}j(t,s=>{(async()=>{try{let{source:o,themeName:i,localPath:a}=JSON.parse(s),r;if(o==="hubspot"){if(!i){m(e,400,{error:"themeName is required for HubSpot import"});return}let u=he();if(!u){m(e,400,{error:"No HubSpot account connected"});return}let p=i.replace(/^\/+|\/+$/g,"");if(!p){m(e,400,{error:"Invalid theme name"});return}let f=p.replace(/[@/]/g,"_").replace(/_+/g,"_"),{homedir:h}=await import("os"),y=Ge(h(),"vibespot-themes",".references",f);Ae(y);let{fetchTheme:b}=await Promise.resolve().then(()=>($n(),Wo));await b(u,p,y),r=y}else if(o==="local"){if(!a){m(e,400,{error:"localPath is required for local import"});return}if(!ms(a)){m(e,400,{error:`Path not found: ${a}`});return}r=a}else{m(e,400,{error:"source must be 'hubspot' or 'local'"});return}let{extractDesignContext:l}=await Promise.resolve().then(()=>(us(),ds)),c=await l(r);n.brandAssets||(n.brandAssets={}),n.brandAssets.styleguide=c,n.updatedAt=Date.now();let d=Ge(n.themePath,".vibespot");Ae(d),H(Ge(d,"styleguide.md"),c),D(),m(e,200,{ok:!0,styleguide:c,source:r})}catch(o){m(e,500,{error:o instanceof Error?o.message:String(o)})}})()})}g();ot();Se();import{join as ou}from"path";Yt();function Ga(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}m(e,200,{id:n.id,themeName:n.themeName,themePath:n.themePath,messageCount:n.messages.length,moduleCount:n.modules.length,moduleOrder:n.moduleOrder})}function Ua(t,e,n){let s=v();if(!s){m(n,404,{error:"No active session"});return}if(t==="GET"){let o=me();m(n,200,{modules:o.map(i=>({moduleName:i.moduleName,fieldsJson:i.fieldsJson,moduleHtml:i.moduleHtml,moduleCss:i.moduleCss,moduleJs:i.moduleJs||null})),sharedCss:s.sharedCss,sharedJs:s.sharedJs});return}if(t==="DELETE"){Zs(e,n,o=>{o.deleteEntirely?_i(o.moduleName):Ri(o.moduleName),D(),m(n,200,{ok:!0})});return}m(n,405,{error:"Method not allowed"})}function Wa(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}j(t,s=>{try{let o=JSON.parse(s);if(o.shared){if(o.shared==="css")n.sharedCss=o.content;else if(o.shared==="js")n.sharedJs=o.content;else{m(e,400,{error:"Invalid shared type"});return}let c=Ce();c&&(o.shared==="css"?c.sharedCss=o.content:c.sharedJs=o.content),n.updatedAt=Date.now(),D(),st(),m(e,200,{ok:!0});return}let{moduleName:i,fileType:a,content:r}=o;if(!i||!a){m(e,400,{error:"moduleName and fileType required"});return}let l=n.modules.find(c=>c.moduleName===i);if(!l){m(e,404,{error:`Module "${i}" not found`});return}switch(a){case"html":l.moduleHtml=r;break;case"css":l.moduleCss=r;break;case"js":l.moduleJs=r||void 0;break;case"fields":try{JSON.parse(r)}catch{m(e,400,{error:"Invalid JSON in fields.json"});return}l.fieldsJson=r;break;default:m(e,400,{error:`Invalid fileType: ${a}`});return}n.updatedAt=Date.now(),D(),st(),m(e,200,{ok:!0})}catch(o){m(e,400,{error:String(o)})}})}function Ba(t,e){Zs(t,e,n=>{Array.isArray(n.order)?(At(n.order),D(),m(e,200,{ok:!0})):m(e,400,{error:"order must be an array"})})}async function Ka(t){let e=v();if(!e){m(t,404,{error:"No active session"});return}try{st();let n=Jn(e.themePath),s=os(`hs cms upload "${e.themePath}" "${e.themeName}"`,"Uploading to HubSpot",{cwd:ou(e.themePath,".."),timeout:18e4});m(t,200,{ok:!0,jobId:s,fixes:n})}catch(n){m(t,500,{error:String(n)})}}function Va(t,e){j(t,n=>{try{let{moduleName:s,fieldPath:o,value:i}=JSON.parse(n);Oi(s,o,i),D(),m(e,200,{ok:!0})}catch(s){m(e,400,{error:String(s)})}})}function Ya(t,e){j(t,n=>{try{let{url:s}=JSON.parse(n);if(!s||typeof s!="string"){m(e,400,{error:"url is required"});return}let o=Go(s),i=o.components.map(r=>`- ${r.name}: ${r.description}`).join(`
|
|
1312
1366
|
`),a={sourceDir:o.sourceDir,componentCount:o.components.length,components:o.components.map(r=>({name:r.name,description:r.description})),hasTailwind:o.hasTailwind,cssVarCount:o.cssVarCount,fonts:o.fonts,interactions:o.interactions,conversionPrompt:`Import and convert the React landing page from ${s} to native HubSpot modules.
|
|
1313
1367
|
|
|
1314
1368
|
Source analysis found ${o.components.length} components:
|
|
@@ -1318,11 +1372,11 @@ Design system: ${o.hasTailwind?"Tailwind CSS":"Custom CSS"}, ${o.cssVarCount} CS
|
|
|
1318
1372
|
Fonts: ${o.fonts.length>0?o.fonts.join(", "):"System fonts"}
|
|
1319
1373
|
Interactions: ${o.interactions.join(", ")}
|
|
1320
1374
|
|
|
1321
|
-
Read the React source files from ${o.sourceDir} and convert each component to a HubSpot module. Preserve the design, layout, colors, and content. Generate fields.json so marketers can edit all text, images, colors, and links in the HubSpot page editor.`};m(e,200,a)}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function ca(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}if(!ke()){m(e,200,{available:!1,commits:[]});return}let o=new URL(t.url||"/","http://localhost").searchParams.get("templateId"),i=o?ti(n.themePath,o,50):ei(n.themePath,50);m(e,200,{available:!0,commits:i,filtered:!!o})}function da(t,e){j(t,n=>{try{let s=v();if(!s){m(e,404,{error:"No active session"});return}let{hash:o,templateId:i}=JSON.parse(n);if(!o||typeof o!="string"){m(e,400,{error:"Commit hash is required"});return}if(ze("assistant",`Rolled back to version ${o.slice(0,7)}.`),i){let a=s.templates.find(c=>c.id===i);if(!a){m(e,404,{error:"Template not found"});return}let r=a.moduleOrder.map(c=>`modules/${c}.module`);a.templateFile&&r.push(a.templateFile);let l=si(s.themePath,i,o,r);if(!l.success){m(e,500,{error:l.error||"Rollback failed"});return}vi()}else{let a=ni(s.themePath,o);if(!a.success){m(e,500,{error:a.error||"Rollback failed"});return}Si()}D(),m(e,200,{ok:!0,modules:ue().map(a=>a.moduleName)})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}var pa={".html":"text/html",".css":"text/css",".js":"application/javascript",".json":"application/json",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".ico":"image/x-icon",".woff2":"font/woff2"};function fa(t){let{port:e,uiDir:n}=t,s=yd((i,a)=>vd(i,a,n)),o=new Sd({server:s});return o.on("connection",i=>xd(i)),new Promise((i,a)=>{s.on("error",r=>{r.code==="EADDRINUSE"?s.listen(e+1,()=>{i({port:e+1,close:()=>{s.close(),o.close()}})}):a(r)}),s.listen(e,()=>{i({port:e,close:()=>{s.close(),o.close()}})})})}function vd(t,e,n){let s=new URL(t.url||"/",`http://${t.headers.host}`),o=t.method||"GET";if(e.setHeader("X-Content-Type-Options","nosniff"),e.setHeader("X-Frame-Options","DENY"),e.setHeader("X-XSS-Protection","1; mode=block"),e.setHeader("Referrer-Policy","strict-origin-when-cross-origin"),s.pathname.startsWith("/api/")){wd(o,s.pathname,t,e);return}if(s.pathname==="/preview"){let i=Mi();e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(i);return}if(s.pathname==="/module-preview"){let i=s.searchParams.get("module")||"",a=Ni(i);e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(a||"<!-- module not found -->");return}if(s.pathname.startsWith("/theme-assets/")){Cd(s.pathname.slice(14),e);return}Ad(s.pathname,n,t,e)}function wd(t,e,n,s){let o=n.headers.origin||"";if(/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(o)&&s.setHeader("Access-Control-Allow-Origin",o),s.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),s.setHeader("Access-Control-Allow-Headers","Content-Type"),t==="OPTIONS"){s.writeHead(204),s.end();return}switch(e){case"/api/session":na(t,s);break;case"/api/modules":sa(t,n,s);break;case"/api/modules/reorder":ia(n,s);break;case"/api/modules/code":oa(n,s);break;case"/api/upload":ra(s);break;case"/api/upload-files":t==="POST"?Hi(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/field":aa(n,s);break;case"/api/import":la(n,s);break;case"/api/setup":yr(s);break;case"/api/setup/create":br(n,s);break;case"/api/setup/fetch":Sr(n,s);break;case"/api/setup/open":vr(n,s);break;case"/api/setup/resume":wr(n,s);break;case"/api/setup/apikey":xr(n,s);break;case"/api/setup/remote-themes":t==="GET"?Cr(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/status":t==="GET"?$r(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/engine":t==="POST"?Tr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/apikey":t==="POST"?Er(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/install":t==="POST"?Mr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":t==="POST"?Nr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":t==="POST"?_r(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":t==="POST"?Pr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":t==="POST"?Rr(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":t==="POST"?Or(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-mode":t==="POST"?jr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/cli-toggle":t==="POST"?Fr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings":t==="POST"?Jr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/changelog":t==="GET"?m(s,200,{changelog:qs()}):m(s,405,{error:"Method not allowed"});break;case"/api/themes":Hr(t,n,s);break;case"/api/themes/switch":t==="POST"?Lr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":t==="POST"?Gr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/themes/rename":t==="POST"?Ur(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/history":t==="GET"?ca(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/rollback":t==="POST"?da(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/dashboard":t==="GET"?Br(s):m(s,405,{error:"Method not allowed"});break;case"/api/templates":Kr(t,n,s);break;case"/api/templates/activate":t==="POST"?Yr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/templates/rename":t==="POST"?zr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/templates/clone":t==="POST"?qr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/module-library":t==="GET"?Xr(s):m(s,405,{error:"Method not allowed"});break;case"/api/brand-assets":Zr(t,n,s);break;case"/api/brand-assets/extract":t==="POST"?ea(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/brand-assets/import-reference":t==="POST"?ta(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/download-zip":t==="GET"?Vr(s):m(s,405,{error:"Method not allowed"});break;default:e.startsWith("/api/settings/job/")&&t==="GET"?Dr(e,s):e.match(/^\/api\/templates\/[^/]+\/add-module$/)&&t==="POST"?Qr(e,n,s):m(s,404,{error:"Not found"})}}function xd(t){t.on("message",async n=>{let s;try{s=JSON.parse(n.toString())}catch{t.send(JSON.stringify({type:"error",message:"Invalid JSON"}));return}switch(s.type){case"chat":{let o=String(s.message||"");if(!o.trim())return;ze("user",o),D();let i=Array.isArray(s.fileIds)?s.fileIds:void 0,a=dr();a.needsPrompt&&t.send(JSON.stringify({type:"agentic_prompt"}));try{if(a.useAgentic){let l=[],c=[],d=await lr(o,u=>{if(u.type==="module_progress"&&u.moduleFiles){let{moduleFiles:p,...f}=u;t.send(JSON.stringify(f))}else t.send(JSON.stringify(u));if(u.type==="agent_step")l.push({step:u.step,label:u.label});else if(u.type==="agent_decision"){let p=l[l.length-1];p&&(p.decisions||(p.decisions=[]),p.decisions.push(u.decision))}else u.type==="design_system_ready"?Oe({sharedCss:u.sharedCss,sharedJs:u.sharedJs}):u.type==="blueprint_ready"?(Oe({sharedCss:u.sharedCss,sharedJs:u.sharedJs}),ht(u.moduleOrder),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(p=>p.moduleName)}))):u.type==="module_progress"&&u.status==="complete"&&u.moduleFiles?(Oe({modules:[{moduleName:u.module,fieldsJson:u.moduleFiles.fieldsJson,metaJson:u.moduleFiles.metaJson,moduleHtml:u.moduleFiles.moduleHtml,moduleCss:u.moduleFiles.moduleCss,moduleJs:u.moduleFiles.moduleJs}]}),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(p=>p.moduleName)})),c.push({name:u.module,status:"complete"})):u.type==="module_progress"&&u.status==="failed"&&c.push({name:u.module,status:"failed"})},i);cr(d,{steps:l,modules:c,stats:d.stats})}else ar(l=>{t.send(JSON.stringify({type:"parse_warning",message:l}))}),await Os(o,l=>{t.send(JSON.stringify({type:"stream",content:l}))},l=>{t.send(JSON.stringify({type:"stream_status",content:l}))},i);let r=v();if(r){Xe();let l=Se(),c=null;if(l){let d=l.moduleOrder.map(u=>`modules/${u}.module`);l.templateFile&&d.push(l.templateFile),l.sharedCss&&d.push(`css/${r.themeName}-theme.css`),l.sharedJs&&d.push(`js/${r.themeName}-animations.js`),c=Zo(r.themePath,l.id,o,d)}else c=rs(r.themePath,o);c&&t.send(JSON.stringify({type:"version_created",hash:c}))}t.send(JSON.stringify({type:"generation_complete"})),t.send(JSON.stringify({type:"modules_updated",modules:ue().map(l=>l.moduleName)}))}catch(r){t.send(JSON.stringify({type:"error",message:r instanceof Error?r.message:String(r)}))}break}case"start_upload":{let o=v();if(!o){t.send(JSON.stringify({type:"error",message:"No active session"}));break}try{Xe();let i=An(o.themePath);if(i.length>0&&t.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i})),(_().hubspotUploadMode||"api")==="api"){let l=he();if(!l){t.send(JSON.stringify({type:"upload_failed",output:"No HubSpot account configured. Open Settings \u2192 HubSpot to add one.",errors:[{file:"",message:"No HubSpot account configured",fixable:!1}]}));break}t.send(JSON.stringify({type:"upload_started",jobId:"api-upload"}));let c=await In(l,o.themePath,o.themeName,{onFileStart:d=>{t.send(JSON.stringify({type:"upload_output",chunk:`Uploading ${d}
|
|
1375
|
+
Read the React source files from ${o.sourceDir} and convert each component to a HubSpot module. Preserve the design, layout, colors, and content. Generate fields.json so marketers can edit all text, images, colors, and links in the HubSpot page editor.`};m(e,200,a)}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}function za(t,e){let n=v();if(!n){m(e,404,{error:"No active session"});return}if(!Ee()){m(e,200,{available:!1,commits:[]});return}let o=new URL(t.url||"/","http://localhost").searchParams.get("templateId"),i=o?Ei(n.themePath,o,50):Ti(n.themePath,50);m(e,200,{available:!0,commits:i,filtered:!!o})}function qa(t,e){j(t,n=>{try{let s=v();if(!s){m(e,404,{error:"No active session"});return}let{hash:o,templateId:i}=JSON.parse(n);if(!o||typeof o!="string"){m(e,400,{error:"Commit hash is required"});return}if(tt("assistant",`Rolled back to version ${o.slice(0,7)}.`),i){let a=s.templates.find(c=>c.id===i);if(!a){m(e,404,{error:"Template not found"});return}let r=a.moduleOrder.map(c=>`modules/${c}.module`);a.templateFile&&r.push(a.templateFile);let l=Mi(s.themePath,i,o,r);if(!l.success){m(e,500,{error:l.error||"Rollback failed"});return}Yi()}else{let a=Ni(s.themePath,o);if(!a.success){m(e,500,{error:a.error||"Rollback failed"});return}Vi()}D(),m(e,200,{ok:!0,modules:me().map(a=>a.moduleName)})}catch(s){m(e,500,{error:s instanceof Error?s.message:String(s)})}})}no();var Za={".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 el(t){let{port:e,uiDir:n}=t,s=iu((i,a)=>lu(i,a,n)),o=new au({server:s});return o.on("connection",i=>du(i)),new Promise((i,a)=>{s.on("error",r=>{r.code==="EADDRINUSE"?s.listen(e+1,()=>{i({port:e+1,close:()=>{s.close(),o.close()}})}):a(r)}),s.listen(e,()=>{i({port:e,close:()=>{s.close(),o.close()}})})})}function lu(t,e,n){let s=new URL(t.url||"/",`http://${t.headers.host}`),o=t.method||"GET";if(e.setHeader("X-Content-Type-Options","nosniff"),e.setHeader("X-Frame-Options","DENY"),e.setHeader("X-XSS-Protection","1; mode=block"),e.setHeader("Referrer-Policy","strict-origin-when-cross-origin"),s.pathname.startsWith("/api/")){cu(o,s.pathname,t,e);return}if(s.pathname==="/preview"){let i=Ls();e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(i);return}if(s.pathname==="/module-preview"){let i=s.searchParams.get("module")||"",a=Hs(i);e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(a||"<!-- module not found -->");return}if(s.pathname.startsWith("/theme-assets/")){uu(s.pathname.slice(14),e);return}mu(s.pathname,n,t,e)}function cu(t,e,n,s){let o=n.headers.origin||"";if(/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(o)&&s.setHeader("Access-Control-Allow-Origin",o),s.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),s.setHeader("Access-Control-Allow-Headers","Content-Type"),t==="OPTIONS"){s.writeHead(204),s.end();return}switch(e){case"/api/session":Ga(t,s);break;case"/api/modules":Ua(t,n,s);break;case"/api/modules/reorder":Ba(n,s);break;case"/api/modules/code":Wa(n,s);break;case"/api/upload":Ka(s);break;case"/api/upload-files":t==="POST"?hr(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/field":Va(n,s);break;case"/api/import":Ya(n,s);break;case"/api/setup":Zr(s);break;case"/api/setup/create":ea(n,s);break;case"/api/setup/fetch":ta(n,s);break;case"/api/setup/open":na(n,s);break;case"/api/setup/resume":sa(n,s);break;case"/api/setup/apikey":oa(n,s);break;case"/api/setup/remote-themes":t==="GET"?ia(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/status":t==="GET"?ca(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/engine":t==="POST"?da(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/apikey":t==="POST"?ua(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/install":t==="POST"?ma(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-auth":t==="POST"?pa(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/gh-auth":t==="POST"?fa(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-switch":t==="POST"?ga(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/gh-logout":t==="POST"?ha(s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/cli-auth":t==="POST"?ya(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/hs-mode":t==="POST"?ba(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings/cli-toggle":t==="POST"?Sa(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/settings":t==="POST"?va(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/changelog":t==="GET"?m(s,200,{changelog:Io()}):m(s,405,{error:"Method not allowed"});break;case"/api/themes":xa(t,n,s);break;case"/api/themes/switch":t==="POST"?Ca(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/themes/delete-local":t==="POST"?Aa(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/themes/rename":t==="POST"?Ia(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/history":t==="GET"?za(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/rollback":t==="POST"?qa(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/dashboard":t==="GET"?Ma(s):m(s,405,{error:"Method not allowed"});break;case"/api/templates":_a(t,n,s);break;case"/api/templates/activate":t==="POST"?Ra(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/templates/rename":t==="POST"?Oa(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/templates/clone":t==="POST"?ja(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/module-library":t==="GET"?Fa(s):m(s,405,{error:"Method not allowed"});break;case"/api/brand-assets":Da(t,n,s);break;case"/api/brand-assets/extract":t==="POST"?La(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/brand-assets/import-reference":t==="POST"?Ha(n,s):m(s,405,{error:"Method not allowed"});break;case"/api/download-zip":t==="GET"?Pa(s):m(s,405,{error:"Method not allowed"});break;default:e.startsWith("/api/settings/job/")&&t==="GET"?wa(e,s):e.match(/^\/api\/templates\/[^/]+\/add-module$/)&&t==="POST"?Ja(e,n,s):m(s,404,{error:"Not found"})}}function du(t){t.on("message",async n=>{let s;try{s=JSON.parse(n.toString())}catch{t.send(JSON.stringify({type:"error",message:"Invalid JSON"}));return}switch(s.type){case"chat":{let o=String(s.message||"");if(!o.trim())return;tt("user",o),D();let i=Array.isArray(s.fileIds)?s.fileIds:void 0,a=po();a.needsPrompt&&t.send(JSON.stringify({type:"agentic_prompt"}));try{if(a.useAgentic){let l=[],c=[],d=await uo(o,u=>{if(u.type==="module_progress"&&u.moduleFiles){let{moduleFiles:p,...f}=u;t.send(JSON.stringify(f))}else t.send(JSON.stringify(u));if(u.type==="agent_step")l.push({step:u.step,label:u.label});else if(u.type==="agent_decision"){let p=l[l.length-1];p&&(p.decisions||(p.decisions=[]),p.decisions.push(u.decision))}else u.type==="design_system_ready"?De({sharedCss:u.sharedCss,sharedJs:u.sharedJs}):u.type==="blueprint_ready"?(De({sharedCss:u.sharedCss,sharedJs:u.sharedJs}),At(u.moduleOrder),t.send(JSON.stringify({type:"modules_updated",modules:me().map(p=>p.moduleName)}))):u.type==="module_progress"&&u.status==="complete"&&u.moduleFiles?(De({modules:[{moduleName:u.module,fieldsJson:u.moduleFiles.fieldsJson,metaJson:u.moduleFiles.metaJson,moduleHtml:u.moduleFiles.moduleHtml,moduleCss:u.moduleFiles.moduleCss,moduleJs:u.moduleFiles.moduleJs}]}),t.send(JSON.stringify({type:"modules_updated",modules:me().map(p=>p.moduleName)})),c.push({name:u.module,status:"complete"})):u.type==="module_progress"&&u.status==="failed"&&c.push({name:u.module,status:"failed"})},i);mo(d,{steps:l,modules:c,stats:d.stats})}else lo(l=>{t.send(JSON.stringify({type:"parse_warning",message:l}))}),await on(o,l=>{t.send(JSON.stringify({type:"stream",content:l}))},l=>{t.send(JSON.stringify({type:"stream_status",content:l}))},i);let r=v();if(r){st();let l=Ce(),c=null;if(l){let d=l.moduleOrder.map(u=>`modules/${u}.module`);l.templateFile&&d.push(l.templateFile),l.sharedCss&&d.push(`css/${r.themeName}-theme.css`),l.sharedJs&&d.push(`js/${r.themeName}-animations.js`),c=$i(r.themePath,l.id,o,d)}else c=Ts(r.themePath,o);c&&t.send(JSON.stringify({type:"version_created",hash:c}))}t.send(JSON.stringify({type:"generation_complete"})),t.send(JSON.stringify({type:"modules_updated",modules:me().map(l=>l.moduleName)}));{let l=v();l&&a.useAgentic&&!l.brandAssets?.styleguide&&!l.brandAssets?.brandvoice&&!l.brandAssets?.themeContext&&t.send(JSON.stringify({type:"suggest_brand_extraction"}))}}catch(r){t.send(JSON.stringify({type:"error",message:r instanceof Error?r.message:String(r)}))}break}case"extract_brand_assets":{let o=v();if(!o){t.send(JSON.stringify({type:"error",message:"No active session"}));break}(async()=>{try{let i=M(),{engine:a,apiKey:r,model:l}=ts(i),{buildPreviewHtml:c}=await Promise.resolve().then(()=>(zn(),Gs)),d=c();if(!d||d.length<50)return;let{extractThemeContext:u}=await Promise.resolve().then(()=>(bo(),yo)),p=await u(d,o.brandAssets?.themeContext,a,r,l),{mkdirSync:f,writeFileSync:h}=await import("fs");if(p){o.brandAssets||(o.brandAssets={}),o.brandAssets.themeContext=p,o.updatedAt=Date.now();let y=at(o.themePath,".vibespot");cn(y)||f(y,{recursive:!0}),h(at(y,"theme-context.md"),p),D(),t.send(JSON.stringify({type:"brand_asset_extracted",assetType:"themeContext"}))}if(!o.brandAssets?.styleguide)try{let{extractDesignContext:y}=await Promise.resolve().then(()=>(us(),ds)),b=await y(o.themePath);if(b){o.brandAssets||(o.brandAssets={}),o.brandAssets.styleguide=b,o.updatedAt=Date.now();let A=at(o.themePath,".vibespot");cn(A)||f(A,{recursive:!0}),h(at(A,"styleguide.md"),b),D(),t.send(JSON.stringify({type:"brand_asset_extracted",assetType:"styleguide"}))}}catch{}t.send(JSON.stringify({type:"brand_extraction_complete"}))}catch(i){t.send(JSON.stringify({type:"brand_extraction_error",message:i instanceof Error?i.message:String(i)}))}})();break}case"start_upload":{let o=v();if(!o){t.send(JSON.stringify({type:"error",message:"No active session"}));break}try{st();let i=Jn(o.themePath);if(i.length>0&&t.send(JSON.stringify({type:"upload_status",phase:"autofix",fixes:i})),(M().hubspotUploadMode||"api")==="api"){let l=he();if(!l){t.send(JSON.stringify({type:"upload_failed",output:"No HubSpot account configured. Open Settings \u2192 HubSpot to add one.",errors:[{file:"",message:"No HubSpot account configured",fixable:!1}]}));break}t.send(JSON.stringify({type:"upload_started",jobId:"api-upload"}));let c=await Dn(l,o.themePath,o.themeName,{onFileStart:d=>{t.send(JSON.stringify({type:"upload_output",chunk:`Uploading ${d}
|
|
1322
1376
|
`}))},onFileComplete:d=>{t.send(JSON.stringify({type:"upload_output",chunk:` \u2713 ${d}
|
|
1323
1377
|
`}))},onFileError:(d,u)=>{t.send(JSON.stringify({type:"upload_output",chunk:` \u2717 ${d}: ${u.message}
|
|
1324
|
-
`}))},onProgress:(d,u)=>{t.send(JSON.stringify({type:"upload_progress",completed:d,total:u}))}});if(c.success){let d=
|
|
1325
|
-
`),errors:d}))}}else{let l=
|
|
1378
|
+
`}))},onProgress:(d,u)=>{t.send(JSON.stringify({type:"upload_progress",completed:d,total:u}))}});if(c.success){let d=Xe();t.send(JSON.stringify({type:"upload_complete",output:`Uploaded ${c.uploaded} files`,portalId:d?.portalId||"",dataCenter:d?.dataCenter||"na1",themeName:o.themeName}))}else{let d=jn(c.errors);t.send(JSON.stringify({type:"upload_failed",output:c.errors.map(u=>`${u.file}: ${u.message}`).join(`
|
|
1379
|
+
`),errors:d}))}}else{let l=os(`hs cms upload "${o.themePath}" "${o.themeName}"`,"Uploading to HubSpot",{cwd:at(o.themePath,".."),timeout:18e4});t.send(JSON.stringify({type:"upload_started",jobId:l}));let c=u=>{t.send(JSON.stringify({type:"upload_output",chunk:u}))};Yr(l,c);let d=setInterval(()=>{let u=ss(l);if(!(!u||u.status==="running"))if(clearInterval(d),zr(l,c),u.status==="completed"){let p=Oe(),f=p.portalId?Lt(p.portalId):"na1";t.send(JSON.stringify({type:"upload_complete",output:u.output,portalId:p.portalId||"",dataCenter:f,themeName:o.themeName}))}else{let p=Fn(u.output);t.send(JSON.stringify({type:"upload_failed",output:u.output,errors:p,exitCode:u.exitCode}))}},500)}}catch(i){t.send(JSON.stringify({type:"error",message:i instanceof Error?i.message:String(i)}))}break}case"upload_fix_with_ai":{let o=String(s.errorContext||"");if(!o.trim()){t.send(JSON.stringify({type:"error",message:"No error context provided"}));break}let i=`The HubSpot upload ("hs cms upload") failed. Below is the upload log output containing the errors.
|
|
1326
1380
|
|
|
1327
1381
|
IMPORTANT: Be verbose in your response. For each error:
|
|
1328
1382
|
1. State exactly which file has the problem and what the error is
|
|
@@ -1335,9 +1389,9 @@ CRITICAL: After fixing the reported errors, scan ALL other module files in the t
|
|
|
1335
1389
|
After fixing all errors, summarize the changes you made.
|
|
1336
1390
|
|
|
1337
1391
|
Upload log:
|
|
1338
|
-
${o}`;
|
|
1339
|
-
`));let n
|
|
1340
|
-
`));try{process.platform==="darwin"?
|
|
1392
|
+
${o}`;tt("user",i),D(),t.send(JSON.stringify({type:"upload_fix_started"}));try{await on(i,r=>{t.send(JSON.stringify({type:"stream",content:r})),t.send(JSON.stringify({type:"upload_fix_stream",content:r}))});let a=v();if(a){st();let r=Ts(a.themePath,"AI fix: upload errors");r&&t.send(JSON.stringify({type:"version_created",hash:r}))}t.send(JSON.stringify({type:"upload_fix_complete"})),t.send(JSON.stringify({type:"modules_updated",modules:me().map(r=>r.moduleName)}))}catch(a){t.send(JSON.stringify({type:"upload_failed",output:a instanceof Error?a.message:String(a),errors:[{file:"AI fix",message:a instanceof Error?a.message:String(a),fixable:!1}]}))}break}case"ping":t.send(JSON.stringify({type:"pong"}));break;default:t.send(JSON.stringify({type:"error",message:`Unknown type: ${s.type}`}))}});let e=v();if(e){let n=M(),s={"claude-code":"Claude Code","anthropic-api":"Anthropic API","openai-api":"OpenAI API","gemini-cli":"Gemini CLI","gemini-api":"Gemini API","codex-cli":"Codex CLI",api:"Anthropic API"},o=Ce();t.send(JSON.stringify({type:"init",sessionId:e.id,themeName:e.themeName,modules:me().map(i=>i.moduleName),messageCount:e.messages.length,messages:e.messages,gitAvailable:Ee(),engine:n.aiEngine?s[n.aiEngine]||n.aiEngine:"",templateId:o?.id||null,pageType:o?.pageType||null,templates:(e.templates||[]).map(i=>({id:i.id,label:i.label,pageType:i.pageType,moduleCount:i.modules.length}))}))}else t.send(JSON.stringify({type:"needs_setup"}))}function uu(t,e){let n=v();if(!n){e.writeHead(404,{"Content-Type":"text/plain"}),e.end("No session");return}let s=at(n.themePath,"assets",t);if(!cn(s)){e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Asset not found");return}let o=Qa(s),i=Za[o]||"application/octet-stream",a=vo(s);e.writeHead(200,{"Content-Type":i,"Cache-Control":"no-cache"}),e.end(a)}var Xa=new Map;function mu(t,e,n,s){let i=at(e,t==="/"?"/index.html":t);if(!cn(i)){let c=at(e,"index.html");if(cn(c)){let d=vo(c);s.writeHead(200,{"Content-Type":"text/html","Cache-Control":"no-cache"}),s.end(d)}else s.writeHead(404,{"Content-Type":"text/plain"}),s.end("Not found");return}let a=Qa(i),r=Za[a]||"application/octet-stream",l=a===".html";try{let c=Xa.get(i);if(!c){let u=vo(i),p='"'+ru("md5").update(u).digest("hex").slice(0,16)+'"';c={buffer:u,etag:p,contentType:r},Xa.set(i,c)}if(n.headers["if-none-match"]===c.etag){s.writeHead(304),s.end();return}s.writeHead(200,{"Content-Type":c.contentType,"Cache-Control":l?"no-cache":"public, max-age=3600",ETag:c.etag}),s.end(c.buffer)}catch{s.writeHead(500,{"Content-Type":"text/plain"}),s.end("Internal Server Error")}}Se();var fu=4200;async function tl(){let t=fs.hex("#e8613a"),e=fs.dim;console.log(""),console.log(t(" v vibeSpot")),console.log(e(` Starting...
|
|
1393
|
+
`));let n=gu();n||(console.error(fs.red(" Could not find UI assets. Is the package installed correctly?")),process.exit(1));try{let{port:s,close:o}=await el({port:fu,uiDir:n}),i=`http://localhost:${s}`;console.log(t(` v ${i}`)),console.log(e(` Press Ctrl+C to stop
|
|
1394
|
+
`));try{process.platform==="darwin"?wo("open",[i],{stdio:"ignore"}):process.platform==="win32"?wo("cmd",["/c","start","",i],{stdio:"ignore"}):wo("xdg-open",[i],{stdio:"ignore"})}catch{}await new Promise(a=>{process.on("SIGINT",()=>{console.log(e(`
|
|
1341
1395
|
Saving session...`)),D(),o(),console.log(e(` Goodbye!
|
|
1342
|
-
`)),a(),setTimeout(()=>process.exit(0),500)})})}catch(s){console.error(
|
|
1396
|
+
`)),a(),setTimeout(()=>process.exit(0),500)})})}catch(s){console.error(fs.red(` Failed to start: ${s instanceof Error?s.message:String(s)}`)),process.exit(1)}}function gu(){let t=[ps(import.meta.dirname,"../../ui"),ps(import.meta.dirname,"../ui"),ps(process.cwd(),"ui")];for(let e of t)if(pu(ps(e,"index.html")))return e;return null}Z();function nl(){let t=new hu;return t.name("vibespot").description("AI-powered HubSpot CMS landing page builder").version(St()).action(tl),t.command("wizard").description("Classic CLI wizard \u2014 step-by-step conversion flow").action(Si),t.command("init").description("Check and install required tools").action(vi),t.command("convert").description("Convert a React project to HubSpot modules").action(wi),t.command("upload").description("Upload theme to HubSpot").action(xi),t.command("doctor").description("Diagnose environment issues").action(Ci),t}var yu=nl();yu.parseAsync(process.argv).catch(t=>{console.error(t),process.exit(1)});
|
|
1343
1397
|
//# sourceMappingURL=index.js.map
|