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