vibespot 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +293 -6781
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
- package/ui/chat.js +215 -10
- package/ui/dashboard.js +12 -17
- package/ui/dialog.js +2 -3
- package/ui/favicon.ico +0 -0
- package/ui/field-editor.js +1 -0
- package/ui/index.html +58 -31
- package/ui/settings.js +456 -238
- package/ui/setup.js +205 -18
- package/ui/styles.css +343 -0
- package/ui/upload-panel.js +115 -39
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/program.ts","../src/cli/theme.ts","../src/cli/banner.ts","../src/utils/detect.ts","../src/utils/shell.ts","../src/utils/config.ts","../src/utils/fs.ts","../src/prompts/prompter.ts","../src/wizard/preflight.ts","../src/wizard/source.ts","../src/wizard/theme-setup.ts","../src/wizard/conversion.ts","../src/ai/claude-code.ts","../src/ai/prompts.ts","../src/ai/claude-api.ts","../src/ai/gemini-cli.ts","../src/ai/codex-cli.ts","../src/wizard/uploader.ts","../src/server/auto-fix.ts","../src/wizard/next-steps.ts","../src/commands/wizard.ts","../src/commands/init.ts","../src/commands/convert.ts","../src/commands/upload.ts","../src/commands/doctor.ts","../src/commands/vibe.ts","../src/server/server.ts","../src/server/session.ts","../src/server/project-git.ts","../src/hubl/renderer.ts","../src/server/preview.ts","../src/server/ai-handler.ts","../src/server/process-manager.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { wizardCommand } from \"../commands/wizard.js\";\nimport { initCommand } from \"../commands/init.js\";\nimport { convertCommand } from \"../commands/convert.js\";\nimport { uploadCommand } from \"../commands/upload.js\";\nimport { doctorCommand } from \"../commands/doctor.js\";\nimport { vibeCommand } from \"../commands/vibe.js\";\n\nexport function buildProgram(): Command {\n const program = new Command();\n\n program\n .name(\"vibespot\")\n .description(\n \"AI-powered HubSpot CMS landing page builder\"\n )\n .version(\"0.3.0\")\n .action(vibeCommand);\n\n program\n .command(\"wizard\")\n .description(\"Classic CLI wizard — step-by-step conversion flow\")\n .action(wizardCommand);\n\n program\n .command(\"init\")\n .description(\"Check and install required tools\")\n .action(initCommand);\n\n program\n .command(\"convert\")\n .description(\"Convert a React project to HubSpot modules\")\n .action(convertCommand);\n\n program\n .command(\"upload\")\n .description(\"Upload theme to HubSpot\")\n .action(uploadCommand);\n\n program\n .command(\"doctor\")\n .description(\"Diagnose environment issues\")\n .action(doctorCommand);\n\n return program;\n}\n","import chalk from \"chalk\";\n\nexport const palette = {\n accent: \"#FF7A59\",\n accentBright: \"#FF9A7A\",\n success: \"#00BDA5\",\n info: \"#0066FF\",\n warn: \"#FFB020\",\n error: \"#E23D2D\",\n muted: \"#8B8D91\",\n vibes: \"#00BDD6\",\n};\n\nconst noColor = !!process.env.NO_COLOR;\n\nfunction hex(color: string) {\n return noColor ? chalk : chalk.hex(color);\n}\n\nexport const theme = {\n accent: hex(palette.accent),\n accentBright: hex(palette.accentBright),\n success: hex(palette.success),\n info: hex(palette.info),\n warn: hex(palette.warn),\n error: hex(palette.error),\n muted: hex(palette.muted),\n vibes: hex(palette.vibes),\n heading: noColor ? chalk.bold : chalk.bold.hex(palette.accent),\n command: hex(palette.accentBright),\n dim: chalk.dim,\n bold: chalk.bold,\n};\n","import { theme } from \"./theme.js\";\n\nconst VERSION = \"0.3.0\";\n\nexport function printBanner() {\n const v = theme.vibes;\n const o = theme.accent; // HubSpot orange for \"Spot\"\n const m = theme.muted;\n\n // Block-pixel ASCII art: \"vibe ≋ Spot\"\n const lines = [\n `${v(\"██ ██ ██ █████ ▄▄▄▄▄\")}${v(\" ≋≋≋≋≋≋≋≋ \")}${o(\"▄▄▄▄▄ █████ ▄▄▄▄ ▀▀██▀▀\")}`,\n `${v(\"██ ██ ██ ██ ██ ██ \")}${v(\" ≋≋≋≋≋≋ \")}${o(\"██ ██ ██ ██ ██ ██ \")}`,\n `${v(\"██ ██ ██ █████ ████ \")}${v(\" ≋≋≋≋ \")}${o(\"▀▀▀▄ █████ ██ ██ ██ \")}`,\n `${v(\" █▄▄█▀ ██ ██ ██ ██ \")}${v(\" ≋≋≋≋≋≋ \")}${o(\" ██ ██ ██ ██ ██ \")}`,\n `${v(\" ▀▀▀ ██ █████ ▀▀▀▀▀\")}${v(\" ≋≋≋≋≋≋≋≋ \")}${o(\"▀▀▀▀ ██ ▀▀▀▀ ██ \")}`,\n ];\n\n console.log();\n for (const line of lines) {\n console.log(` ${line}`);\n }\n console.log();\n console.log(` ${m(\"AI-powered HubSpot Landing Pages\")} ${theme.dim(`v${VERSION}`)}`);\n console.log();\n}\n","import { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { readFileSync, existsSync, readdirSync } from \"node:fs\";\nimport { run } from \"./shell.js\";\nimport { loadConfig, maskApiKey, type AIEngineType } from \"./config.js\";\n\nconst whichCmd = process.platform === \"win32\" ? \"where\" : \"which\";\n\nexport interface ToolInfo {\n name: string;\n found: boolean;\n version: string;\n path: string;\n}\n\nexport function detectNode(): ToolInfo {\n const result = run(\"node --version\");\n return {\n name: \"Node.js\",\n found: result.success,\n version: result.stdout.replace(/^v/, \"\"),\n path: run(`${whichCmd} node`).stdout,\n };\n}\n\nexport function detectGit(): ToolInfo {\n const result = run(\"git --version\");\n return {\n name: \"Git\",\n found: result.success,\n version: result.stdout.replace(\"git version \", \"\"),\n path: run(`${whichCmd} git`).stdout,\n };\n}\n\nexport function detectHubSpotCLI(): ToolInfo {\n const result = run(\"hs --version\");\n return {\n name: \"HubSpot CLI\",\n found: result.success,\n version: result.stdout,\n path: run(`${whichCmd} hs`).stdout,\n };\n}\n\nexport interface CLIToolInfo extends ToolInfo {\n authenticated: boolean;\n authDetail: string;\n}\n\nexport function detectClaudeCode(): CLIToolInfo {\n const result = run(\"claude --version\");\n if (!result.success) {\n return { name: \"Claude Code\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Not installed\" };\n }\n\n // Check for Claude Code auth by looking for credentials\n // Claude Code stores OAuth tokens in ~/.claude/ — if the dir exists with credentials, it's authenticated\n const claudeDir = join(homedir(), \".claude\");\n let authenticated = false;\n let authDetail = \"Not signed in — run `claude` to authenticate\";\n\n try {\n if (existsSync(claudeDir)) {\n // If .claude dir exists with auth files, consider it authenticated\n const files = readdirSync(claudeDir);\n const hasAuth = files.some(f =>\n f.includes(\"credentials\") || f.includes(\"auth\") || f.includes(\"token\") || f === \".credentials.json\"\n );\n if (hasAuth || files.length > 2) {\n // Has some config — likely authenticated\n authenticated = true;\n authDetail = \"Authenticated\";\n }\n }\n } catch { /* ignore */ }\n\n return {\n name: \"Claude Code\",\n found: true,\n version: result.stdout,\n path: run(`${whichCmd} claude`).stdout,\n authenticated,\n authDetail,\n };\n}\n\nexport function detectDataCenter(portalId: string): string {\n try {\n const configPath = join(homedir(), \".hscli\", \"config.yml\");\n if (!existsSync(configPath)) return \"na1\";\n\n const config = readFileSync(configPath, \"utf-8\");\n\n // Find the account block matching this portal ID\n const accountIdx = config.indexOf(`accountId: ${portalId}`);\n if (accountIdx === -1) return \"na1\";\n\n // Look for personalAccessKey after this account entry\n const keyIdx = config.indexOf(\"personalAccessKey:\", accountIdx);\n if (keyIdx === -1) return \"na1\";\n\n // Extract the key value (next non-empty trimmed line after the label)\n const keySection = config.slice(keyIdx, keyIdx + 300);\n const keyMatch = keySection.match(/personalAccessKey:[\\s>-]*\\n\\s+(\\S+)/);\n if (!keyMatch) return \"na1\";\n\n // CiRldTE = base64 prefix for \"eu1\" datacenter in HubSpot personal access keys\n if (keyMatch[1].startsWith(\"CiRldTE\")) return \"eu1\";\n } catch {\n // Fall through to default\n }\n return \"na1\";\n}\n\nexport interface HubSpotAccount {\n name: string;\n portalId: string;\n authType: string;\n isDefault: boolean;\n}\n\nexport function detectHubSpotAuth(): {\n authenticated: boolean;\n portalName: string;\n portalId: string;\n accounts: HubSpotAccount[];\n} {\n const result = run(\"hs accounts list\");\n if (!result.success || !result.stdout) {\n return { authenticated: false, portalName: \"\", portalId: \"\", accounts: [] };\n }\n\n // Parse all accounts from the table\n const accounts: HubSpotAccount[] = [];\n let defaultName = \"\";\n let defaultId = \"\";\n\n // Default account line: \"Account: name [standard] (123456)\"\n const defaultMatch = result.stdout.match(/Account:\\s*(.+?)\\s*\\((\\d+)\\)/);\n if (defaultMatch) {\n defaultName = defaultMatch[1].trim();\n defaultId = defaultMatch[2].trim();\n }\n\n // Parse table rows: \"name [standard] 123456 personalaccesskey\"\n const lines = result.stdout.split(\"\\n\");\n for (const line of lines) {\n const tableMatch = line.match(/^\\s*(.+?)\\s+(\\d{5,})\\s+(.*)/);\n if (tableMatch && !/Account ID/i.test(line) && !/^-+$/.test(line.trim()) && !/^Name\\s/i.test(line.trim())) {\n const name = tableMatch[1].trim();\n const portalId = tableMatch[2].trim();\n const authType = tableMatch[3]?.trim() || \"unknown\";\n accounts.push({\n name,\n portalId,\n authType,\n isDefault: portalId === defaultId,\n });\n }\n }\n\n if (defaultMatch) {\n return {\n authenticated: true,\n portalName: defaultName,\n portalId: defaultId,\n accounts,\n };\n }\n\n // Fallback: at least one account in table\n if (accounts.length > 0) {\n return {\n authenticated: true,\n portalName: accounts[0].name,\n portalId: accounts[0].portalId,\n accounts,\n };\n }\n\n return {\n authenticated: result.stdout.length > 0,\n portalName: \"\",\n portalId: \"\",\n accounts: [],\n };\n}\n\nexport function detectGeminiCLI(): CLIToolInfo {\n const result = run(\"gemini --version\");\n if (!result.success) {\n return { name: \"Gemini CLI\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Not installed\" };\n }\n\n // Gemini CLI uses Google Cloud auth — check for application default credentials\n const adcPath = join(homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\");\n const hasAdc = existsSync(adcPath);\n // Also check GOOGLE_API_KEY / GEMINI_API_KEY env vars\n const hasEnvKey = !!(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || process.env.GOOGLE_AI_API_KEY);\n const authenticated = hasAdc || hasEnvKey;\n\n return {\n name: \"Gemini CLI\",\n found: true,\n version: result.stdout,\n path: run(`${whichCmd} gemini`).stdout,\n authenticated,\n authDetail: authenticated ? \"Authenticated\" : \"Run `gemini` to sign in with Google\",\n };\n}\n\nexport function detectCodexCLI(): CLIToolInfo {\n const result = run(\"codex --version\");\n if (!result.success) {\n return { name: \"OpenAI Codex CLI\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Not installed\" };\n }\n\n // Codex CLI supports OAuth (stored in ~/.codex/auth.json) or OPENAI_API_KEY\n const hasKey = !!(process.env.OPENAI_API_KEY);\n let hasOAuth = false;\n try {\n const authFile = join(homedir(), \".codex\", \"auth.json\");\n if (existsSync(authFile)) {\n const content = readFileSync(authFile, \"utf-8\");\n hasOAuth = content.length > 10; // non-empty auth file\n }\n } catch { /* ignore */ }\n\n const authenticated = hasKey || hasOAuth;\n const detail = hasOAuth ? \"Authenticated (OAuth)\" : hasKey ? \"Authenticated (API key)\" : \"Not authenticated\";\n return {\n name: \"OpenAI Codex CLI\",\n found: true,\n version: result.stdout,\n path: run(`${whichCmd} codex`).stdout,\n authenticated,\n authDetail: detail,\n };\n}\n\nexport function detectGitHubCLI(): ToolInfo {\n const result = run(\"gh --version\");\n return {\n name: \"GitHub CLI\",\n found: result.success,\n version: result.stdout.split(\"\\n\")[0]?.replace(\"gh version \", \"\").split(\" \")[0] || \"\",\n path: run(`${whichCmd} gh`).stdout,\n };\n}\n\nexport function detectGitHubAuth(): { authenticated: boolean; username: string } {\n const result = run(\"gh auth status 2>&1\");\n if (!result.success && !result.stdout) {\n return { authenticated: false, username: \"\" };\n }\n // gh auth status outputs to stderr, but our run() captures both\n const output = result.stdout || result.stderr || \"\";\n const match = output.match(/Logged in to github\\.com.*account\\s+(\\S+)/);\n if (match) {\n return { authenticated: true, username: match[1] };\n }\n // Alternate pattern: \"account borismichel\"\n const altMatch = output.match(/account\\s+(\\S+)/);\n if (altMatch && output.includes(\"Logged in\")) {\n return { authenticated: true, username: altMatch[1] };\n }\n return { authenticated: output.includes(\"Logged in\"), username: \"\" };\n}\n\nexport function hasAnthropicKey(): boolean {\n return !!process.env.ANTHROPIC_API_KEY;\n}\n\nexport function nodeVersionOk(version: string): boolean {\n const major = parseInt(version.split(\".\")[0], 10);\n return major >= 18;\n}\n\nexport function hsCliVersionOk(version: string): boolean {\n const major = parseInt(version.split(\".\")[0], 10);\n return !isNaN(major) && major >= 8;\n}\n\n// ---------------------------------------------------------------------------\n// Comprehensive environment status (used by GET /api/settings/status)\n// ---------------------------------------------------------------------------\n\nexport interface EnvironmentStatus {\n tools: {\n node: ToolInfo;\n git: ToolInfo;\n hubspot: ToolInfo & { authenticated: boolean; portalName: string; portalId: string; accounts: HubSpotAccount[] };\n github: ToolInfo & { authenticated: boolean; username: string };\n claudeCode: CLIToolInfo;\n geminiCli: CLIToolInfo;\n codexCli: CLIToolInfo;\n };\n apiKeys: {\n anthropic: { configured: boolean; masked: string; source: \"config\" | \"env\" | null };\n openai: { configured: boolean; masked: string; source: \"config\" | \"env\" | null };\n gemini: { configured: boolean; masked: string; source: \"config\" | \"env\" | null };\n };\n activeEngine: AIEngineType | null;\n availableEngines: AIEngineType[];\n}\n\nexport function detectEnvironment(): EnvironmentStatus {\n const config = loadConfig();\n\n const node = detectNode();\n const git = detectGit();\n const hs = detectHubSpotCLI();\n const hsAuth = hs.found ? detectHubSpotAuth() : { authenticated: false, portalName: \"\", portalId: \"\", accounts: [] as HubSpotAccount[] };\n const gh = detectGitHubCLI();\n const ghAuth = gh.found ? detectGitHubAuth() : { authenticated: false, username: \"\" };\n const claude = detectClaudeCode();\n const gemini = detectGeminiCLI();\n const codex = detectCodexCLI();\n\n // Determine API key status\n function keyStatus(configKey: string | undefined, ...envVars: string[]): { configured: boolean; masked: string; source: \"config\" | \"env\" | null } {\n if (configKey) return { configured: true, masked: maskApiKey(configKey), source: \"config\" };\n for (const v of envVars) {\n if (process.env[v]) return { configured: true, masked: maskApiKey(process.env[v]!), source: \"env\" };\n }\n return { configured: false, masked: \"\", source: null };\n }\n\n const anthropicKey = keyStatus(config.anthropicApiKey, \"ANTHROPIC_API_KEY\");\n const openaiKey = keyStatus(config.openaiApiKey, \"OPENAI_API_KEY\");\n const geminiKey = keyStatus(config.geminiApiKey, \"GEMINI_API_KEY\", \"GOOGLE_AI_API_KEY\");\n\n // Build available engines — CLI tools must be authenticated to be usable\n const available: AIEngineType[] = [];\n if (claude.found && claude.authenticated) available.push(\"claude-code\");\n if (anthropicKey.configured) available.push(\"anthropic-api\");\n if (openaiKey.configured) available.push(\"openai-api\");\n if (gemini.found && gemini.authenticated) available.push(\"gemini-cli\");\n if (geminiKey.configured) available.push(\"gemini-api\");\n if (codex.found && codex.authenticated) available.push(\"codex-cli\");\n\n return {\n tools: {\n node,\n git,\n hubspot: { ...hs, ...hsAuth },\n github: { ...gh, ...ghAuth },\n claudeCode: claude,\n geminiCli: gemini,\n codexCli: codex,\n },\n apiKeys: {\n anthropic: anthropicKey,\n openai: openaiKey,\n gemini: geminiKey,\n },\n activeEngine: config.aiEngine || null,\n availableEngines: available,\n };\n}\n","import { execSync, type ExecSyncOptions } from \"node:child_process\";\n\nexport interface ShellResult {\n stdout: string;\n stderr: string;\n success: boolean;\n}\n\nexport function run(\n command: string,\n options: ExecSyncOptions = {}\n): ShellResult {\n try {\n const stdout = execSync(command, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120_000,\n ...options,\n }).trim();\n return { stdout, stderr: \"\", success: true };\n } catch (err: unknown) {\n const e = err as { stdout?: Buffer | string; stderr?: Buffer | string };\n const stdout = (e.stdout ?? \"\").toString().trim();\n const stderr = (e.stderr ?? \"\").toString().trim();\n return { stdout, stderr, success: false };\n }\n}\n\nexport function runOrThrow(\n command: string,\n options: ExecSyncOptions = {}\n): string {\n return execSync(command, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120_000,\n ...options,\n }).trim();\n}\n\nexport function runPassthrough(\n command: string,\n options: ExecSyncOptions = {}\n): boolean {\n try {\n execSync(command, {\n stdio: \"inherit\",\n timeout: 300_000,\n ...options,\n });\n return true;\n } catch {\n return false;\n }\n}\n","import { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { readFile, writeFile, fileExists } from \"./fs.js\";\n\nexport type AIEngineType =\n | \"claude-code\"\n | \"anthropic-api\"\n | \"openai-api\"\n | \"gemini-cli\"\n | \"gemini-api\"\n | \"codex-cli\"\n // Legacy value — migrated to \"anthropic-api\" on load\n | \"api\";\n\nexport interface VibeSpotConfig {\n aiEngine?: AIEngineType;\n anthropicApiKey?: string;\n openaiApiKey?: string;\n geminiApiKey?: string;\n claudeCodeModel?: string;\n anthropicApiModel?: string;\n openaiApiModel?: string;\n lastThemePath?: string;\n lastSourcePath?: string;\n}\n\nconst CONFIG_DIR = join(homedir(), \".vibespot\");\nconst CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\n\nexport function loadConfig(): VibeSpotConfig {\n if (!fileExists(CONFIG_PATH)) return {};\n\n try {\n const raw = JSON.parse(readFile(CONFIG_PATH));\n // Migrate legacy \"api\" engine type\n if (raw.aiEngine === \"api\") {\n raw.aiEngine = \"anthropic-api\";\n }\n return raw;\n } catch {\n return {};\n }\n}\n\n/**\n * Get the API key for a given engine, checking config first then env vars.\n */\nexport function getApiKeyForEngine(engine: AIEngineType, config?: VibeSpotConfig): string | undefined {\n const c = config || loadConfig();\n switch (engine) {\n case \"anthropic-api\":\n case \"api\":\n return c.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n case \"openai-api\":\n return c.openaiApiKey || process.env.OPENAI_API_KEY;\n case \"gemini-api\":\n return c.geminiApiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY;\n default:\n return undefined;\n }\n}\n\n/**\n * Mask an API key for display (show first 7 + last 4 chars).\n */\nexport function maskApiKey(key: string): string {\n if (key.length <= 12) return \"***\";\n return key.slice(0, 7) + \"...\" + key.slice(-4);\n}\n\nexport function saveConfig(config: VibeSpotConfig): void {\n const existing = loadConfig();\n const merged = { ...existing, ...config };\n writeFile(CONFIG_PATH, JSON.stringify(merged, null, 2));\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport function readFile(path: string): string {\n return readFileSync(path, \"utf-8\");\n}\n\nexport function writeFile(path: string, content: string): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content, \"utf-8\");\n}\n\nexport function fileExists(path: string): boolean {\n return existsSync(path);\n}\n\nexport function ensureDir(path: string): void {\n mkdirSync(path, { recursive: true });\n}\n\nexport function resolveAsset(name: string): string {\n // In built package, assets/ is at the package root\n // During dev, it's relative to the project root\n const paths = [\n join(import.meta.dirname, \"../../assets\", name),\n join(import.meta.dirname, \"../assets\", name),\n join(process.cwd(), \"assets\", name),\n ];\n\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n\n throw new Error(`Asset not found: ${name}`);\n}\n","import * as p from \"@clack/prompts\";\nimport { theme } from \"../cli/theme.js\";\n\nexport function isCancel(value: unknown): value is symbol {\n return p.isCancel(value);\n}\n\nexport function handleCancel(value: unknown): void {\n if (p.isCancel(value)) {\n p.cancel(theme.muted(\"Operation cancelled.\"));\n process.exit(0);\n }\n}\n\nexport async function intro(title: string): Promise<void> {\n p.intro(theme.heading(title));\n}\n\nexport async function outro(message: string): Promise<void> {\n p.outro(theme.success(message));\n}\n\nexport async function note(message: string, title?: string): Promise<void> {\n p.note(message, title ? theme.heading(title) : undefined);\n}\n\nexport async function text(opts: {\n message: string;\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | undefined;\n}): Promise<string> {\n const result = await p.text({\n message: theme.accent(opts.message),\n placeholder: opts.placeholder,\n defaultValue: opts.defaultValue,\n validate: opts.validate,\n });\n handleCancel(result);\n return result as string;\n}\n\nexport async function confirm(opts: {\n message: string;\n initialValue?: boolean;\n}): Promise<boolean> {\n const result = await p.confirm({\n message: theme.accent(opts.message),\n initialValue: opts.initialValue ?? true,\n });\n handleCancel(result);\n return result as boolean;\n}\n\nexport async function select<T extends string>(opts: {\n message: string;\n options: { value: T; label: string; hint?: string }[];\n}): Promise<T> {\n const result = await p.select({\n message: theme.accent(opts.message),\n options: opts.options,\n });\n handleCancel(result);\n return result as T;\n}\n\nexport async function spinner(): Promise<{\n start: (msg: string) => void;\n stop: (msg: string) => void;\n message: (msg: string) => void;\n}> {\n const s = p.spinner();\n return {\n start: (msg: string) => s.start(theme.muted(msg)),\n stop: (msg: string) => s.stop(theme.success(msg)),\n message: (msg: string) => s.message(theme.muted(msg)),\n };\n}\n\nexport function log(message: string): void {\n p.log.info(message);\n}\n\nexport function logSuccess(message: string): void {\n p.log.success(theme.success(message));\n}\n\nexport function logWarn(message: string): void {\n p.log.warn(theme.warn(message));\n}\n\nexport function logError(message: string): void {\n p.log.error(theme.error(message));\n}\n\nexport function logStep(message: string): void {\n p.log.step(theme.accent(message));\n}\n","import {\n detectNode,\n detectGit,\n detectHubSpotCLI,\n detectClaudeCode,\n detectGeminiCLI,\n detectCodexCLI,\n detectHubSpotAuth,\n hasAnthropicKey,\n nodeVersionOk,\n} from \"../utils/detect.js\";\nimport { run, runPassthrough } from \"../utils/shell.js\";\nimport { saveConfig, loadConfig, type AIEngineType } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport interface PreflightResult {\n aiEngine: AIEngineType;\n model?: string;\n portalId: string;\n portalName: string;\n}\n\nexport async function runPreflight(): Promise<PreflightResult> {\n await ui.intro(\"Checking your environment\");\n\n // Node.js\n const node = detectNode();\n if (!node.found) {\n ui.logError(\"Node.js not found. Install it from https://nodejs.org\");\n process.exit(1);\n }\n if (!nodeVersionOk(node.version)) {\n ui.logError(\n `Node.js ${node.version} is too old. Version 18+ required. Update at https://nodejs.org`\n );\n process.exit(1);\n }\n ui.logSuccess(`Node.js v${node.version}`);\n\n // Git\n const git = detectGit();\n if (!git.found) {\n ui.logError(\"Git not found. Install it from https://git-scm.com\");\n process.exit(1);\n }\n ui.logSuccess(`Git ${git.version}`);\n\n // HubSpot CLI\n let hs = detectHubSpotCLI();\n if (!hs.found) {\n ui.logWarn(\"HubSpot CLI not found\");\n await ui.note(\n \"The HubSpot CLI is required to upload your theme.\\nI'll install it for you now.\",\n \"Missing dependency\"\n );\n\n const install = await ui.confirm({\n message: \"Install HubSpot CLI globally?\",\n });\n\n if (!install) {\n ui.logError(\n \"HubSpot CLI is required. Install manually: npm install -g @hubspot/cli\"\n );\n process.exit(1);\n }\n\n const s = await ui.spinner();\n s.start(\"Installing HubSpot CLI...\");\n\n const result = run(\"npm install -g @hubspot/cli\");\n if (!result.success) {\n s.stop(\"Failed to install HubSpot CLI\");\n ui.logError(\"Try running manually: npm install -g @hubspot/cli\");\n process.exit(1);\n }\n\n hs = detectHubSpotCLI();\n s.stop(`HubSpot CLI v${hs.version} installed`);\n } else {\n ui.logSuccess(`HubSpot CLI v${hs.version}`);\n }\n\n // HubSpot authentication\n let auth = detectHubSpotAuth();\n if (!auth.authenticated) {\n ui.logWarn(\"HubSpot not authenticated\");\n await ui.note(\n \"You need to connect the CLI to your HubSpot account.\\nThis will open a browser window — log in and authorize.\",\n \"Authentication required\"\n );\n\n const doAuth = await ui.confirm({ message: \"Run `hs init` now?\" });\n\n if (!doAuth) {\n ui.logError(\"HubSpot authentication is required. Run `hs init` manually.\");\n process.exit(1);\n }\n\n const s = await ui.spinner();\n s.start(\"Waiting for HubSpot authentication...\");\n\n const authOk = runPassthrough(\"hs init\");\n if (!authOk) {\n s.stop(\"Authentication failed\");\n ui.logError(\"HubSpot authentication failed. Try running `hs init` manually.\");\n process.exit(1);\n }\n\n auth = detectHubSpotAuth();\n s.stop(\n `Connected to portal${auth.portalName ? `: ${auth.portalName}` : \"\"} (ID: ${auth.portalId})`\n );\n } else {\n ui.logSuccess(\n `HubSpot portal${auth.portalName ? `: ${auth.portalName}` : \"\"} (ID: ${auth.portalId})`\n );\n }\n\n // AI Engine selection\n const claude = detectClaudeCode();\n const gemini = detectGeminiCLI();\n const codex = detectCodexCLI();\n const hasKey = hasAnthropicKey();\n const config = loadConfig();\n\n const engineLabels: Record<AIEngineType, string> = {\n \"claude-code\": \"Claude Code\",\n \"api\": \"Anthropic API\",\n \"anthropic-api\": \"Anthropic API\",\n \"openai-api\": \"OpenAI API\",\n \"gemini-api\": \"Gemini API\",\n \"gemini-cli\": \"Gemini CLI\",\n \"codex-cli\": \"OpenAI Codex\",\n };\n\n let aiEngine: AIEngineType;\n const lastUsed = config.aiEngine;\n\n // Always build list of available engines\n const available: { value: AIEngineType; label: string; hint: string }[] = [];\n\n if (claude.found) {\n available.push({\n value: \"claude-code\",\n label: \"Claude Code\",\n hint: lastUsed === \"claude-code\"\n ? \"last used — recommended\"\n : \"uses your existing Claude subscription — recommended\",\n });\n }\n if (gemini.found) {\n available.push({\n value: \"gemini-cli\",\n label: \"Gemini CLI\",\n hint: lastUsed === \"gemini-cli\"\n ? \"last used\"\n : \"uses your existing Gemini setup\",\n });\n }\n if (codex.found) {\n available.push({\n value: \"codex-cli\",\n label: \"OpenAI Codex\",\n hint: lastUsed === \"codex-cli\"\n ? \"last used\"\n : \"uses your existing OpenAI setup\",\n });\n }\n if (hasKey) {\n available.push({\n value: \"api\",\n label: \"Anthropic API\",\n hint: lastUsed === \"api\"\n ? \"last used\"\n : \"uses your API key\",\n });\n }\n\n // Sort last-used engine to the top\n if (lastUsed) {\n available.sort((a, b) =>\n a.value === lastUsed ? -1 : b.value === lastUsed ? 1 : 0\n );\n }\n\n if (available.length === 1) {\n // Only one option — use it automatically\n aiEngine = available[0].value;\n ui.logSuccess(`AI engine: ${engineLabels[aiEngine]} (auto-detected)`);\n } else if (available.length > 1) {\n // Multiple available — always ask\n aiEngine = await ui.select({\n message: \"Choose your AI engine:\",\n options: available,\n });\n } else {\n // None available — guide the user\n await ui.note(\n \"You need an AI coding assistant to power the conversion.\\n\\n\" +\n `${theme.bold(\"Option 1:\")} Install Claude Code ${theme.muted(\"(recommended)\")}\\n` +\n \" https://claude.ai/code\\n\\n\" +\n `${theme.bold(\"Option 2:\")} Install Gemini CLI\\n` +\n \" https://github.com/google-gemini/gemini-cli\\n\\n\" +\n `${theme.bold(\"Option 3:\")} Install OpenAI Codex\\n` +\n \" https://github.com/openai/codex\\n\\n\" +\n `${theme.bold(\"Option 4:\")} Set an Anthropic API key\\n` +\n \" export ANTHROPIC_API_KEY=sk-ant-...\\n\" +\n \" (get one at https://console.anthropic.com)\",\n \"AI engine required\"\n );\n\n aiEngine = await ui.select({\n message: \"Which will you set up?\",\n options: [\n {\n value: \"claude-code\" as const,\n label: \"Claude Code\",\n hint: \"I'll install it now\",\n },\n {\n value: \"gemini-cli\" as const,\n label: \"Gemini CLI\",\n hint: \"I'll install it now\",\n },\n {\n value: \"codex-cli\" as const,\n label: \"OpenAI Codex\",\n hint: \"I'll install it now\",\n },\n {\n value: \"api\" as const,\n label: \"Anthropic API\",\n hint: \"I'll enter my key\",\n },\n ],\n });\n\n if (aiEngine === \"api\") {\n const key = await ui.text({\n message: \"Enter your Anthropic API key:\",\n placeholder: \"sk-ant-api03-...\",\n validate: (v) =>\n v.startsWith(\"sk-ant-\") ? undefined : \"Key should start with sk-ant-\",\n });\n process.env.ANTHROPIC_API_KEY = key;\n saveConfig({ anthropicApiKey: key });\n }\n }\n\n // Model selection for Claude Code\n let model: string | undefined;\n if (aiEngine === \"claude-code\") {\n model = await ui.select({\n message: \"Which model?\",\n options: [\n { value: \"sonnet\", label: \"Sonnet\", hint: \"fast, recommended\" },\n { value: \"opus\", label: \"Opus\", hint: \"most capable\" },\n { value: \"haiku\", label: \"Haiku\", hint: \"fastest, cheapest\" },\n ],\n });\n }\n\n saveConfig({ aiEngine });\n\n await ui.outro(\"Environment ready!\");\n\n return {\n aiEngine,\n model,\n portalId: auth.portalId,\n portalName: auth.portalName,\n };\n}\n","import { readdirSync, statSync } from \"node:fs\";\nimport { join, basename, extname } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport interface ComponentInfo {\n name: string;\n path: string;\n description: string;\n}\n\nexport interface SourceAnalysis {\n sourceDir: string;\n wasCloned: boolean;\n components: ComponentInfo[];\n hasTailwind: boolean;\n cssVarCount: number;\n fonts: string[];\n interactions: string[];\n}\n\nfunction findComponents(dir: string): ComponentInfo[] {\n const components: ComponentInfo[] = [];\n\n // Common locations for landing page components\n const searchDirs = [\n join(dir, \"src/components/landing\"),\n join(dir, \"src/components/sections\"),\n join(dir, \"src/components\"),\n join(dir, \"src/pages\"),\n join(dir, \"app/components\"),\n join(dir, \"components\"),\n ];\n\n for (const searchDir of searchDirs) {\n if (!fileExists(searchDir)) continue;\n\n try {\n const files = readdirSync(searchDir);\n for (const file of files) {\n const filePath = join(searchDir, file);\n const stat = statSync(filePath);\n if (!stat.isFile()) continue;\n\n const ext = extname(file);\n if (![\".tsx\", \".jsx\"].includes(ext)) continue;\n\n // Skip utility/UI components\n const name = basename(file, ext);\n if (name.startsWith(\"ui\") || name === \"index\") continue;\n\n // Read the file to extract a description\n const content = readFile(filePath);\n const desc = describeComponent(name, content);\n\n components.push({ name, path: filePath, description: desc });\n }\n } catch {\n // Directory read failed, skip\n }\n }\n\n return components;\n}\n\nfunction describeComponent(name: string, content: string): string {\n const hints: string[] = [];\n\n if (/carousel|slider|swiper|embla/i.test(content)) hints.push(\"carousel\");\n if (/accordion|collapsible|expand/i.test(content)) hints.push(\"accordion\");\n if (/form|submit|input.*email/i.test(content)) hints.push(\"form\");\n if (/nav|navigation|menu/i.test(content)) hints.push(\"navigation\");\n if (/hero|headline|tagline/i.test(content)) hints.push(\"hero\");\n if (/footer|copyright/i.test(content)) hints.push(\"footer\");\n if (/testimonial|quote|review/i.test(content)) hints.push(\"testimonials\");\n if (/pricing|plan|tier/i.test(content)) hints.push(\"pricing\");\n if (/faq|question.*answer/i.test(content)) hints.push(\"FAQ\");\n if (/feature|benefit|advantage/i.test(content)) hints.push(\"features\");\n if (/contact|get.in.touch/i.test(content)) hints.push(\"contact\");\n if (/cta|call.to.action/i.test(content)) hints.push(\"CTA\");\n if (/team|member|bio/i.test(content)) hints.push(\"team\");\n\n if (hints.length === 0) {\n // Fallback: infer from component name\n const readable = name\n .replace(/Section$/, \"\")\n .replace(/([A-Z])/g, \" $1\")\n .trim();\n return readable;\n }\n\n return hints.join(\", \");\n}\n\nfunction analyzeCSS(dir: string): { varCount: number; fonts: string[] } {\n const cssFiles = [\n join(dir, \"src/index.css\"),\n join(dir, \"src/globals.css\"),\n join(dir, \"src/app/globals.css\"),\n join(dir, \"app/globals.css\"),\n ];\n\n let varCount = 0;\n const fonts: string[] = [];\n\n for (const cssFile of cssFiles) {\n if (!fileExists(cssFile)) continue;\n\n const content = readFile(cssFile);\n const varMatches = content.match(/--[\\w-]+:/g);\n if (varMatches) varCount += varMatches.length;\n\n const fontMatches = content.match(\n /font-family:\\s*['\"]([^'\"]+)['\"]/g\n );\n if (fontMatches) {\n for (const m of fontMatches) {\n const font = m.match(/['\"]([^'\"]+)['\"]/)?.[1];\n if (font && !fonts.includes(font)) fonts.push(font);\n }\n }\n\n const importMatches = content.match(\n /@import\\s+url\\([^)]*fonts\\.googleapis\\.com[^)]*family=([^&)]+)/g\n );\n if (importMatches) {\n for (const m of importMatches) {\n const font = m.match(/family=([^&)]+)/)?.[1]?.replace(/\\+/g, \" \");\n if (font && !fonts.includes(font)) fonts.push(font);\n }\n }\n }\n\n return { varCount, fonts };\n}\n\nfunction detectInteractions(dir: string): string[] {\n const interactions: string[] = [];\n\n const hooksDir = join(dir, \"src/hooks\");\n if (fileExists(hooksDir)) {\n try {\n const hooks = readdirSync(hooksDir);\n for (const hook of hooks) {\n if (/scroll/i.test(hook)) interactions.push(\"Scroll animations\");\n if (/intersection/i.test(hook)) interactions.push(\"Scroll animations\");\n }\n } catch {\n // Ignore\n }\n }\n\n // Check landing components for patterns\n const componentDir = join(dir, \"src/components/landing\");\n if (fileExists(componentDir)) {\n try {\n const files = readdirSync(componentDir);\n for (const file of files) {\n if (!file.endsWith(\".tsx\") && !file.endsWith(\".jsx\")) continue;\n const content = readFile(join(componentDir, file));\n if (/carousel|embla|swiper/i.test(content) && !interactions.includes(\"Carousel\"))\n interactions.push(\"Carousel\");\n if (/accordion|collapsible/i.test(content) && !interactions.includes(\"Accordion\"))\n interactions.push(\"Accordion\");\n if (/typing|typewriter/i.test(content) && !interactions.includes(\"Typing animation\"))\n interactions.push(\"Typing animation\");\n if (/parallax|requestAnimationFrame/i.test(content) && !interactions.includes(\"Parallax\"))\n interactions.push(\"Parallax\");\n }\n } catch {\n // Ignore\n }\n }\n\n if (interactions.length === 0) {\n interactions.push(\"Scroll animations\");\n }\n\n return interactions;\n}\n\n/**\n * Headless source analysis — called from the vibe server (no interactive prompts).\n * Clones the repo if it's a URL, then analyzes components.\n */\nexport function analyzeSource(input: string): SourceAnalysis {\n let sourceDir: string;\n let wasCloned = false;\n\n if (input.startsWith(\"http\") || input.startsWith(\"git@\")) {\n wasCloned = true;\n const repoName =\n basename(input.replace(/\\.git$/, \"\")) || \"react-source\";\n sourceDir = join(process.cwd(), \"workspace\", repoName);\n\n if (!fileExists(sourceDir)) {\n const result = run(`git clone --depth 1 \"${input}\" \"${sourceDir}\"`);\n if (!result.success) {\n throw new Error(`Failed to clone ${input}: ${result.stderr}`);\n }\n }\n } else {\n sourceDir = input;\n if (!fileExists(sourceDir)) {\n throw new Error(`Directory not found: ${sourceDir}`);\n }\n }\n\n const components = findComponents(sourceDir);\n const hasTailwind =\n fileExists(join(sourceDir, \"tailwind.config.ts\")) ||\n fileExists(join(sourceDir, \"tailwind.config.js\"));\n const { varCount, fonts } = analyzeCSS(sourceDir);\n const interactions = detectInteractions(sourceDir);\n\n return {\n sourceDir,\n wasCloned,\n components,\n hasTailwind,\n cssVarCount: varCount,\n fonts,\n interactions,\n };\n}\n\nexport async function setupSource(): Promise<SourceAnalysis> {\n await ui.intro(\"Source Project\");\n\n const input = await ui.text({\n message: \"GitHub URL or local path to your React project:\",\n placeholder: \"https://github.com/user/my-lovable-page\",\n validate: (v) => {\n if (!v.trim()) return \"Please enter a URL or path\";\n return undefined;\n },\n });\n\n let sourceDir: string;\n let wasCloned = false;\n\n if (input.startsWith(\"http\") || input.startsWith(\"git@\")) {\n wasCloned = true;\n // Clone from GitHub\n const repoName =\n basename(input.replace(/\\.git$/, \"\")) || \"react-source\";\n sourceDir = join(process.cwd(), \"workspace\", repoName);\n\n if (fileExists(sourceDir)) {\n // Already cloned from a previous run — reuse it\n ui.logSuccess(`Using existing clone: ${theme.dim(sourceDir)}`);\n } else {\n const s = await ui.spinner();\n s.start(\"Cloning repository...\");\n\n const result = run(`git clone --depth 1 \"${input}\" \"${sourceDir}\"`);\n if (!result.success) {\n s.stop(\"Clone failed\");\n ui.logError(\n `Failed to clone ${input}. Check the URL and your access permissions.`\n );\n process.exit(1);\n }\n\n s.stop(`Cloned to ${theme.dim(sourceDir)}`);\n }\n } else {\n sourceDir = input;\n if (!fileExists(sourceDir)) {\n ui.logError(`Directory not found: ${sourceDir}`);\n process.exit(1);\n }\n ui.logSuccess(`Using local source: ${theme.dim(sourceDir)}`);\n }\n\n // Analyze\n const s = await ui.spinner();\n s.start(\"Analyzing project structure...\");\n\n const components = findComponents(sourceDir);\n const hasTailwind =\n fileExists(join(sourceDir, \"tailwind.config.ts\")) ||\n fileExists(join(sourceDir, \"tailwind.config.js\"));\n const { varCount, fonts } = analyzeCSS(sourceDir);\n const interactions = detectInteractions(sourceDir);\n\n s.stop(`Found ${components.length} landing page components`);\n\n if (components.length === 0) {\n ui.logWarn(\n \"No components found. Make sure the React source has .tsx/.jsx files in src/components/\"\n );\n process.exit(1);\n }\n\n // Show summary\n const componentList = components\n .map((c, i) => ` ${theme.dim(`${i + 1}.`)} ${theme.bold(c.name)} ${theme.muted(`— ${c.description}`)}`)\n .join(\"\\n\");\n\n const cssInfo = hasTailwind\n ? `Tailwind + custom CSS (${varCount} variables)`\n : `Custom CSS (${varCount} variables)`;\n const fontInfo = fonts.length > 0 ? fonts.join(\", \") : \"System fonts\";\n const jsInfo = interactions.join(\", \");\n\n await ui.note(\n `${componentList}\\n\\n CSS: ${cssInfo}\\n JS: ${jsInfo}\\n Font: ${fontInfo}`,\n `${components.length} components detected`\n );\n\n const ok = await ui.confirm({ message: \"Does this look right?\" });\n if (!ok) {\n ui.logError(\"Please adjust your source directory and try again.\");\n process.exit(0);\n }\n\n await ui.outro(\"Source analyzed!\");\n\n return {\n sourceDir,\n wasCloned,\n components,\n hasTailwind,\n cssVarCount: varCount,\n fonts,\n interactions,\n };\n}\n","import { join } from \"node:path\";\nimport { readdirSync, renameSync } from \"node:fs\";\nimport { run, runPassthrough } from \"../utils/shell.js\";\nimport { fileExists, readFile, writeFile, ensureDir } from \"../utils/fs.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport interface ThemeInfo {\n themePath: string;\n themeName: string;\n}\n\nexport async function setupTheme(): Promise<ThemeInfo> {\n await ui.intro(\"HubSpot Theme Setup\");\n\n const choice = await ui.select({\n message: \"Do you have an existing HubSpot theme?\",\n options: [\n {\n value: \"fetch\" as const,\n label: \"Fetch my existing theme from HubSpot\",\n hint: \"downloads your current theme\",\n },\n {\n value: \"create\" as const,\n label: \"Start fresh (HubSpot Boilerplate)\",\n hint: \"creates a new starter theme\",\n },\n ],\n });\n\n let themeName: string;\n let themePath: string;\n\n const workspaceDir = join(process.cwd(), \"workspace\");\n ensureDir(workspaceDir);\n\n if (choice === \"fetch\") {\n themeName = await ui.text({\n message: \"What's your theme name in HubSpot?\",\n placeholder: \"My-Company-Theme\",\n validate: (v) =>\n v.trim() ? undefined : \"Theme name is required\",\n });\n\n themePath = join(workspaceDir, themeName);\n\n const s = await ui.spinner();\n s.start(\"Fetching theme from HubSpot...\");\n\n const result = run(`hs cms fetch \"${themeName}\" \"${themePath}\"`);\n if (!result.success) {\n s.stop(\"Fetch failed\");\n ui.logError(\n `Could not fetch theme \"${themeName}\". Check the name in HubSpot Design Manager.`\n );\n ui.logError('Run `hs cms list /` to see available themes.');\n process.exit(1);\n }\n\n s.stop(`Theme fetched: ${theme.dim(themePath)}`);\n } else {\n themeName = await ui.text({\n message: \"Name for your new theme:\",\n placeholder: \"my-theme\",\n defaultValue: \"my-theme\",\n });\n\n themePath = join(workspaceDir, themeName);\n\n const s = await ui.spinner();\n s.start(\"Creating theme from boilerplate...\");\n\n // Snapshot cwd contents before hs create to detect what it creates\n const cwdBefore = new Set(readdirSync(process.cwd()));\n\n // hs create always creates in process.cwd(), ignoring execSync cwd\n const result = run(`hs cms theme create \"${themeName}\"`);\n\n // Find the created directory — hs create may use exact name or a variant\n let createdAt = join(process.cwd(), themeName);\n if (!fileExists(createdAt)) {\n // Fallback: find any new directory that appeared in cwd\n const cwdAfter = readdirSync(process.cwd());\n const newDir = cwdAfter.find((e) => !cwdBefore.has(e) && fileExists(join(process.cwd(), e)));\n if (newDir) {\n createdAt = join(process.cwd(), newDir);\n }\n }\n\n if (!result.success || !fileExists(createdAt)) {\n s.stop(\"Creation failed\");\n const errMsg = result.stderr || result.stdout || \"\";\n ui.logError(\n `Could not create theme \"${themeName}\".` +\n (errMsg ? `\\n${errMsg.slice(0, 300)}` : \"\") +\n \"\\nTry running manually: hs cms theme create my-theme\"\n );\n process.exit(1);\n }\n\n // Move from cwd into workspace/\n if (createdAt !== themePath) {\n renameSync(createdAt, themePath);\n }\n\n s.stop(`Theme created: ${theme.dim(themePath)}`);\n\n // Rename theme label from \"CMS theme boilerplate\" to the user's chosen name\n const themeJsonPath = join(themePath, \"theme.json\");\n if (fileExists(themeJsonPath)) {\n try {\n const themeJson = JSON.parse(readFile(themeJsonPath));\n themeJson.label = themeName;\n writeFile(themeJsonPath, JSON.stringify(themeJson, null, 2) + \"\\n\");\n ui.logSuccess(`Theme label set to \"${themeName}\"`);\n } catch {\n ui.logWarn(\"Could not update theme.json label — you can rename it manually in HubSpot.\");\n }\n }\n }\n\n // Validate and patch\n await ui.intro(\"Checking theme compatibility\");\n\n const baseHtmlPath = join(themePath, \"templates/layouts/base.html\");\n if (!fileExists(baseHtmlPath)) {\n ui.logError(\n `base.html not found at ${baseHtmlPath}. Your theme may have a different structure.`\n );\n process.exit(1);\n }\n ui.logSuccess(\"base.html found\");\n\n // Check for template_css and template_js support\n let baseHtml = readFile(baseHtmlPath);\n let patched = false;\n\n if (!baseHtml.includes(\"template_css\")) {\n ui.logWarn(\"Missing template_css support in base.html\");\n\n // Find the line with require_css for theme-overrides or the last require_css\n const cssInsertPoint =\n baseHtml.indexOf(\"theme-overrides.css\") !== -1\n ? baseHtml.indexOf(\n \"{{\",\n baseHtml.lastIndexOf(\"\\n\", baseHtml.indexOf(\"theme-overrides.css\"))\n )\n : baseHtml.lastIndexOf(\"require_css\");\n\n if (cssInsertPoint > 0) {\n const insertBefore = baseHtml.lastIndexOf(\"\\n\", cssInsertPoint);\n const block = `\\n {% if template_css %}\\n {{ require_css(get_asset_url(template_css)) }}\\n {% endif %}`;\n baseHtml =\n baseHtml.slice(0, insertBefore) + block + baseHtml.slice(insertBefore);\n patched = true;\n }\n } else {\n ui.logSuccess(\"template_css support\");\n }\n\n if (!baseHtml.includes(\"template_js\")) {\n ui.logWarn(\"Missing template_js support in base.html\");\n\n // Find the line with require_js for main.js or the last require_js\n const jsLine = baseHtml.indexOf(\"require_js\");\n if (jsLine > 0) {\n const lineEnd = baseHtml.indexOf(\"\\n\", jsLine);\n // Find the end of the require_js line (including closing tags)\n const nextLine = baseHtml.indexOf(\"\\n\", lineEnd + 1);\n const block = `\\n {% if template_js %}\\n {{ require_js(get_asset_url(template_js)) }}\\n {% endif %}`;\n const insertAt =\n baseHtml.indexOf(\"}}\", jsLine) + 2 + baseHtml.slice(baseHtml.indexOf(\"}}\", jsLine) + 2).indexOf(\"\\n\") + 1;\n baseHtml =\n baseHtml.slice(0, baseHtml.indexOf(\"\\n\", baseHtml.indexOf(\"}}\", jsLine) + 2)) +\n block +\n baseHtml.slice(baseHtml.indexOf(\"\\n\", baseHtml.indexOf(\"}}\", jsLine) + 2));\n patched = true;\n }\n } else {\n ui.logSuccess(\"template_js support\");\n }\n\n if (patched) {\n const s = await ui.spinner();\n s.start(\"Patching base.html...\");\n writeFile(baseHtmlPath, baseHtml);\n s.stop(\"base.html patched with template_css/template_js support\");\n }\n\n // Check .hsignore\n const hsignorePath = join(themePath, \".hsignore\");\n if (fileExists(hsignorePath)) {\n const hsignore = readFile(hsignorePath);\n if (!hsignore.includes(\"docs/\")) {\n writeFile(hsignorePath, hsignore + \"\\ndocs/\\n\");\n ui.logSuccess(\"Added docs/ to .hsignore\");\n }\n } else {\n writeFile(hsignorePath, \"docs/\\n*.md\\nnode_modules/\\n.git\\n\");\n ui.logSuccess(\"Created .hsignore\");\n }\n\n await ui.outro(\"Theme ready!\");\n\n return { themePath, themeName };\n}\n","import { join } from \"node:path\";\nimport { readdirSync, rmSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets } from \"../ai/engine.js\";\nimport type { AIEngineType } from \"../utils/config.js\";\nimport { ClaudeCodeEngine } from \"../ai/claude-code.js\";\nimport { ClaudeAPIEngine } from \"../ai/claude-api.js\";\nimport { GeminiCLIEngine } from \"../ai/gemini-cli.js\";\nimport { CodexCLIEngine } from \"../ai/codex-cli.js\";\nimport { getConversionGuide } from \"../ai/prompts.js\";\nimport { readFile, writeFile, fileExists } from \"../utils/fs.js\";\nimport * as ui from \"../prompts/prompter.js\";\n\nfunction createEngine(type: AIEngineType, model?: string): AIEngine {\n switch (type) {\n case \"claude-code\":\n return new ClaudeCodeEngine(model);\n case \"gemini-cli\":\n return new GeminiCLIEngine();\n case \"codex-cli\":\n return new CodexCLIEngine();\n case \"api\":\n return new ClaudeAPIEngine();\n }\n}\n\nexport async function runConversion(opts: {\n aiEngine: AIEngineType;\n model?: string;\n sourceDir: string;\n themePath: string;\n}): Promise<GeneratedAssets> {\n await ui.intro(\"Converting React to HubSpot Modules\");\n\n await ui.note(\n \"AI will now analyze your React code and create\\nHubSpot-native modules. This takes 2-5 minutes.\",\n \"AI Conversion\"\n );\n\n const engine = createEngine(opts.aiEngine, opts.model);\n\n const conversionGuide = getConversionGuide();\n\n const s = await ui.spinner();\n s.start(\"Starting AI conversion...\");\n\n const startTime = Date.now();\n\n const result = await engine.convert({\n sourceDir: opts.sourceDir,\n themePath: opts.themePath,\n conversionGuide,\n onProgress: (step, detail) => {\n if (step === \"created\") {\n ui.logSuccess(detail);\n } else {\n s.message(detail);\n }\n },\n });\n\n const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);\n s.stop(`AI conversion complete (${elapsed}s)`);\n\n // Validate and auto-fix all known HubSpot issues before upload\n const fixes = validateAndFix(opts.themePath);\n for (const fix of fixes) {\n ui.logSuccess(`Auto-fixed: ${fix}`);\n }\n\n // Show conversion checklist\n const checklist = buildChecklist(opts.themePath, result);\n const lines: string[] = [];\n for (const item of checklist) {\n const icon = item.passed ? \"\\u2705\" : \"\\u274c\";\n const severity = !item.passed ? (item.critical ? \" (CRITICAL)\" : \" (cosmetic)\") : \"\";\n lines.push(`${icon} ${item.label}${severity}`);\n }\n const passed = checklist.filter((c) => c.passed).length;\n lines.push(`\\n${passed}/${checklist.length} checks passed`);\n await ui.note(lines.join(\"\\n\"), \"Conversion Checklist\");\n\n const criticalFailures = checklist.filter((c) => !c.passed && c.critical);\n const cosmeticFailures = checklist.filter((c) => !c.passed && !c.critical);\n\n if (criticalFailures.length > 0) {\n ui.logError(\n `${criticalFailures.length} critical issue(s) — upload will likely fail:\\n` +\n criticalFailures.map((c) => ` - ${c.label}`).join(\"\\n\")\n );\n const proceed = await ui.confirm({\n message: \"Continue with upload anyway?\",\n initialValue: false,\n });\n if (!proceed) {\n throw new Error(\"Conversion aborted due to critical checklist failures.\");\n }\n } else if (cosmeticFailures.length > 0) {\n ui.logWarn(\n `${cosmeticFailures.length} non-critical issue(s) — page will work but may look incomplete:\\n` +\n cosmeticFailures.map((c) => ` - ${c.label}`).join(\"\\n\")\n );\n }\n\n // Offer to clean up log file\n const logPath = join(opts.themePath, \"..\", \"vibespot-conversion.log\");\n if (fileExists(logPath)) {\n const keepLog = await ui.confirm({\n message: \"Keep conversion log file for debugging?\",\n initialValue: false,\n });\n if (!keepLog) {\n rmSync(logPath);\n } else {\n ui.logSuccess(`Log saved: ${logPath}`);\n }\n }\n\n await ui.outro(\"Files ready for upload!\");\n\n return result;\n}\n\n/**\n * Run all validation and auto-fix routines before upload.\n * Returns a list of human-readable fix descriptions.\n */\nexport function validateAndFix(themePath: string): string[] {\n const fixes: string[] = [];\n\n // 1. Template annotations\n validateTemplates(themePath);\n\n // 2. Module meta.json\n validateModuleMeta(themePath);\n\n // 3. Fix fields.json issues in all modules\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n\n const moduleName = entry.replace(\".module\", \"\");\n let content = readFile(fieldsPath);\n let changed = false;\n\n // 3a. \"textarea\" → \"text\"\n if (content.includes('\"textarea\"')) {\n content = content.replace(/\"textarea\"/g, '\"text\"');\n changed = true;\n fixes.push(`${moduleName}: \"textarea\" → \"text\"`);\n }\n\n // 3b. \"name\": \"name\" → \"name\": \"item_name\"\n if (/\"name\":\\s*\"name\"/.test(content)) {\n content = content.replace(/\"name\":\\s*\"name\"/g, '\"name\": \"item_name\"');\n changed = true;\n fixes.push(`${moduleName}: reserved field name \"name\" → \"item_name\"`);\n }\n\n // 3c. Fix \"choice\" fields — choices must be [[\"value\",\"Label\"]] not [\"value\"]\n // 3d. Fix \"link\" fields — default must be { url: { href, type }, open_in_new_tab, no_follow }\n try {\n const fields = JSON.parse(content);\n let jsonFixed = false;\n if (fixChoiceFields(fields)) {\n jsonFixed = true;\n fixes.push(`${moduleName}: fixed choice field format`);\n }\n if (fixLinkFields(fields)) {\n jsonFixed = true;\n fixes.push(`${moduleName}: fixed link field default value`);\n }\n if (jsonFixed) {\n content = JSON.stringify(fields, null, 2) + \"\\n\";\n changed = true;\n }\n } catch {\n fixes.push(`${moduleName}: fields.json has invalid JSON — manual fix needed`);\n }\n\n if (changed) writeFile(fieldsPath, content);\n\n // 3d. Fix now() in module.html\n const htmlPath = join(modulesDir, entry, \"module.html\");\n if (fileExists(htmlPath)) {\n let html = readFile(htmlPath);\n if (html.includes(\"now()\")) {\n html = html.replace(/now\\(\\)/g, \"local_dt\");\n writeFile(htmlPath, html);\n fixes.push(`${moduleName}: now() → local_dt`);\n }\n }\n }\n }\n\n // 4. Remove HubDB templates (requires CMS Hub Pro/Enterprise)\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\")) continue;\n const filePath = join(templatesDir, file);\n const content = readFile(filePath);\n if (content.includes(\"hubdb_table\") || content.includes(\"hubdb_table_rows\")) {\n rmSync(filePath);\n fixes.push(`Removed ${file} (HubDB requires CMS Hub Pro/Enterprise)`);\n }\n }\n }\n\n return fixes;\n}\n\n/** Recursively fix choice fields: convert string[] choices to [value, Label][] */\nfunction fixChoiceFields(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"choice\" && Array.isArray(f.choices)) {\n const needsFix = f.choices.some((c: unknown) => typeof c === \"string\");\n if (needsFix) {\n f.choices = (f.choices as unknown[]).map((c: unknown) => {\n if (typeof c === \"string\") {\n const label = c.charAt(0).toUpperCase() + c.slice(1);\n return [c, label];\n }\n return c;\n });\n fixed = true;\n }\n }\n\n // Recurse into group children\n if (Array.isArray(f.children)) {\n if (fixChoiceFields(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n\n/** Recursively fix link fields: default must be { url: { href, type }, open_in_new_tab, no_follow } */\nfunction fixLinkFields(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"link\") {\n const def = f.default;\n // Fix if default is a string, missing, or doesn't have the required url.href structure\n const needsFix =\n typeof def === \"string\" ||\n def === undefined ||\n def === null ||\n (typeof def === \"object\" && !(def as Record<string, unknown>).url);\n\n if (needsFix) {\n const href = typeof def === \"string\" ? def : \"\";\n f.default = {\n url: { href, type: \"EXTERNAL\" },\n open_in_new_tab: false,\n no_follow: false,\n };\n fixed = true;\n }\n }\n\n // Recurse into group children\n if (Array.isArray(f.children)) {\n if (fixLinkFields(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n\ninterface CheckItem {\n label: string;\n passed: boolean;\n /** If true, failure blocks upload. If false, it's cosmetic / nice-to-have. */\n critical: boolean;\n}\n\nfunction buildChecklist(themePath: string, result: GeneratedAssets): CheckItem[] {\n const items: CheckItem[] = [];\n\n // Modules — critical: upload will fail with zero modules\n const moduleCount = result.modules.length;\n items.push({\n label: `Modules created (${moduleCount})`,\n passed: moduleCount > 0,\n critical: true,\n });\n\n // fields.json — critical: invalid fields cause upload deserialization errors\n let fieldsOk = true;\n for (const m of result.modules) {\n if (m.fieldsJson.includes('\"textarea\"') || /\"name\":\\s*\"name\"/.test(m.fieldsJson)) {\n fieldsOk = false;\n break;\n }\n }\n items.push({\n label: \"fields.json valid (no textarea, no reserved names)\",\n passed: moduleCount > 0 && fieldsOk,\n critical: true,\n });\n\n // module.html — critical: modules won't render without it\n const allHaveHtml = result.modules.every((m) => m.moduleHtml.length > 0);\n items.push({\n label: \"module.html created for each module\",\n passed: moduleCount > 0 && allHaveHtml,\n critical: true,\n });\n\n // module.css — not critical (page works but looks unstyled)\n const missingCss = result.modules.filter((m) => !m.moduleCss).map((m) => m.moduleName);\n const allHaveCss = missingCss.length === 0;\n items.push({\n label: allHaveCss\n ? \"module.css created for each module\"\n : `module.css missing for: ${missingCss.join(\", \")}`,\n passed: moduleCount > 0 && allHaveCss,\n critical: false,\n });\n\n // Style tab — not critical (modules work without style tab)\n const hasStyleTab = result.modules.some((m) => m.fieldsJson.includes('\"STYLE\"'));\n items.push({\n label: \"Style tab fields (color pickers)\",\n passed: hasStyleTab,\n critical: false,\n });\n\n // Shared CSS — not critical (modules have their own CSS)\n items.push({\n label: \"Shared CSS with design system variables\",\n passed: result.sharedCss.length > 50,\n critical: false,\n });\n\n // Shared JS — not critical (page works without animations)\n items.push({\n label: \"Shared JS for scroll animations\",\n passed: result.sharedJs.length > 50,\n critical: false,\n });\n\n // Page template — critical: no template means no page in HubSpot\n items.push({\n label: \"Page template with dnd_area\",\n passed: result.template.length > 0 && result.template.includes(\"dnd_area\"),\n critical: true,\n });\n\n // Template annotations — critical: template won't appear in picker\n const templatesDir = join(themePath, \"templates\");\n let templateAnnotated = false;\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\") || file === \"base.html\" || file.startsWith(\"system\")) continue;\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\") && /templateType\\s*:\\s*page/i.test(content)) {\n templateAnnotated = true;\n break;\n }\n }\n }\n items.push({\n label: \"Template annotations (templateType: page)\",\n passed: templateAnnotated,\n critical: true,\n });\n\n return items;\n}\n\n/**\n * Ensure all templates in templates/ have the required HubSpot annotations.\n * Without `templateType: page` and `isAvailableForNewContent: true`,\n * the template won't appear in HubSpot's template picker.\n */\nexport function validateTemplates(themePath: string): void {\n const templatesDir = join(themePath, \"templates\");\n if (!fileExists(templatesDir)) return;\n\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\") || file === \"base.html\" || file.startsWith(\"system\")) continue;\n\n const filePath = join(templatesDir, file);\n let content = readFile(filePath);\n\n // Skip files that don't look like page templates\n if (!content.includes(\"dnd_area\") && !content.includes(\"extends\")) continue;\n\n const hasTemplateType = /templateType\\s*:\\s*page/i.test(content);\n const hasAvailable = /isAvailableForNewContent\\s*:\\s*true/i.test(content);\n\n if (hasTemplateType && hasAvailable) continue;\n\n // Build the annotation block\n const label = file.replace(\".html\", \"\").replace(/[-_]/g, \" \").replace(/\\b\\w/g, c => c.toUpperCase());\n\n if (content.includes(\"<!--\") && content.indexOf(\"-->\") < 200) {\n // Has an existing comment block at the top — patch it\n const commentEnd = content.indexOf(\"-->\");\n let annotation = content.slice(0, commentEnd);\n\n if (!hasTemplateType) {\n annotation += \"\\n templateType: page\";\n }\n if (!hasAvailable) {\n annotation += \"\\n isAvailableForNewContent: true\";\n }\n if (!/label\\s*:/i.test(annotation)) {\n annotation += `\\n label: ${label}`;\n }\n\n content = annotation + content.slice(commentEnd);\n } else {\n // No annotation block — prepend one\n const block = `<!--\\n templateType: page\\n isAvailableForNewContent: true\\n label: ${label}\\n-->\\n`;\n content = block + content;\n }\n\n writeFile(filePath, content);\n ui.logSuccess(`Template \"${file}\" — annotations verified`);\n }\n\n}\n\n/**\n * Ensure all module meta.json files have the required fields for\n * landing page compatibility.\n */\nexport function validateModuleMeta(themePath: string): void {\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const metaPath = join(modulesDir, entry, \"meta.json\");\n if (!fileExists(metaPath)) continue;\n\n try {\n const meta = JSON.parse(readFile(metaPath));\n let changed = false;\n\n if (!meta.host_template_types || !meta.host_template_types.includes(\"PAGE\")) {\n meta.host_template_types = [\"PAGE\"];\n changed = true;\n }\n if (!meta.is_available_for_new_content) {\n meta.is_available_for_new_content = true;\n changed = true;\n }\n\n if (changed) {\n writeFile(metaPath, JSON.stringify(meta, null, 2) + \"\\n\");\n }\n } catch {\n // Skip malformed meta.json\n }\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { join, basename } from \"node:path\";\nimport { readdirSync, statSync, writeFileSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport { getConversionGuide, getHubspotRules } from \"./prompts.js\";\nimport { readFile, fileExists } from \"../utils/fs.js\";\n\n/** Boilerplate modules from `hs cms theme create` — used to distinguish AI-generated modules. */\nconst BOILERPLATE_MODULES = new Set([\n \"button.module\",\n \"card.module\",\n \"menu.module\",\n \"pricing-card.module\",\n \"social-follow.module\",\n]);\n\n/** Boilerplate templates from `hs cms theme create`. */\nconst BOILERPLATE_TEMPLATES = new Set([\n \"about.html\",\n \"blog-index.html\",\n \"blog-post.html\",\n \"contact.html\",\n \"home.html\",\n \"hubdb.html\",\n \"landing-page.html\",\n \"pricing.html\",\n \"qa-test.html\",\n \"base.html\",\n]);\n\nexport class ClaudeCodeEngine implements AIEngine {\n private model?: string;\n private reported = new Set<string>();\n private moduleCount = 0;\n private expectedModules = 0;\n\n constructor(model?: string) {\n this.model = model;\n }\n\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, onProgress } = opts;\n const guide = opts.conversionGuide || getConversionGuide();\n\n // Reset progress tracking\n this.reported.clear();\n this.moduleCount = 0;\n this.expectedModules = 0;\n\n // Count source components to estimate expected modules\n const sourceComponents = this.countSourceComponents(sourceDir);\n\n // Snapshot existing files so we can detect what Claude actually created\n const existingModules = this.listModules(themePath);\n const existingCss = this.listDir(join(themePath, \"css\"));\n const existingJs = this.listDir(join(themePath, \"js\"));\n const existingTemplates = this.listDir(join(themePath, \"templates\"));\n\n // Build the prompt for Claude Code\n const prompt = this.buildFullPrompt(sourceDir, themePath, guide);\n\n onProgress(\"convert\", `Starting Claude Code (${sourceComponents} source components found)...`);\n\n // Run Claude Code with real-time progress tracking\n let stdout = \"\";\n let stderr = \"\";\n\n // Poll the filesystem every 3s to show progress\n const progressInterval = setInterval(() => {\n this.reportProgress(themePath, existingModules, existingCss, existingJs, existingTemplates, onProgress);\n }, 3000);\n\n try {\n await new Promise<void>((resolve, reject) => {\n // Strip CLAUDECODE env var to allow running from inside a Claude Code session\n const env = { ...process.env };\n delete env.CLAUDECODE;\n\n const args = [\n \"--print\",\n \"--max-turns\", \"50\",\n \"--allowedTools\", \"Read,Glob,Grep,Write,Edit,Bash\",\n ];\n if (this.model) args.push(\"--model\", this.model);\n\n const child = spawn(\"claude\", args, {\n cwd: themePath,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n shell: true,\n });\n\n child.stdout.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) => reject(new Error(`Claude Code failed to start: ${err.message}`)));\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(\n `Claude Code exited with code ${code}.\\n` +\n (stderr ? `Stderr: ${stderr.slice(0, 500)}\\n` : \"\") +\n (stdout ? `Output: ${stdout.slice(0, 500)}` : \"No output\")\n ));\n } else {\n resolve();\n }\n });\n\n // Handle stdin errors (EPIPE if claude exits before prompt is fully written)\n child.stdin.on(\"error\", () => {});\n\n // Send prompt via stdin and close\n child.stdin.write(prompt);\n child.stdin.end();\n\n // 30 min timeout\n setTimeout(() => {\n child.kill();\n reject(new Error(\"Claude Code timed out after 30 minutes\"));\n }, 1_800_000);\n });\n } finally {\n clearInterval(progressInterval);\n }\n\n // Write full log to workspace for debugging\n const logPath = join(themePath, \"..\", \"vibespot-conversion.log\");\n try {\n const timestamp = new Date().toISOString();\n const logContent = [\n `=== vibeSpot Conversion Log ===`,\n `Timestamp: ${timestamp}`,\n `Source: ${sourceDir}`,\n `Theme: ${themePath}`,\n `Model: ${this.model || \"default\"}`,\n ``,\n `=== PROMPT SENT ===`,\n prompt.slice(0, 500) + \"\\n... (truncated, full guide follows)\",\n ``,\n `=== CLAUDE CODE STDOUT ===`,\n stdout || \"(empty)\",\n ``,\n `=== CLAUDE CODE STDERR ===`,\n stderr || \"(empty)\",\n ``,\n ].join(\"\\n\");\n writeFileSync(logPath, logContent, \"utf-8\");\n onProgress(\"status\", `Log written to ${basename(logPath)}`);\n } catch {\n // Non-critical — don't fail if log can't be written\n }\n\n onProgress(\"scan\", \"Scanning generated files...\");\n\n // Scan the theme directory for what Claude Code created\n const result = this.scanGeneratedFiles(themePath);\n\n // Validate that new files were actually created\n const newModules = result.modules.filter(\n (m) => !existingModules.has(m.moduleName + \".module\")\n );\n\n if (newModules.length === 0) {\n const outputPreview = stdout.slice(0, 1500) || \"(no output)\";\n const stderrPreview = stderr.slice(0, 500);\n throw new Error(\n \"Claude Code did not create any new module files.\\n\\n\" +\n \"This usually means the model described the conversion instead of using Write tool to create files.\\n\\n\" +\n \"Possible causes:\\n\" +\n \" - Model didn't use Write tool (just printed text)\\n\" +\n \" - Claude Code hit a rate limit or API error\\n\" +\n \" - The source directory was not accessible\\n\\n\" +\n `Source: ${opts.sourceDir}\\n` +\n `Theme: ${themePath}\\n` +\n (stderrPreview ? `\\nStderr:\\n${stderrPreview}\\n` : \"\") +\n `\\nClaude output:\\n${outputPreview}`\n );\n }\n\n return result;\n }\n\n /** Poll filesystem and emit \"created\" events for newly detected files. */\n private reportProgress(\n themePath: string,\n existingModules: Set<string>,\n existingCss: Set<string>,\n existingJs: Set<string>,\n existingTemplates: Set<string>,\n onProgress: (step: string, detail: string) => void,\n ): void {\n let newItems = 0;\n\n // Check for new CSS files\n const currentCss = this.listDir(join(themePath, \"css\"));\n for (const f of currentCss) {\n if (existingCss.has(f) || !f.endsWith(\".css\")) continue;\n const key = `css:${f}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n onProgress(\"created\", `Shared CSS (${f})`);\n newItems++;\n }\n }\n\n // Check for new JS files\n const currentJs = this.listDir(join(themePath, \"js\"));\n for (const f of currentJs) {\n if (existingJs.has(f) || !f.endsWith(\".js\")) continue;\n const key = `js:${f}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n onProgress(\"created\", `Shared JS (${f})`);\n newItems++;\n }\n }\n\n // Try to detect expected module count from template file (once it exists)\n if (this.expectedModules === 0) {\n this.expectedModules = this.detectExpectedModules(themePath, existingTemplates);\n }\n\n // Check for new modules\n const currentModules = this.listModules(themePath);\n for (const mod of currentModules) {\n if (existingModules.has(mod)) continue;\n const key = `module:${mod}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n this.moduleCount++;\n const counter = this.expectedModules > 0\n ? `[${this.moduleCount}/${this.expectedModules}]`\n : `[${this.moduleCount}]`;\n onProgress(\"created\", `Module ${counter}: ${mod.replace(\".module\", \"\")}`);\n newItems++;\n }\n }\n\n // Check for new templates\n const currentTemplates = this.listDir(join(themePath, \"templates\"));\n for (const f of currentTemplates) {\n if (existingTemplates.has(f) || !f.endsWith(\".html\")) continue;\n const key = `template:${f}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n onProgress(\"created\", `Page template (${f})`);\n newItems++;\n }\n }\n\n // Update spinner status text (only if no new items were just logged)\n if (newItems === 0) {\n if (this.moduleCount > 0) {\n const of = this.expectedModules > 0 ? `/${this.expectedModules}` : \"\";\n onProgress(\"status\", `${this.moduleCount}${of} modules created, conversion continuing...`);\n } else if (this.reported.size > 0) {\n onProgress(\"status\", \"Shared assets created, building modules...\");\n } else {\n onProgress(\"status\", \"Claude Code is analyzing source files...\");\n }\n }\n }\n\n private buildFullPrompt(\n sourceDir: string,\n themePath: string,\n guide: string\n ): string {\n return `You are converting a React landing page to native HubSpot CMS modules.\n\nSOURCE DIRECTORY: ${sourceDir}\nTHEME DIRECTORY: ${themePath}\n\nIMPORTANT — YOU MUST CREATE REAL FILES:\nYou have access to Write, Edit, Read, Glob, Grep, and Bash tools. You MUST use the Write tool to create each file. Do NOT just describe or list what files should be created — actually call the Write tool for every single file. If you do not call Write, no files will be created and the conversion will fail.\n\nSTEP-BY-STEP PROCESS:\n1. Use Glob to find all .tsx/.jsx files in ${sourceDir}/src/\n2. Use Read to read each component file and understand the page structure\n3. Use Write to create a shared CSS file at ${themePath}/css/<name>-theme.css\n - Include CSS custom properties, design system variables, utility classes\n - Add theme-override countermeasures (.body-wrapper:has(), scoped !important overrides)\n4. Use Write to create a shared JS file at ${themePath}/js/<name>-animations.js\n - Convert React hooks to vanilla JS (IntersectionObserver for scroll animations)\n - IIFE wrapper, DOMContentLoaded setup\n5. For EACH visual section of the page, use Write to create ALL FOUR files:\n a. ${themePath}/modules/<name>.module/fields.json\n - Editable fields for the section content\n - NEVER use \"textarea\" type (use \"text\" instead)\n - NEVER use \"name\" as a field name (use \"item_name\" instead)\n - Add a \"styles\" group with \"tab\": \"STYLE\" containing color pickers\n b. ${themePath}/modules/<name>.module/meta.json\n - Must include: host_template_types: [\"PAGE\"], is_available_for_new_content: true\n c. ${themePath}/modules/<name>.module/module.html\n - HubL template that renders the section (convert JSX to HubL)\n d. ${themePath}/modules/<name>.module/module.css\n - REQUIRED — complete vanilla CSS for this section\n - Must include: layout, spacing, colors, typography, backgrounds, gradients, shadows, borders, hover effects, responsive breakpoints\n - Convert ALL Tailwind classes to BEM-style CSS. Do NOT skip this file.\n6. Use Write to create a page template at ${themePath}/templates/lp-<name>.html\n - Annotation: templateType: page, isAvailableForNewContent: true\n - Extends \"./layouts/base.html\"\n - Sets template_css and template_js variables\n - Wraps modules in dnd_area with dnd_section containers\n7. Read ${themePath}/templates/layouts/base.html and ensure it supports template_css and template_js variables\n\nCSS QUALITY: The converted page must visually match the original React page. Every module.css must be self-contained with complete styling for that section.\n\nDo NOT run hs upload — I will handle that separately.\n\nHUBSPOT CMS RULES:\n${getHubspotRules()}\n\nCONVERSION GUIDE:\n${guide}`;\n }\n\n private scanGeneratedFiles(themePath: string): GeneratedAssets {\n const result: GeneratedAssets = {\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n modules: [],\n };\n\n // Find shared CSS (any non-boilerplate CSS in css/)\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (\n file.endsWith(\".css\") &&\n file !== \"theme-overrides.css\" &&\n file !== \"main.css\" &&\n file !== \"style.css\"\n ) {\n result.sharedCss = readFile(join(cssDir, file));\n break;\n }\n }\n }\n\n // Find shared JS (any non-boilerplate JS in js/)\n const jsDir = join(themePath, \"js\");\n if (fileExists(jsDir)) {\n for (const file of readdirSync(jsDir)) {\n if (\n file.endsWith(\".js\") &&\n file !== \"main.js\"\n ) {\n result.sharedJs = readFile(join(jsDir, file));\n break;\n }\n }\n }\n\n // Find new template (prefer lp-* or non-boilerplate templates)\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n // First pass: look for lp-* templates (AI-generated naming convention)\n for (const file of readdirSync(templatesDir)) {\n if (file.startsWith(\"lp-\") && file.endsWith(\".html\")) {\n result.template = readFile(join(templatesDir, file));\n break;\n }\n }\n // Second pass: any non-boilerplate template with dnd_area\n if (!result.template) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !BOILERPLATE_TEMPLATES.has(file) &&\n !file.startsWith(\"system\")\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n // Third pass: fall back to any template with dnd_area\n if (!result.template) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !file.startsWith(\"system\") &&\n file !== \"base.html\"\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n }\n\n // Scan modules/\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const modDir = join(modulesDir, entry);\n if (!statSync(modDir).isDirectory()) continue;\n\n const moduleFiles: ModuleFiles = {\n moduleName: entry.replace(\".module\", \"\"),\n fieldsJson: \"\",\n metaJson: \"\",\n moduleHtml: \"\",\n moduleCss: \"\",\n };\n\n const fj = join(modDir, \"fields.json\");\n if (fileExists(fj)) moduleFiles.fieldsJson = readFile(fj);\n\n const mj = join(modDir, \"meta.json\");\n if (fileExists(mj)) moduleFiles.metaJson = readFile(mj);\n\n const mh = join(modDir, \"module.html\");\n if (fileExists(mh)) moduleFiles.moduleHtml = readFile(mh);\n\n const mc = join(modDir, \"module.css\");\n if (fileExists(mc)) moduleFiles.moduleCss = readFile(mc);\n\n const mjs = join(modDir, \"module.js\");\n if (fileExists(mjs)) moduleFiles.moduleJs = readFile(mjs);\n\n // Only count modules that have at least fields.json and module.html\n if (moduleFiles.fieldsJson && moduleFiles.moduleHtml) {\n result.modules.push(moduleFiles);\n }\n }\n }\n\n return result;\n }\n\n /** List module directories in modules/ */\n private listModules(themePath: string): Set<string> {\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return new Set();\n return new Set(\n readdirSync(modulesDir).filter((e) => e.endsWith(\".module\"))\n );\n }\n\n /** List files in a directory */\n private listDir(dir: string): Set<string> {\n if (!fileExists(dir)) return new Set();\n return new Set(readdirSync(dir));\n }\n\n /** Detect expected module count from template file (counts dnd_module references) */\n private detectExpectedModules(themePath: string, existingTemplates: Set<string>): number {\n const templatesDir = join(themePath, \"templates\");\n if (!fileExists(templatesDir)) return 0;\n\n for (const file of readdirSync(templatesDir)) {\n if (existingTemplates.has(file)) continue;\n if (!file.endsWith(\".html\") || file === \"base.html\" || file.startsWith(\"system\")) continue;\n\n try {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n const matches = content.match(/dnd_module/g);\n return matches ? matches.length : 0;\n }\n } catch {\n // Skip unreadable files\n }\n }\n return 0;\n }\n\n /** Count .tsx/.jsx component files in the source directory */\n private countSourceComponents(sourceDir: string): number {\n const srcDir = join(sourceDir, \"src\");\n if (!fileExists(srcDir)) return 0;\n return this.countComponentsRecursive(srcDir);\n }\n\n private countComponentsRecursive(dir: string): number {\n let count = 0;\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry);\n try {\n const stat = statSync(fullPath);\n if (stat.isDirectory() && entry !== \"node_modules\" && entry !== \".git\") {\n count += this.countComponentsRecursive(fullPath);\n } else if (/\\.(tsx|jsx)$/.test(entry) && !entry.includes(\".test.\") && !entry.includes(\".spec.\")) {\n count++;\n }\n } catch {\n // Skip unreadable entries\n }\n }\n return count;\n }\n}\n","import { readFile, resolveAsset } from \"../utils/fs.js\";\n\n// In-memory cache for guide files (~90KB total, read once)\nconst guideCache = new Map<string, string>();\n\nfunction cachedAsset(name: string): string {\n let val = guideCache.get(name);\n if (val !== undefined) return val;\n try { val = readFile(resolveAsset(name)); } catch { val = \"\"; }\n guideCache.set(name, val);\n return val;\n}\n\nexport function getConversionGuide(): string {\n return cachedAsset(\"conversion-guide.md\") || \"Conversion guide not found. Using built-in rules.\";\n}\n\nexport function getDesignGuide(): string {\n return cachedAsset(\"design-guide.md\");\n}\n\nexport function getContentGuide(): string {\n return cachedAsset(\"content-guide.md\");\n}\n\nexport function getHubspotRules(): string {\n return cachedAsset(\"hubspot-rules.md\");\n}\n\nexport function getHumanifyGuide(): string {\n return cachedAsset(\"humanify-guide.md\");\n}\n\n/**\n * Extract page-type-specific section from page-types.md.\n * Returns only the relevant section for the given page type.\n */\nexport function getPageTypeGuide(pageType: string): string {\n const fullGuide = cachedAsset(\"page-types.md\");\n if (!fullGuide) return \"\";\n\n // Map page type to section header\n const sectionHeaders: Record<string, string> = {\n landing_page: \"## Landing Page\",\n blog_post: \"## Blog Post\",\n website_page: \"## Website Page\",\n module_only: \"## Module Only\",\n };\n\n const header = sectionHeaders[pageType];\n if (!header) return \"\";\n\n const startIdx = fullGuide.indexOf(header);\n if (startIdx < 0) return \"\";\n\n // Find the next section (## at start of line) after this one\n const afterHeader = fullGuide.indexOf(\"\\n## \", startIdx + header.length);\n const section = afterHeader >= 0\n ? fullGuide.slice(startIdx, afterHeader).trim()\n : fullGuide.slice(startIdx).trim();\n\n return section;\n}\n\nexport function buildSystemPrompt(conversionGuide: string): string {\n return `You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.\n\n## Rules\nFollow the conversion guide below EXACTLY. Key rules:\n- Use \"type\": \"text\" (NEVER \"textarea\")\n- NEVER use \"name\": \"name\" (it's reserved) — use alternatives like \"item_name\"\n- Wrap style fields in a \"styles\" group with \"tab\": \"STYLE\" on the group\n- All CSS classes must use a unique prefix to avoid theme conflicts\n- Every dnd_section needs padding={\"top\":\"0\",\"bottom\":\"0\",\"left\":\"0\",\"right\":\"0\"}, full_width=true\n- Use template_css and template_js variables (resolved in base.html, not child templates)\n- Add .body-wrapper:has(.my-page) CSS fix + JS fallback for body background\n- Add scoped overrides with !important for headings, paragraphs, links to defeat theme-overrides.css\n- Use IntersectionObserver for scroll animations (add .visible class)\n- Convert Tailwind utilities to vanilla CSS with BEM naming\n- Convert React hooks to vanilla JS (no React, no npm packages)\n\n## HubSpot CMS Rules\n${getHubspotRules()}\n\n## Conversion Guide\n${conversionGuide}`;\n}\n\nexport function buildAnalyzePrompt(componentList: string): string {\n return `Analyze these React components and create a module map.\n\nFor each component, return a JSON object with:\n- name: HubSpot module name (e.g., \"My Hero\")\n- description: Brief description of the section\n- hasRepeaters: true if it contains .map() or array iteration\n- hasInteractivity: true if it has JS-driven behavior (carousel, accordion, etc.)\n\nComponents:\n${componentList}\n\nReturn ONLY valid JSON array, no markdown fences.`;\n}\n\nexport function buildModulePrompt(\n componentSource: string,\n moduleName: string,\n cssVars: string\n): string {\n return `Convert this React component to a HubSpot module named \"${moduleName}\".\n\nReturn a JSON object with these keys:\n- fieldsJson: complete fields.json content (as JSON string)\n- metaJson: complete meta.json content (as JSON string)\n- moduleHtml: complete module.html content (HubL template)\n- moduleCss: complete module.css content (vanilla CSS)\n- moduleJs: module.js content if interactive behavior needed, or null\n\nDesign system CSS variables available:\n${cssVars}\n\nReact component source:\n${componentSource}\n\nReturn ONLY valid JSON, no markdown fences.`;\n}\n\nexport function buildCssPrompt(\n indexCss: string,\n tailwindConfig: string,\n pagePrefix: string\n): string {\n return `Create a shared CSS file for a HubSpot CMS landing page.\n\nExtract the design system from the source CSS and Tailwind config below.\nUse the class prefix \".${pagePrefix}-\" for all custom classes.\n\nRequirements:\n- CSS custom properties for all colors, spacing\n- Page wrapper styles (.${pagePrefix}-page) with !important font/color\n- .body-wrapper:has(.${pagePrefix}-page) background fix\n- .body-wrapper.${pagePrefix}-page-active JS fallback\n- Scoped overrides: .${pagePrefix}-page h1-h6, p, a with !important\n- .dnd-section padding: 0 !important and .row-fluid max-width: 100%\n- Form overrides for dark themes\n- Utility classes (container, section, grid, glass)\n- Scroll animation classes (.${pagePrefix}-scroll-animate / .visible)\n- Mobile breakpoint at 767px\n- Responsive grid fallbacks\n\nSource CSS:\n${indexCss}\n\nTailwind config:\n${tailwindConfig}\n\nReturn ONLY the CSS content, no markdown fences.`;\n}\n\nexport function buildJsPrompt(\n hooksSource: string,\n interactiveComponents: string,\n pagePrefix: string\n): string {\n return `Create a shared vanilla JS file for a HubSpot CMS landing page.\n\nConvert the React hooks and interactive components below to plain JavaScript.\nUse the class prefix \"${pagePrefix}-\" to match the CSS.\n\nRequirements:\n- IIFE wrapper with \"use strict\"\n- initBodyWrapper: add \"${pagePrefix}-page-active\" class to .body-wrapper\n- initScrollAnimations: IntersectionObserver for .${pagePrefix}-scroll-animate → .visible\n- Convert any carousels, accordions, typing animations to vanilla JS\n- DOMContentLoaded / readyState check\n\nReact hooks source:\n${hooksSource}\n\nInteractive component sources:\n${interactiveComponents}\n\nReturn ONLY the JavaScript content, no markdown fences.`;\n}\n\nexport function buildTemplatePrompt(\n moduleNames: string[],\n themeName: string,\n pagePrefix: string\n): string {\n return `Create a HubSpot page template that assembles these modules:\n\n${moduleNames.map((n, i) => `${i + 1}. ${n}.module`).join(\"\\n\")}\n\nTemplate requirements:\n- templateType: page, isAvailableForNewContent: true\n- extends \"./layouts/base.html\"\n- set template_css = \"../../css/${pagePrefix}-theme.css\"\n- set template_js = \"../../js/${pagePrefix}-animations.js\"\n- Empty header and footer blocks (modules handle them)\n- Wrap content in <div class=\"${pagePrefix}-page\">\n- Each module in its own dnd_section with padding zeroed and full_width=true\n- dnd_area label: \"${themeName} Landing Page\"\n\nReturn ONLY the template HTML content, no markdown fences.`;\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport { join, basename } from \"node:path\";\nimport { readdirSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport {\n buildSystemPrompt,\n buildCssPrompt,\n buildJsPrompt,\n buildModulePrompt,\n buildTemplatePrompt,\n} from \"./prompts.js\";\nimport { readFile, fileExists, writeFile, ensureDir } from \"../utils/fs.js\";\n\nexport class ClaudeAPIEngine implements AIEngine {\n private client: Anthropic;\n private model = \"claude-sonnet-4-6\";\n\n constructor(apiKey?: string) {\n this.client = new Anthropic({\n apiKey: apiKey || process.env.ANTHROPIC_API_KEY,\n });\n }\n\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, conversionGuide, onProgress } = opts;\n const systemPrompt = buildSystemPrompt(conversionGuide);\n\n // Determine a page prefix from the source dir name\n const dirName = basename(sourceDir) || \"page\";\n const pagePrefix = dirName\n .toLowerCase()\n .replace(/[^a-z0-9]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 15);\n\n // Step 1: Generate shared CSS\n onProgress(\"css\", \"Analyzing design system...\");\n const indexCss = this.findAndReadCSS(sourceDir);\n const tailwindConfig = this.findAndReadTailwind(sourceDir);\n\n const cssContent = await this.complete(\n systemPrompt,\n buildCssPrompt(indexCss, tailwindConfig, pagePrefix)\n );\n const cssPath = join(themePath, \"css\", `${pagePrefix}-theme.css`);\n writeFile(cssPath, cssContent);\n onProgress(\"css-done\", `Created css/${pagePrefix}-theme.css`);\n\n // Step 2: Generate shared JS\n onProgress(\"js\", \"Creating shared JavaScript...\");\n const hooksSource = this.findAndReadHooks(sourceDir);\n const interactiveSource = this.findInteractiveComponents(sourceDir);\n\n const jsContent = await this.complete(\n systemPrompt,\n buildJsPrompt(hooksSource, interactiveSource, pagePrefix)\n );\n const jsPath = join(themePath, \"js\", `${pagePrefix}-animations.js`);\n writeFile(jsPath, jsContent);\n onProgress(\"js-done\", `Created js/${pagePrefix}-animations.js`);\n\n // Step 3: Generate modules\n onProgress(\"modules\", \"Building modules...\");\n const components = this.findComponents(sourceDir);\n const modules: ModuleFiles[] = [];\n\n for (let i = 0; i < components.length; i++) {\n const comp = components[i];\n const moduleName = comp.name\n .replace(/Section$/, \"\")\n .replace(/([A-Z])/g, \" $1\")\n .trim();\n\n onProgress(\n \"module\",\n `Building ${moduleName}.module (${i + 1}/${components.length})...`\n );\n\n const source = readFile(comp.path);\n const response = await this.complete(\n systemPrompt,\n buildModulePrompt(source, moduleName, `See css/${pagePrefix}-theme.css`)\n );\n\n try {\n const parsed = JSON.parse(response);\n const mod: ModuleFiles = {\n moduleName,\n fieldsJson: typeof parsed.fieldsJson === \"string\"\n ? parsed.fieldsJson\n : JSON.stringify(parsed.fieldsJson, null, 2),\n metaJson: typeof parsed.metaJson === \"string\"\n ? parsed.metaJson\n : JSON.stringify(parsed.metaJson, null, 2),\n moduleHtml: parsed.moduleHtml || \"\",\n moduleCss: parsed.moduleCss || \"\",\n moduleJs: parsed.moduleJs || undefined,\n };\n\n // Write module files\n const modDir = join(themePath, \"modules\", `${moduleName}.module`);\n ensureDir(modDir);\n writeFile(join(modDir, \"fields.json\"), mod.fieldsJson);\n writeFile(join(modDir, \"meta.json\"), mod.metaJson);\n writeFile(join(modDir, \"module.html\"), mod.moduleHtml);\n writeFile(join(modDir, \"module.css\"), mod.moduleCss);\n if (mod.moduleJs) writeFile(join(modDir, \"module.js\"), mod.moduleJs);\n\n modules.push(mod);\n onProgress(\"module-done\", `${moduleName}.module (${this.countFiles(mod)} files)`);\n } catch {\n onProgress(\"module-error\", `Failed to parse ${moduleName} — skipping`);\n }\n }\n\n // Step 4: Generate template\n onProgress(\"template\", \"Creating page template...\");\n const moduleNames = modules.map((m) => m.moduleName);\n const templateContent = await this.complete(\n systemPrompt,\n buildTemplatePrompt(moduleNames, dirName, pagePrefix)\n );\n\n const templatePath = join(\n themePath,\n \"templates\",\n `lp-${pagePrefix}.html`\n );\n writeFile(templatePath, templateContent);\n onProgress(\"template-done\", `Created templates/lp-${pagePrefix}.html`);\n\n return {\n sharedCss: cssContent,\n sharedJs: jsContent,\n template: templateContent,\n modules,\n };\n }\n\n private async complete(system: string, user: string): Promise<string> {\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: 8192,\n system,\n messages: [{ role: \"user\", content: user }],\n });\n\n const textBlock = response.content.find((b) => b.type === \"text\");\n return textBlock?.text || \"\";\n }\n\n private findAndReadCSS(dir: string): string {\n const paths = [\n join(dir, \"src/index.css\"),\n join(dir, \"src/globals.css\"),\n join(dir, \"src/app/globals.css\"),\n join(dir, \"app/globals.css\"),\n ];\n for (const p of paths) {\n if (fileExists(p)) return readFile(p);\n }\n return \"\";\n }\n\n private findAndReadTailwind(dir: string): string {\n const paths = [\n join(dir, \"tailwind.config.ts\"),\n join(dir, \"tailwind.config.js\"),\n join(dir, \"tailwind.config.mjs\"),\n ];\n for (const p of paths) {\n if (fileExists(p)) return readFile(p);\n }\n return \"\";\n }\n\n private findAndReadHooks(dir: string): string {\n const hooksDir = join(dir, \"src/hooks\");\n if (!fileExists(hooksDir)) return \"\";\n try {\n return readdirSync(hooksDir)\n .filter((f) => f.endsWith(\".ts\") || f.endsWith(\".tsx\"))\n .map((f) => `// ${f}\\n${readFile(join(hooksDir, f))}`)\n .join(\"\\n\\n\");\n } catch {\n return \"\";\n }\n }\n\n private findInteractiveComponents(dir: string): string {\n const components = this.findComponents(dir);\n const interactive: string[] = [];\n\n for (const comp of components) {\n const content = readFile(comp.path);\n if (\n /carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(\n content\n )\n ) {\n interactive.push(`// ${comp.name}\\n${content}`);\n }\n }\n\n return interactive.join(\"\\n\\n\");\n }\n\n private findComponents(dir: string): { name: string; path: string }[] {\n const searchDirs = [\n join(dir, \"src/components/landing\"),\n join(dir, \"src/components/sections\"),\n join(dir, \"src/components\"),\n ];\n\n for (const searchDir of searchDirs) {\n if (!fileExists(searchDir)) continue;\n try {\n return readdirSync(searchDir)\n .filter(\n (f) =>\n (f.endsWith(\".tsx\") || f.endsWith(\".jsx\")) &&\n !f.startsWith(\"ui\") &&\n f !== \"index.tsx\" &&\n f !== \"index.jsx\"\n )\n .map((f) => ({\n name: f.replace(/\\.(tsx|jsx)$/, \"\"),\n path: join(searchDir, f),\n }));\n } catch {\n continue;\n }\n }\n\n return [];\n }\n\n private countFiles(mod: ModuleFiles): number {\n let count = 3; // fields.json, meta.json, module.html always present\n if (mod.moduleCss) count++;\n if (mod.moduleJs) count++;\n return count;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport { getConversionGuide } from \"./prompts.js\";\nimport { readFile, fileExists } from \"../utils/fs.js\";\n\nexport class GeminiCLIEngine implements AIEngine {\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, onProgress } = opts;\n const guide = opts.conversionGuide || getConversionGuide();\n\n const prompt = this.buildFullPrompt(sourceDir, themePath, guide);\n\n onProgress(\"convert\", \"Running Gemini CLI (this may take a few minutes)...\");\n\n // Use async spawn so the event loop stays free for spinner animation\n await new Promise<void>((resolve, reject) => {\n const child = spawn(\"gemini\", [\"-p\", prompt], {\n cwd: themePath,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n shell: true,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) => reject(new Error(`Gemini CLI failed: ${err.message}`)));\n child.on(\"close\", (code) => {\n if (code !== 0 && stderr && !stdout) {\n reject(new Error(`Gemini CLI failed: ${stderr}`));\n } else {\n resolve();\n }\n });\n\n setTimeout(() => {\n child.kill();\n reject(new Error(\"Gemini CLI timed out after 10 minutes\"));\n }, 600_000);\n });\n\n onProgress(\"scan\", \"Scanning generated files...\");\n\n return this.scanGeneratedFiles(themePath);\n }\n\n private buildFullPrompt(\n sourceDir: string,\n themePath: string,\n guide: string\n ): string {\n return `Read the conversion guide below, then convert the React landing page at ${sourceDir} into native HubSpot CMS modules for the theme at ${themePath}.\n\nINSTRUCTIONS:\n1. Analyze all .tsx/.jsx components in the React source\n2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures\n3. Create a shared JS file in js/ for scroll animations and interactive features\n4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css\n5. Add a styles group with \"tab\": \"STYLE\" and color pickers to each module\n6. Create a page template in templates/ that assembles all modules\n7. Make sure base.html supports template_css and template_js variables\n\nCONVERSION GUIDE:\n${guide}\n\nDo NOT run hs upload — I will handle that separately.\nCreate all files directly in the theme directory.`;\n }\n\n private scanGeneratedFiles(themePath: string): GeneratedAssets {\n const result: GeneratedAssets = {\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n modules: [],\n };\n\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (\n (file.includes(\"theme\") || file.includes(\"page\")) &&\n file.endsWith(\".css\") &&\n file !== \"theme-overrides.css\" &&\n file !== \"main.css\" &&\n file !== \"style.css\"\n ) {\n result.sharedCss = readFile(join(cssDir, file));\n break;\n }\n }\n }\n\n const jsDir = join(themePath, \"js\");\n if (fileExists(jsDir)) {\n for (const file of readdirSync(jsDir)) {\n if (\n (file.includes(\"animation\") || file.includes(\"page\")) &&\n file.endsWith(\".js\") &&\n file !== \"main.js\"\n ) {\n result.sharedJs = readFile(join(jsDir, file));\n break;\n }\n }\n }\n\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !file.startsWith(\"system\") &&\n file !== \"base.html\"\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const modDir = join(modulesDir, entry);\n if (!statSync(modDir).isDirectory()) continue;\n\n const moduleFiles: ModuleFiles = {\n moduleName: entry.replace(\".module\", \"\"),\n fieldsJson: \"\",\n metaJson: \"\",\n moduleHtml: \"\",\n moduleCss: \"\",\n };\n\n const fj = join(modDir, \"fields.json\");\n if (fileExists(fj)) moduleFiles.fieldsJson = readFile(fj);\n\n const mj = join(modDir, \"meta.json\");\n if (fileExists(mj)) moduleFiles.metaJson = readFile(mj);\n\n const mh = join(modDir, \"module.html\");\n if (fileExists(mh)) moduleFiles.moduleHtml = readFile(mh);\n\n const mc = join(modDir, \"module.css\");\n if (fileExists(mc)) moduleFiles.moduleCss = readFile(mc);\n\n const mjs = join(modDir, \"module.js\");\n if (fileExists(mjs)) moduleFiles.moduleJs = readFile(mjs);\n\n if (moduleFiles.fieldsJson && moduleFiles.moduleHtml) {\n result.modules.push(moduleFiles);\n }\n }\n }\n\n return result;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport { getConversionGuide } from \"./prompts.js\";\nimport { readFile, fileExists } from \"../utils/fs.js\";\n\nexport class CodexCLIEngine implements AIEngine {\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, onProgress } = opts;\n const guide = opts.conversionGuide || getConversionGuide();\n\n const prompt = this.buildFullPrompt(sourceDir, themePath, guide);\n\n onProgress(\"convert\", \"Running OpenAI Codex (this may take a few minutes)...\");\n\n // Use async spawn so the event loop stays free for spinner animation\n await new Promise<void>((resolve, reject) => {\n const child = spawn(\"codex\", [\"exec\", \"--full-auto\", prompt], {\n cwd: themePath,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n shell: true,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) => reject(new Error(`Codex CLI failed: ${err.message}`)));\n child.on(\"close\", (code) => {\n if (code !== 0 && stderr && !stdout) {\n reject(new Error(`Codex CLI failed: ${stderr}`));\n } else {\n resolve();\n }\n });\n\n setTimeout(() => {\n child.kill();\n reject(new Error(\"Codex CLI timed out after 10 minutes\"));\n }, 600_000);\n });\n\n onProgress(\"scan\", \"Scanning generated files...\");\n\n return this.scanGeneratedFiles(themePath);\n }\n\n private buildFullPrompt(\n sourceDir: string,\n themePath: string,\n guide: string\n ): string {\n return `Read the conversion guide below, then convert the React landing page at ${sourceDir} into native HubSpot CMS modules for the theme at ${themePath}.\n\nINSTRUCTIONS:\n1. Analyze all .tsx/.jsx components in the React source\n2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures\n3. Create a shared JS file in js/ for scroll animations and interactive features\n4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css\n5. Add a styles group with \"tab\": \"STYLE\" and color pickers to each module\n6. Create a page template in templates/ that assembles all modules\n7. Make sure base.html supports template_css and template_js variables\n\nCONVERSION GUIDE:\n${guide}\n\nDo NOT run hs upload — I will handle that separately.\nCreate all files directly in the theme directory.`;\n }\n\n private scanGeneratedFiles(themePath: string): GeneratedAssets {\n const result: GeneratedAssets = {\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n modules: [],\n };\n\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (\n (file.includes(\"theme\") || file.includes(\"page\")) &&\n file.endsWith(\".css\") &&\n file !== \"theme-overrides.css\" &&\n file !== \"main.css\" &&\n file !== \"style.css\"\n ) {\n result.sharedCss = readFile(join(cssDir, file));\n break;\n }\n }\n }\n\n const jsDir = join(themePath, \"js\");\n if (fileExists(jsDir)) {\n for (const file of readdirSync(jsDir)) {\n if (\n (file.includes(\"animation\") || file.includes(\"page\")) &&\n file.endsWith(\".js\") &&\n file !== \"main.js\"\n ) {\n result.sharedJs = readFile(join(jsDir, file));\n break;\n }\n }\n }\n\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !file.startsWith(\"system\") &&\n file !== \"base.html\"\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const modDir = join(modulesDir, entry);\n if (!statSync(modDir).isDirectory()) continue;\n\n const moduleFiles: ModuleFiles = {\n moduleName: entry.replace(\".module\", \"\"),\n fieldsJson: \"\",\n metaJson: \"\",\n moduleHtml: \"\",\n moduleCss: \"\",\n };\n\n const fj = join(modDir, \"fields.json\");\n if (fileExists(fj)) moduleFiles.fieldsJson = readFile(fj);\n\n const mj = join(modDir, \"meta.json\");\n if (fileExists(mj)) moduleFiles.metaJson = readFile(mj);\n\n const mh = join(modDir, \"module.html\");\n if (fileExists(mh)) moduleFiles.moduleHtml = readFile(mh);\n\n const mc = join(modDir, \"module.css\");\n if (fileExists(mc)) moduleFiles.moduleCss = readFile(mc);\n\n const mjs = join(modDir, \"module.js\");\n if (fileExists(mjs)) moduleFiles.moduleJs = readFile(mjs);\n\n if (moduleFiles.fieldsJson && moduleFiles.moduleHtml) {\n result.modules.push(moduleFiles);\n }\n }\n }\n\n return result;\n }\n}\n","import { join, basename } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\nimport {\n parseUploadErrors,\n autoFixError,\n type UploadError,\n} from \"../server/auto-fix.js\";\n\n/** Count \"Uploaded file\" lines in hs cms upload output */\nfunction countUploadedFiles(output: string): number {\n return (output.match(/^Uploaded file /gm) || []).length;\n}\n\nexport async function runUpload(themePath: string): Promise<boolean> {\n await ui.intro(\"Uploading to HubSpot\");\n\n const themeName = basename(themePath) || themePath;\n const s = await ui.spinner();\n\n const MAX_RETRIES = 3;\n\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n s.start(\n attempt === 1\n ? \"Uploading theme...\"\n : `Retrying upload (attempt ${attempt}/${MAX_RETRIES})...`\n );\n\n const result = run(`hs cms upload \"${themePath}\" \"${themeName}\"`, {\n cwd: join(themePath, \"..\"),\n });\n\n // Combine stdout + stderr — hs cms upload logs success lines and errors to both\n const fullOutput = [result.stdout, result.stderr].filter(Boolean).join(\"\\n\");\n const uploadedCount = countUploadedFiles(fullOutput);\n\n if (result.success) {\n s.stop(`All files uploaded! (${uploadedCount} files)`);\n await ui.outro(\"Upload complete!\");\n return true;\n }\n\n // Parse errors from combined output\n const errors = parseUploadErrors(fullOutput);\n\n // If files were uploaded despite errors, tell the user\n if (uploadedCount > 0) {\n s.stop(`${uploadedCount} files uploaded, but some errors occurred`);\n } else {\n s.stop(\"Upload failed\");\n }\n\n if (errors.length === 0) {\n // Unknown error — show raw output\n ui.logError(`Upload error:\\n${fullOutput.slice(0, 500)}`);\n\n if (uploadedCount > 0) {\n ui.logWarn(\n \"Most files uploaded successfully. The theme may already be usable in HubSpot.\\n\" +\n \"You can check your HubSpot Design Manager to verify.\"\n );\n const proceed = await ui.confirm({\n message: \"Continue anyway (theme is likely uploaded)?\",\n initialValue: true,\n });\n if (proceed) return true;\n }\n\n if (attempt < MAX_RETRIES) {\n const retry = await ui.confirm({\n message: \"Try uploading again?\",\n });\n if (!retry) break;\n continue;\n }\n break;\n }\n\n // Try to auto-fix known errors\n let anyFixed = false;\n for (const error of errors) {\n if (error.fixable) {\n const fixed = autoFixError(themePath, error);\n if (fixed) {\n ui.logSuccess(`Auto-fixed: ${error.message}`);\n anyFixed = true;\n } else {\n ui.logWarn(`Could not auto-fix: ${error.message}`);\n }\n } else {\n ui.logError(error.message);\n }\n }\n\n if (anyFixed && attempt < MAX_RETRIES) {\n // Retry after fixes\n continue;\n }\n\n // If files were uploaded, offer to continue despite errors\n if (uploadedCount > 0) {\n ui.logWarn(\n `${uploadedCount} files uploaded successfully despite errors.\\n` +\n \"The theme may work — check HubSpot Design Manager.\"\n );\n const proceed = await ui.confirm({\n message: \"Continue anyway?\",\n initialValue: true,\n });\n if (proceed) return true;\n }\n\n if (!anyFixed) {\n // Try removing stuck modules as last resort\n s.start(\"Cleaning up stuck modules...\");\n run(`hs cms delete \"${themeName}/modules\"`, {\n cwd: join(themePath, \"..\"),\n });\n s.stop(\"Cleaned up modules, retrying...\");\n }\n }\n\n ui.logError(\n \"Upload failed after multiple attempts. Try running `hs cms upload` manually to see detailed errors.\"\n );\n return false;\n}\n","/**\n * Auto-fix utilities for common HubSpot upload errors.\n * Shared between CLI wizard (uploader.ts) and web server (server.ts).\n */\n\nimport { join } from \"node:path\";\nimport { readdirSync, rmSync } from \"node:fs\";\nimport { readFile, writeFile, fileExists } from \"../utils/fs.js\";\n\nexport interface UploadError {\n file: string;\n message: string;\n fixable: boolean;\n}\n\nexport function parseUploadErrors(output: string): UploadError[] {\n const errors: UploadError[] = [];\n\n if (/textarea.*not.*valid|unknown.*field.*type/i.test(output)) {\n const fileMatch = output.match(/(?:in|file:?)\\s+(\\S+fields\\.json)/i);\n errors.push({\n file: fileMatch?.[1] || \"fields.json\",\n message: '\"textarea\" is not a valid field type',\n fixable: true,\n });\n }\n\n if (/missing field name|field null/i.test(output)) {\n const fileMatch = output.match(/(?:in|file:?)\\s+(\\S+fields\\.json)/i);\n errors.push({\n file: fileMatch?.[1] || \"fields.json\",\n message: '\"name\" is a reserved field name',\n fixable: true,\n });\n }\n\n if (/could not resolve.*now/i.test(output)) {\n errors.push({\n file: \"module.html\",\n message: \"now() is not a valid HubL function\",\n fixable: true,\n });\n }\n\n if (/hubdb|do not have access to hubdb/i.test(output)) {\n errors.push({\n file: \"templates\",\n message: \"HubDB requires CMS Hub Pro/Enterprise\",\n fixable: true,\n });\n }\n\n if (/invalid default value|link.*field.*invalid/i.test(output)) {\n const fieldMatch = output.match(/field.*?(\\w+)\\s+has an invalid/i);\n errors.push({\n file: fieldMatch?.[1] || \"fields.json\",\n message: `Link field has invalid default value`,\n fixable: true,\n });\n }\n\n if (/failed to deserialize/i.test(output)) {\n const fileMatch = output.match(/file '([^']+)'/i);\n errors.push({\n file: fileMatch?.[1] || \"fields.json\",\n message: \"fields.json deserialization error\",\n fixable: true,\n });\n }\n\n if (/format for the color value is invalid/i.test(output)) {\n errors.push({\n file: \"fields.json\",\n message: \"Color field has invalid format (rgba/rgb/named — must be hex)\",\n fixable: true,\n });\n }\n\n return errors;\n}\n\nexport function applyAutoFixes(themePath: string): string[] {\n const fixes: string[] = [];\n if (fixTextareaFields(themePath)) fixes.push('textarea → text');\n if (fixReservedNames(themePath)) fixes.push('name → item_name');\n if (fixNowFunction(themePath)) fixes.push('now() → local_dt');\n if (fixHubDbTemplates(themePath)) fixes.push('Removed HubDB templates');\n if (fixLinkFieldDefaults(themePath)) fixes.push('Fixed link field defaults');\n if (fixColorFieldDefaults(themePath)) fixes.push('Fixed rgba/invalid color values → hex');\n if (fixCdnImports(themePath)) fixes.push('Stripped CDN @import statements');\n return fixes;\n}\n\nexport function autoFixError(themePath: string, error: UploadError): boolean {\n if (error.message.includes(\"textarea\")) return fixTextareaFields(themePath);\n if (error.message.includes(\"reserved field name\")) return fixReservedNames(themePath);\n if (error.message.includes(\"now()\")) return fixNowFunction(themePath);\n if (error.message.includes(\"HubDB\")) return fixHubDbTemplates(themePath);\n if (error.message.includes(\"invalid default value\") || error.message.includes(\"deserialization\"))\n return fixLinkFieldDefaults(themePath);\n if (error.message.includes(\"invalid format\") && error.message.includes(\"color\"))\n return fixColorFieldDefaults(themePath);\n return false;\n}\n\nexport function fixTextareaFields(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n let content = readFile(fieldsPath);\n if (content.includes('\"textarea\"')) {\n content = content.replace(/\"textarea\"/g, '\"text\"');\n writeFile(fieldsPath, content);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixReservedNames(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n let content = readFile(fieldsPath);\n if (/\"name\":\\s*\"name\"/g.test(content)) {\n content = content.replace(/\"name\":\\s*\"name\"/g, '\"name\": \"item_name\"');\n writeFile(fieldsPath, content);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixNowFunction(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const htmlPath = join(modulesDir, entry, \"module.html\");\n if (!fileExists(htmlPath)) continue;\n let content = readFile(htmlPath);\n if (content.includes(\"now()\")) {\n content = content.replace(/now\\(\\)/g, \"local_dt\");\n writeFile(htmlPath, content);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixHubDbTemplates(themePath: string): boolean {\n let fixed = false;\n const templatesDir = join(themePath, \"templates\");\n if (!fileExists(templatesDir)) return false;\n\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\")) continue;\n const filePath = join(templatesDir, file);\n const content = readFile(filePath);\n if (content.includes(\"hubdb_table\") || content.includes(\"hubdb_table_rows\")) {\n rmSync(filePath);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixLinkFieldDefaults(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n try {\n const fields = JSON.parse(readFile(fieldsPath));\n if (fixLinkFieldsRecursive(fields)) {\n writeFile(fieldsPath, JSON.stringify(fields, null, 2) + \"\\n\");\n fixed = true;\n }\n } catch {\n // Skip malformed JSON\n }\n }\n return fixed;\n}\n\n/**\n * Strip external CDN @import statements from all CSS files.\n * Google Fonts and other CDN imports can fail in HubSpot's editor\n * and cause content to appear invisible.\n */\nexport function fixCdnImports(themePath: string): boolean {\n let fixed = false;\n\n // Check shared CSS files\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (!file.endsWith(\".css\")) continue;\n const filePath = join(cssDir, file);\n let content = readFile(filePath);\n const cleaned = content.replace(/@import\\s+url\\(['\"]?https?:\\/\\/[^)]+['\"]?\\)\\s*;?/gi, \"\");\n if (cleaned !== content) {\n writeFile(filePath, cleaned);\n fixed = true;\n }\n }\n }\n\n // Check module CSS files\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const cssPath = join(modulesDir, entry, \"module.css\");\n if (!fileExists(cssPath)) continue;\n let content = readFile(cssPath);\n const cleaned = content.replace(/@import\\s+url\\(['\"]?https?:\\/\\/[^)]+['\"]?\\)\\s*;?/gi, \"\");\n if (cleaned !== content) {\n writeFile(cssPath, cleaned);\n fixed = true;\n }\n }\n }\n\n // Check module HTML for <link> tags to external CDNs\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const htmlPath = join(modulesDir, entry, \"module.html\");\n if (!fileExists(htmlPath)) continue;\n let content = readFile(htmlPath);\n const cleaned = content.replace(/<link[^>]+href=['\"]https?:\\/\\/[^'\"]+['\"][^>]*>/gi, \"\");\n if (cleaned !== content) {\n writeFile(htmlPath, cleaned);\n fixed = true;\n }\n }\n }\n\n return fixed;\n}\n\n/**\n * Fix color fields that use rgba(), rgb(), named colors, or 3-digit hex.\n * HubSpot requires: { \"color\": \"#rrggbb\", \"opacity\": 100 }\n */\nexport function fixColorFieldDefaults(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n try {\n const fields = JSON.parse(readFile(fieldsPath));\n if (fixColorFieldsRecursive(fields)) {\n writeFile(fieldsPath, JSON.stringify(fields, null, 2) + \"\\n\");\n fixed = true;\n }\n } catch {\n // Skip malformed JSON\n }\n }\n return fixed;\n}\n\nfunction fixColorFieldsRecursive(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"color\" && f.default && typeof f.default === \"object\") {\n const def = f.default as Record<string, unknown>;\n const colorVal = def.color;\n if (typeof colorVal === \"string\" && !isValidHexColor(colorVal)) {\n const converted = convertToHex(colorVal);\n if (converted) {\n def.color = converted.hex;\n // If the rgba had opacity, use that instead of the existing opacity\n if (converted.opacity !== undefined) {\n def.opacity = converted.opacity;\n }\n fixed = true;\n }\n }\n }\n\n if (Array.isArray(f.children)) {\n if (fixColorFieldsRecursive(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n\nfunction isValidHexColor(color: string): boolean {\n return /^#[0-9a-fA-F]{6}$/.test(color);\n}\n\nfunction convertToHex(color: string): { hex: string; opacity?: number } | null {\n // 3-digit hex → 6-digit\n const hex3 = color.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);\n if (hex3) {\n return { hex: `#${hex3[1]}${hex3[1]}${hex3[2]}${hex3[2]}${hex3[3]}${hex3[3]}` };\n }\n\n // rgba(r, g, b, a)\n const rgba = color.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/i);\n if (rgba) {\n const r = Math.min(255, parseInt(rgba[1]));\n const g = Math.min(255, parseInt(rgba[2]));\n const b = Math.min(255, parseInt(rgba[3]));\n const hex = `#${r.toString(16).padStart(2, \"0\")}${g.toString(16).padStart(2, \"0\")}${b.toString(16).padStart(2, \"0\")}`;\n const opacity = rgba[4] !== undefined ? Math.round(parseFloat(rgba[4]) * 100) : undefined;\n return { hex, opacity };\n }\n\n // Named colors (common ones)\n const named: Record<string, string> = {\n white: \"#ffffff\", black: \"#000000\", red: \"#ff0000\", green: \"#008000\",\n blue: \"#0000ff\", yellow: \"#ffff00\", orange: \"#ffa500\", purple: \"#800080\",\n gray: \"#808080\", grey: \"#808080\", transparent: \"#000000\",\n };\n const lower = color.toLowerCase().trim();\n if (named[lower]) {\n return { hex: named[lower], opacity: lower === \"transparent\" ? 0 : undefined };\n }\n\n return null;\n}\n\nfunction fixLinkFieldsRecursive(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"link\") {\n const def = f.default;\n const needsFix =\n typeof def === \"string\" ||\n def === undefined ||\n def === null ||\n (typeof def === \"object\" && !(def as Record<string, unknown>).url);\n\n if (needsFix) {\n const href = typeof def === \"string\" ? def : \"\";\n f.default = {\n url: { href, type: \"EXTERNAL\" },\n open_in_new_tab: false,\n no_follow: false,\n };\n fixed = true;\n }\n }\n\n if (Array.isArray(f.children)) {\n if (fixLinkFieldsRecursive(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n","import { execSync } from \"node:child_process\";\nimport { rmSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\nimport { detectDataCenter } from \"../utils/detect.js\";\nimport { fileExists } from \"../utils/fs.js\";\n\nexport async function showNextSteps(opts: {\n portalId: string;\n sourceDir: string;\n themePath: string;\n wasCloned: boolean;\n}): Promise<void> {\n const { portalId, sourceDir, themePath, wasCloned } = opts;\n await ui.intro(\"You're all set!\");\n\n const dataCenter = detectDataCenter(portalId);\n const host =\n dataCenter === \"eu1\" ? \"app-eu1.hubspot.com\" : \"app.hubspot.com\";\n\n await ui.note(\n `Your React page has been converted and uploaded to HubSpot.\\n` +\n `The theme and modules are now in your account, but you still\\n` +\n `need to ${theme.bold(\"create a new landing page\")} that uses them.\\n\\n` +\n `Next steps:\\n\\n` +\n ` ${theme.bold(\"1.\")} Go to HubSpot ${theme.muted(\"→\")} Content ${theme.muted(\"→\")} Landing Pages ${theme.muted(\"→\")} Create\\n` +\n ` ${theme.bold(\"2.\")} Choose your uploaded theme from the theme picker\\n` +\n ` ${theme.bold(\"3.\")} Select the landing page template that was just created\\n` +\n ` ${theme.bold(\"4.\")} Your converted modules will appear — drag them onto the page\\n` +\n ` ${theme.bold(\"5.\")} Click each section to edit text, images, and colors\\n` +\n ` ${theme.bold(\"6.\")} Upload images via File Manager ${theme.muted(\"(Settings → Files)\")}\\n` +\n ` ${theme.bold(\"7.\")} Preview and publish!`,\n \"What's next\"\n );\n\n const openBrowser = await ui.confirm({\n message: \"Open HubSpot Landing Pages in your browser?\",\n });\n\n if (openBrowser) {\n const url = portalId\n ? `https://${host}/page-ui/${portalId}/management/pages/landing`\n : `https://${host}`;\n\n try {\n // Cross-platform browser open\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(`open \"${url}\"`);\n } else if (platform === \"win32\") {\n execSync(`cmd /c start \"${url}\"`);\n } else {\n execSync(`xdg-open \"${url}\"`);\n }\n ui.logSuccess(\"Opening HubSpot Landing Pages...\");\n } catch {\n ui.log(`Open this URL in your browser: ${theme.info(url)}`);\n }\n }\n\n // Offer to clean up local directories\n const dirsToClean: { path: string; label: string }[] = [];\n if (wasCloned && fileExists(sourceDir)) {\n dirsToClean.push({ path: sourceDir, label: `Cloned source (${basename(sourceDir)})` });\n }\n if (fileExists(themePath)) {\n dirsToClean.push({ path: themePath, label: `Theme directory (${basename(themePath)})` });\n }\n\n if (dirsToClean.length > 0) {\n const cleanup = await ui.confirm({\n message: \"Clean up local working directories?\",\n });\n\n if (cleanup) {\n for (const dir of dirsToClean) {\n try {\n rmSync(dir.path, { recursive: true, force: true });\n ui.logSuccess(`Removed ${dir.label}`);\n } catch {\n ui.logWarn(`Could not remove ${dir.label} — delete manually if needed.`);\n }\n }\n }\n }\n\n await ui.outro(`Thanks for using hub${theme.vibes(\"Vibes\")}! ${theme.vibes(\"~\")}`);\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { runPreflight } from \"../wizard/preflight.js\";\nimport { setupSource } from \"../wizard/source.js\";\nimport { setupTheme } from \"../wizard/theme-setup.js\";\nimport { runConversion } from \"../wizard/conversion.js\";\nimport { runUpload } from \"../wizard/uploader.js\";\nimport { showNextSteps } from \"../wizard/next-steps.js\";\nimport { saveConfig } from \"../utils/config.js\";\n\nexport async function wizardCommand(): Promise<void> {\n printBanner();\n\n // Step 1: Preflight checks\n const preflight = await runPreflight();\n\n // Step 2: Source setup\n const source = await setupSource();\n saveConfig({ lastSourcePath: source.sourceDir });\n\n // Step 3: Theme setup\n const themeInfo = await setupTheme();\n saveConfig({ lastThemePath: themeInfo.themePath });\n\n // Step 4: AI conversion\n await runConversion({\n aiEngine: preflight.aiEngine,\n model: preflight.model,\n sourceDir: source.sourceDir,\n themePath: themeInfo.themePath,\n });\n\n // Step 5: Upload\n await runUpload(themeInfo.themePath);\n\n // Step 6: Next steps + optional cleanup\n await showNextSteps({\n portalId: preflight.portalId,\n sourceDir: source.sourceDir,\n themePath: themeInfo.themePath,\n wasCloned: source.wasCloned,\n });\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { runPreflight } from \"../wizard/preflight.js\";\n\nexport async function initCommand(): Promise<void> {\n printBanner();\n await runPreflight();\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { setupSource } from \"../wizard/source.js\";\nimport { setupTheme } from \"../wizard/theme-setup.js\";\nimport { runConversion } from \"../wizard/conversion.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\n\nexport async function convertCommand(): Promise<void> {\n printBanner();\n\n const config = loadConfig();\n\n if (!config.aiEngine) {\n ui.logError(\n \"AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`.\"\n );\n process.exit(1);\n }\n\n const source = await setupSource();\n const themeInfo = await setupTheme();\n\n await runConversion({\n aiEngine: config.aiEngine,\n sourceDir: source.sourceDir,\n themePath: themeInfo.themePath,\n });\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { runUpload } from \"../wizard/uploader.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\n\nexport async function uploadCommand(): Promise<void> {\n printBanner();\n\n const config = loadConfig();\n\n if (!config.lastThemePath) {\n const path = await ui.text({\n message: \"Path to your HubSpot theme directory:\",\n placeholder: \"./my-theme\",\n validate: (v) => (v.trim() ? undefined : \"Path is required\"),\n });\n await runUpload(path);\n } else {\n const useLast = await ui.confirm({\n message: `Upload from ${config.lastThemePath}?`,\n });\n\n if (useLast) {\n await runUpload(config.lastThemePath);\n } else {\n const path = await ui.text({\n message: \"Path to your HubSpot theme directory:\",\n placeholder: \"./my-theme\",\n });\n await runUpload(path);\n }\n }\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport {\n detectNode,\n detectGit,\n detectHubSpotCLI,\n detectClaudeCode,\n detectGeminiCLI,\n detectCodexCLI,\n detectHubSpotAuth,\n nodeVersionOk,\n hsCliVersionOk,\n} from \"../utils/detect.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport async function doctorCommand(): Promise<void> {\n printBanner();\n await ui.intro(\"Environment Diagnostics\");\n\n let issues = 0;\n\n // Node.js\n const node = detectNode();\n if (!node.found) {\n ui.logError(\"Node.js — not installed\");\n ui.log(\" Install from https://nodejs.org\");\n issues++;\n } else if (!nodeVersionOk(node.version)) {\n ui.logWarn(`Node.js v${node.version} — too old (need 18+)`);\n ui.log(\" Update at https://nodejs.org\");\n issues++;\n } else {\n ui.logSuccess(`Node.js v${node.version}`);\n }\n\n // Git\n const git = detectGit();\n if (!git.found) {\n ui.logError(\"Git — not installed\");\n ui.log(\" Install from https://git-scm.com\");\n issues++;\n } else {\n ui.logSuccess(`Git ${git.version}`);\n }\n\n // HubSpot CLI (only needed for deployment)\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n ui.logWarn(\"HubSpot CLI — not installed (only needed for deployment)\");\n ui.log(\" Install: npm install -g @hubspot/cli\");\n } else if (!hsCliVersionOk(hs.version)) {\n ui.logWarn(`HubSpot CLI v${hs.version} — too old (need v8+)`);\n ui.log(\" Update: npm install -g @hubspot/cli@latest\");\n issues++;\n } else {\n ui.logSuccess(`HubSpot CLI v${hs.version}`);\n\n // HubSpot auth\n const auth = detectHubSpotAuth();\n if (!auth.authenticated) {\n ui.logWarn(\"HubSpot — not authenticated\");\n ui.log(\" Run: hs init\");\n } else {\n ui.logSuccess(\n `HubSpot portal${auth.portalName ? `: ${auth.portalName}` : \"\"} (ID: ${auth.portalId})`\n );\n }\n }\n\n // AI engines\n const claude = detectClaudeCode();\n if (claude.found) {\n ui.logSuccess(`Claude Code ${claude.version} at ${claude.path}`);\n } else {\n ui.log(theme.muted(\"Claude Code — not installed\"));\n }\n\n const gemini = detectGeminiCLI();\n if (gemini.found) {\n ui.logSuccess(`Gemini CLI ${gemini.version} at ${gemini.path}`);\n } else {\n ui.log(theme.muted(\"Gemini CLI — not installed\"));\n }\n\n const codex = detectCodexCLI();\n if (codex.found) {\n ui.logSuccess(`OpenAI Codex ${codex.version} at ${codex.path}`);\n } else {\n ui.log(theme.muted(\"OpenAI Codex — not installed\"));\n }\n\n // API keys\n const config = loadConfig();\n\n const anthropicKey = !!(config.anthropicApiKey || process.env.ANTHROPIC_API_KEY);\n const openaiKey = !!(config.openaiApiKey || process.env.OPENAI_API_KEY);\n const geminiKey = !!(config.geminiApiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY);\n\n if (anthropicKey) ui.logSuccess(\"Anthropic API key configured\");\n else ui.log(theme.muted(\"Anthropic API key — not set\"));\n\n if (openaiKey) ui.logSuccess(\"OpenAI API key configured\");\n else ui.log(theme.muted(\"OpenAI API key — not set\"));\n\n if (geminiKey) ui.logSuccess(\"Google AI API key configured\");\n else ui.log(theme.muted(\"Google AI API key — not set\"));\n const engineLabels: Record<string, string> = {\n \"claude-code\": \"Claude Code\",\n \"api\": \"Anthropic API\",\n \"anthropic-api\": \"Anthropic API\",\n \"openai-api\": \"OpenAI API\",\n \"gemini-api\": \"Gemini API\",\n \"gemini-cli\": \"Gemini CLI\",\n \"codex-cli\": \"OpenAI Codex\",\n };\n if (config.aiEngine) {\n ui.logSuccess(`AI engine: ${engineLabels[config.aiEngine] || config.aiEngine}`);\n }\n if (config.lastThemePath) {\n ui.log(theme.muted(`Last theme: ${config.lastThemePath}`));\n }\n\n // No AI option available\n if (!claude.found && !gemini.found && !codex.found && !anthropicKey && !openaiKey && !geminiKey) {\n ui.logWarn(\"No AI engine available\");\n ui.log(\" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)\");\n ui.log(\" Or install: Claude Code — https://claude.ai/code\");\n ui.log(\" Gemini CLI — https://github.com/google-gemini/gemini-cli\");\n ui.log(\" Codex CLI — https://github.com/openai/codex\");\n issues++;\n }\n\n console.log();\n if (issues === 0) {\n await ui.outro(\"Everything looks good!\");\n } else {\n await ui.outro(\n theme.warn(`${issues} issue${issues > 1 ? \"s\" : \"\"} found — see above`)\n );\n }\n}\n","/**\n * `vibespot vibe` — Vibe coding mode.\n * Immediately starts a local server and opens the browser.\n * All setup happens in the web UI — zero CLI prompts.\n */\n\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport { startServer } from \"../server/server.js\";\nimport { saveSession } from \"../server/session.js\";\n\nconst DEFAULT_PORT = 4200;\n\nexport async function vibeCommand(): Promise<void> {\n const accent = chalk.hex(\"#e8613a\");\n const dim = chalk.dim;\n\n console.log(\"\");\n console.log(accent(\" v vibeSpot\"));\n console.log(dim(\" Starting...\\n\"));\n\n const uiDir = resolveUiDir();\n if (!uiDir) {\n console.error(chalk.red(\" Could not find UI assets. Is the package installed correctly?\"));\n process.exit(1);\n }\n\n try {\n const { port, close } = await startServer({ port: DEFAULT_PORT, uiDir });\n const url = `http://localhost:${port}`;\n\n console.log(accent(` v ${url}`));\n console.log(dim(\" Press Ctrl+C to stop\\n\"));\n\n // Auto-open browser\n try {\n if (process.platform === \"darwin\") {\n execSync(`open \"${url}\"`, { stdio: \"ignore\" });\n } else if (process.platform === \"win32\") {\n execSync(`cmd /c start \"\" \"${url}\"`, { stdio: \"ignore\" });\n } else {\n execSync(`xdg-open \"${url}\"`, { stdio: \"ignore\" });\n }\n } catch {\n // Browser open failed — user can open manually\n }\n\n // Keep running until Ctrl+C\n await new Promise<void>((resolve) => {\n process.on(\"SIGINT\", () => {\n console.log(dim(\"\\n Saving session...\"));\n saveSession();\n close();\n console.log(dim(\" Goodbye!\\n\"));\n resolve();\n });\n });\n } catch (err) {\n console.error(chalk.red(` Failed to start: ${err instanceof Error ? err.message : String(err)}`));\n process.exit(1);\n }\n}\n\nfunction resolveUiDir(): string | null {\n const candidates = [\n join(import.meta.dirname, \"../../ui\"),\n join(import.meta.dirname, \"../ui\"),\n join(process.cwd(), \"ui\"),\n ];\n\n for (const dir of candidates) {\n if (existsSync(join(dir, \"index.html\"))) return dir;\n }\n\n return null;\n}\n","/**\n * Local development server for vibeSpot vibe coding mode.\n * Serves the UI, handles WebSocket connections, and manages AI interactions.\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from \"node:http\";\nimport { readFileSync, existsSync, readdirSync, appendFileSync, rmSync, renameSync } from \"node:fs\";\nimport { join, extname, basename } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { execSync } from \"node:child_process\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport {\n getSession,\n addMessage,\n updateModules,\n reorderModules,\n removeModule,\n detachModule,\n updateFieldValue,\n getOrderedModules,\n writeModulesToDisk,\n saveSession,\n createSession,\n scanThemeFromDisk,\n loadSession,\n listSessions,\n deleteSession,\n reloadModulesFromDisk,\n reloadActiveTemplateFromDisk,\n getActiveTemplate,\n setActiveTemplate,\n addTemplate,\n removeTemplate,\n getModuleLibrary,\n migrateSession,\n renameSession,\n renameTemplate,\n type PageType,\n type TemplateEntry,\n} from \"./session.js\";\nimport { commitThemeState, commitTemplateState, getHistory, getTemplateHistory, rollbackToCommit, rollbackTemplateToCommit, isGitAvailable } from \"./project-git.js\";\nimport { buildPreviewHtml, buildModulePreviewHtml } from \"./preview.js\";\nimport { handleGenerate, handleGenerateStream, setParseWarningCallback, isGenerating } from \"./ai-handler.js\";\nimport { analyzeSource, type SourceAnalysis } from \"../wizard/source.js\";\nimport { loadConfig, saveConfig, getApiKeyForEngine, type AIEngineType } from \"../utils/config.js\";\nimport { detectEnvironment, detectHubSpotCLI, detectHubSpotAuth, detectDataCenter, detectGitHubCLI, detectGitHubAuth } from \"../utils/detect.js\";\nimport { applyAutoFixes, parseUploadErrors } from \"../server/auto-fix.js\";\nimport { startJob, getJob, startStreamingJob, addJobListener, removeJobListener } from \"./process-manager.js\";\nimport { ensureDir, writeFile } from \"../utils/fs.js\";\n\n// ---------------------------------------------------------------------------\n// MIME types for static serving\n// ---------------------------------------------------------------------------\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html\",\n \".css\": \"text/css\",\n \".js\": \"application/javascript\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface ServerOptions {\n port: number;\n uiDir: string;\n}\n\nexport function startServer(opts: ServerOptions): Promise<{ port: number; close: () => void }> {\n const { port, uiDir } = opts;\n\n const server = createServer((req, res) => handleRequest(req, res, uiDir));\n\n // WebSocket server — upgrade on the same HTTP server\n const wss = new WebSocketServer({ server });\n wss.on(\"connection\", (ws) => handleWsConnection(ws));\n\n return new Promise((resolve, reject) => {\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Try next port\n server.listen(port + 1, () => {\n resolve({\n port: port + 1,\n close: () => { server.close(); wss.close(); },\n });\n });\n } else {\n reject(err);\n }\n });\n\n server.listen(port, () => {\n resolve({\n port,\n close: () => { server.close(); wss.close(); },\n });\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// HTTP request handler\n// ---------------------------------------------------------------------------\n\nfunction handleRequest(req: IncomingMessage, res: ServerResponse, uiDir: string): void {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n const method = req.method || \"GET\";\n\n // API routes\n if (url.pathname.startsWith(\"/api/\")) {\n handleApiRoute(method, url.pathname, req, res);\n return;\n }\n\n // Preview route — returns rendered preview HTML\n if (url.pathname === \"/preview\") {\n const html = buildPreviewHtml();\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(html);\n return;\n }\n\n // Single-module preview (for dashboard module library)\n if (url.pathname === \"/module-preview\") {\n const moduleName = url.searchParams.get(\"module\") || \"\";\n const html = buildModulePreviewHtml(moduleName);\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(html || \"<!-- module not found -->\");\n return;\n }\n\n // Static files from ui/ directory\n serveStatic(url.pathname, uiDir, res);\n}\n\n// ---------------------------------------------------------------------------\n// API routes\n// ---------------------------------------------------------------------------\n\nfunction handleApiRoute(\n method: string,\n path: string,\n req: IncomingMessage,\n res: ServerResponse\n): void {\n // CORS headers for local dev\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n switch (path) {\n case \"/api/session\":\n handleSessionRoute(method, res);\n break;\n\n case \"/api/modules\":\n handleModulesRoute(method, req, res);\n break;\n\n case \"/api/modules/reorder\":\n handleReorderRoute(req, res);\n break;\n\n case \"/api/upload\":\n handleUploadRoute(res);\n break;\n\n case \"/api/field\":\n handleFieldRoute(req, res);\n break;\n\n case \"/api/import\":\n handleImportRoute(req, res);\n break;\n\n case \"/api/setup\":\n handleSetupInfoRoute(res);\n break;\n\n case \"/api/setup/create\":\n handleSetupCreateRoute(req, res);\n break;\n\n case \"/api/setup/fetch\":\n handleSetupFetchRoute(req, res);\n break;\n\n case \"/api/setup/open\":\n handleSetupOpenRoute(req, res);\n break;\n\n case \"/api/setup/resume\":\n handleSetupResumeRoute(req, res);\n break;\n\n case \"/api/setup/apikey\":\n handleSetupApiKeyRoute(req, res);\n break;\n\n // Settings routes\n case \"/api/settings/status\":\n if (method === \"GET\") handleSettingsStatusRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/engine\":\n if (method === \"POST\") handleSettingsEngineRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/apikey\":\n if (method === \"POST\") handleSettingsApiKeyRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/install\":\n if (method === \"POST\") handleSettingsInstallRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/hs-auth\":\n if (method === \"POST\") handleSettingsHsAuthRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/gh-auth\":\n if (method === \"POST\") handleSettingsGhAuthRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/hs-switch\":\n if (method === \"POST\") handleSettingsHsSwitchRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/gh-logout\":\n if (method === \"POST\") handleSettingsGhLogoutRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/cli-auth\":\n if (method === \"POST\") handleSettingsCLIAuthRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/themes\":\n handleThemesRoute(method, req, res);\n break;\n\n case \"/api/themes/switch\":\n if (method === \"POST\") handleThemeSwitchRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/themes/delete-local\":\n if (method === \"POST\") handleDeleteLocalThemeRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/themes/rename\":\n if (method === \"POST\") handleRenameThemeRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/history\":\n if (method === \"GET\") handleHistoryRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/rollback\":\n if (method === \"POST\") handleRollbackRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n // Dashboard & template routes\n case \"/api/dashboard\":\n if (method === \"GET\") handleDashboardRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/templates\":\n handleTemplatesRoute(method, req, res);\n break;\n\n case \"/api/templates/activate\":\n if (method === \"POST\") handleTemplateActivateRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/templates/rename\":\n if (method === \"POST\") handleTemplateRenameRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/module-library\":\n if (method === \"GET\") handleModuleLibraryRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/brand-assets\":\n handleBrandAssetsRoute(method, req, res);\n break;\n\n case \"/api/download-zip\":\n if (method === \"GET\") handleDownloadZipRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n default:\n // Prefix match for job polling: /api/settings/job/:id\n if (path.startsWith(\"/api/settings/job/\") && method === \"GET\") {\n handleSettingsJobRoute(path, res);\n }\n // Prefix match for template add-module: /api/templates/:id/add-module\n else if (path.match(/^\\/api\\/templates\\/[^/]+\\/add-module$/) && method === \"POST\") {\n handleAddModuleToTemplateRoute(path, req, res);\n } else {\n jsonResponse(res, 404, { error: \"Not found\" });\n }\n }\n}\n\nfunction handleSessionRoute(method: string, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n jsonResponse(res, 200, {\n id: session.id,\n themeName: session.themeName,\n themePath: session.themePath,\n messageCount: session.messages.length,\n moduleCount: session.modules.length,\n moduleOrder: session.moduleOrder,\n });\n}\n\nfunction handleModulesRoute(\n method: string,\n req: IncomingMessage,\n res: ServerResponse\n): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n if (method === \"GET\") {\n const ordered = getOrderedModules();\n jsonResponse(res, 200, {\n modules: ordered.map((m) => ({\n moduleName: m.moduleName,\n fieldsJson: m.fieldsJson,\n moduleHtml: m.moduleHtml,\n moduleCss: m.moduleCss,\n moduleJs: m.moduleJs || null,\n })),\n sharedCss: session.sharedCss,\n sharedJs: session.sharedJs,\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n const { moduleName, deleteEntirely } = JSON.parse(body);\n if (deleteEntirely) {\n removeModule(moduleName);\n } else {\n detachModule(moduleName);\n }\n saveSession();\n jsonResponse(res, 200, { ok: true });\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\nfunction handleReorderRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n const { order } = JSON.parse(body);\n if (Array.isArray(order)) {\n reorderModules(order);\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } else {\n jsonResponse(res, 400, { error: \"order must be an array\" });\n }\n });\n}\n\nasync function handleUploadRoute(res: ServerResponse): Promise<void> {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n try {\n // Write all modules to disk first\n writeModulesToDisk();\n\n // Apply auto-fixes before uploading\n const fixes = applyAutoFixes(session.themePath);\n\n // Start a streaming upload job\n const jobId = startStreamingJob(\n `hs cms upload \"${session.themePath}\" \"${session.themeName}\"`,\n \"Uploading to HubSpot\",\n { cwd: join(session.themePath, \"..\"), timeout: 180_000 }\n );\n\n jsonResponse(res, 200, {\n ok: true,\n jobId,\n fixes,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: String(err) });\n }\n}\n\nfunction handleFieldRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { moduleName, fieldPath, value } = JSON.parse(body);\n updateFieldValue(moduleName, fieldPath, value);\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 400, { error: String(err) });\n }\n });\n}\n\nfunction handleImportRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { url } = JSON.parse(body);\n if (!url || typeof url !== \"string\") {\n jsonResponse(res, 400, { error: \"url is required\" });\n return;\n }\n\n // Analyze the source (clones if GitHub URL)\n const analysis = analyzeSource(url);\n\n // Build a component summary for the AI\n const componentSummary = analysis.components\n .map((c) => `- ${c.name}: ${c.description}`)\n .join(\"\\n\");\n\n const summary = {\n sourceDir: analysis.sourceDir,\n componentCount: analysis.components.length,\n components: analysis.components.map((c) => ({\n name: c.name,\n description: c.description,\n })),\n hasTailwind: analysis.hasTailwind,\n cssVarCount: analysis.cssVarCount,\n fonts: analysis.fonts,\n interactions: analysis.interactions,\n // Pre-built prompt the UI can send directly to the chat\n conversionPrompt: `Import and convert the React landing page from ${url} to native HubSpot modules.\n\nSource analysis found ${analysis.components.length} components:\n${componentSummary}\n\nDesign system: ${analysis.hasTailwind ? \"Tailwind CSS\" : \"Custom CSS\"}, ${analysis.cssVarCount} CSS variables\nFonts: ${analysis.fonts.length > 0 ? analysis.fonts.join(\", \") : \"System fonts\"}\nInteractions: ${analysis.interactions.join(\", \")}\n\nRead the React source files from ${analysis.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.`,\n };\n\n jsonResponse(res, 200, summary);\n } catch (err) {\n jsonResponse(res, 500, {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Setup routes — onboarding flow in the browser\n// ---------------------------------------------------------------------------\n\nconst WORKSPACE_DIR = join(homedir(), \"vibespot-themes\");\n\nfunction handleSetupInfoRoute(res: ServerResponse): void {\n const session = getSession();\n\n // Full environment detection — checks all 6 AI engines, not just Anthropic + Claude Code\n const env = detectEnvironment();\n\n // Lightweight hs check for \"Fetch from HubSpot\" visibility\n let hsInstalled = false;\n try {\n execSync(\"hs --version\", { encoding: \"utf-8\", stdio: \"pipe\" });\n hsInstalled = true;\n } catch { /* not installed */ }\n\n // List previous sessions\n const sessions = listSessions()\n .sort((a, b) => b.updatedAt - a.updatedAt)\n .slice(0, 10);\n\n // Find local theme folders in workspace/ (with module count)\n const localThemes: Array<{ name: string; moduleCount: number }> = [];\n if (existsSync(WORKSPACE_DIR)) {\n try {\n for (const entry of readdirSync(WORKSPACE_DIR, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n const themeJson = join(WORKSPACE_DIR, entry.name, \"theme.json\");\n if (existsSync(themeJson)) {\n let moduleCount = 0;\n const modulesDir = join(WORKSPACE_DIR, entry.name, \"modules\");\n if (existsSync(modulesDir)) {\n try {\n moduleCount = readdirSync(modulesDir, { withFileTypes: true })\n .filter((e) => e.isDirectory()).length;\n } catch { /* ignore */ }\n }\n localThemes.push({ name: entry.name, moduleCount });\n }\n }\n }\n } catch { /* ignore */ }\n }\n\n jsonResponse(res, 200, {\n hasActiveSession: !!session,\n activeSession: session ? {\n id: session.id,\n themeName: session.themeName,\n moduleCount: session.modules.length,\n } : null,\n hsInstalled,\n aiAvailable: env.availableEngines.length > 0,\n availableEngines: env.availableEngines,\n activeEngine: env.activeEngine,\n sessions,\n localThemes,\n });\n}\n\nfunction handleSetupCreateRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { name } = JSON.parse(body);\n if (!name || typeof name !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n\n const themeName = name\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n const themePath = join(WORKSPACE_DIR, themeName);\n ensureDir(WORKSPACE_DIR);\n\n // Remove existing directory if it exists (stale from a previous run)\n if (existsSync(themePath)) {\n rmSync(themePath, { recursive: true, force: true });\n }\n\n // hs create ALWAYS creates in process.cwd(), ignoring execSync's cwd option.\n // So we create it wherever it lands, then move it to the workspace.\n const cwdBefore = new Set(readdirSync(process.cwd()));\n execSync(`hs cms theme create \"${themeName}\"`, {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n });\n\n // Find where hs create actually put the theme\n let createdAt = join(process.cwd(), themeName);\n if (!existsSync(createdAt)) {\n const cwdAfter = readdirSync(process.cwd());\n const newDir = cwdAfter.find((e) => !cwdBefore.has(e) && existsSync(join(process.cwd(), e)));\n if (newDir) createdAt = join(process.cwd(), newDir);\n }\n\n // Move to workspace if it was created elsewhere\n if (createdAt !== themePath && existsSync(createdAt)) {\n renameSync(createdAt, themePath);\n }\n\n // Clear boilerplate page templates (keep layouts/ and partials/ for extends)\n const tplDir = join(themePath, \"templates\");\n if (existsSync(tplDir)) {\n for (const f of readdirSync(tplDir)) {\n if (f.endsWith(\".html\")) rmSync(join(tplDir, f));\n }\n }\n\n // Create a fresh session — don't scan boilerplate modules into it\n // (boilerplate modules stay on disk but the preview shows the welcome screen)\n createSession(themePath, themeName);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName,\n themePath,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSetupFetchRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { name } = JSON.parse(body);\n if (!name || typeof name !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n\n const themePath = join(WORKSPACE_DIR, name);\n ensureDir(WORKSPACE_DIR);\n\n execSync(`hs cms fetch \"${name}\" \"${themePath}\"`, {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n });\n\n createSession(themePath, name);\n scanThemeFromDisk(themePath);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: name,\n themePath,\n moduleCount: getSession()?.modules.length || 0,\n });\n } catch (err) {\n jsonResponse(res, 500, {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n\nfunction handleSetupOpenRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { path: themePath } = JSON.parse(body);\n if (!themePath || typeof themePath !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme path is required\" });\n return;\n }\n\n // Support both absolute paths and workspace-relative names\n let fullPath = themePath;\n if (!existsSync(fullPath)) {\n fullPath = join(WORKSPACE_DIR, themePath);\n }\n if (!existsSync(fullPath)) {\n jsonResponse(res, 400, { error: `Theme folder not found: ${themePath}` });\n return;\n }\n\n const themeName = basename(fullPath);\n createSession(fullPath, themeName);\n scanThemeFromDisk(fullPath);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName,\n themePath: fullPath,\n moduleCount: getSession()?.modules.length || 0,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSetupResumeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { sessionId } = JSON.parse(body);\n if (!sessionId || typeof sessionId !== \"string\") {\n jsonResponse(res, 400, { error: \"Session ID is required\" });\n return;\n }\n\n const session = loadSession(sessionId);\n if (!session) {\n jsonResponse(res, 404, { error: \"Session not found\" });\n return;\n }\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: session.themeName,\n themePath: session.themePath,\n moduleCount: session.modules.length,\n messageCount: session.messages.length,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSetupApiKeyRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { apiKey } = JSON.parse(body);\n if (!apiKey || typeof apiKey !== \"string\") {\n jsonResponse(res, 400, { error: \"API key is required\" });\n return;\n }\n\n saveConfig({ anthropicApiKey: apiKey });\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Settings routes — environment management, API keys, tool install, auth\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Live model catalog — fetched from provider APIs, cached 10 minutes\n// ---------------------------------------------------------------------------\n\ntype ModelEntry = { id: string; label: string };\nconst modelCache: { data: Record<string, ModelEntry[]>; ts: number } = { data: {}, ts: 0 };\nconst MODEL_CACHE_TTL = 10 * 60 * 1000; // 10 minutes\n\nconst STATIC_MODELS: Record<string, ModelEntry[]> = {\n \"claude-code\": [\n { id: \"sonnet\", label: \"Claude Sonnet (default)\" },\n { id: \"opus\", label: \"Claude Opus\" },\n { id: \"haiku\", label: \"Claude Haiku\" },\n ],\n \"codex-cli\": [\n { id: \"o4-mini\", label: \"o4 Mini (default)\" },\n { id: \"o3\", label: \"o3\" },\n { id: \"gpt-4o\", label: \"GPT-4o\" },\n ],\n};\n\nasync function fetchAnthropicModels(apiKey: string): Promise<ModelEntry[]> {\n const resp = await fetch(\"https://api.anthropic.com/v1/models\", {\n headers: { \"x-api-key\": apiKey, \"anthropic-version\": \"2023-06-01\" },\n });\n if (!resp.ok) return [];\n const data = await resp.json() as { data: { id: string; display_name: string }[] };\n return data.data\n .filter((m) => !m.id.startsWith(\"claude-3-\") && !m.id.startsWith(\"claude-2\"))\n .map((m) => ({ id: m.id, label: m.display_name }));\n}\n\nasync function fetchOpenAIModels(apiKey: string): Promise<ModelEntry[]> {\n const resp = await fetch(\"https://api.openai.com/v1/models\", {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (!resp.ok) return [];\n const data = await resp.json() as { data: { id: string }[] };\n const keep = /^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;\n return data.data\n .filter((m) => keep.test(m.id))\n .sort((a, b) => a.id.localeCompare(b.id))\n .map((m) => ({ id: m.id, label: m.id }));\n}\n\nasync function fetchGeminiModels(apiKey: string): Promise<ModelEntry[]> {\n const resp = await fetch(\n `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,\n );\n if (!resp.ok) return [];\n const data = await resp.json() as { models: { name: string; displayName: string }[] };\n return data.models\n .filter((m) => m.name.includes(\"gemini-2\"))\n .map((m) => ({ id: m.name.replace(\"models/\", \"\"), label: m.displayName }));\n}\n\nasync function getModelCatalog(): Promise<Record<string, ModelEntry[]>> {\n if (Date.now() - modelCache.ts < MODEL_CACHE_TTL && Object.keys(modelCache.data).length > 0) {\n return modelCache.data;\n }\n\n const config = loadConfig();\n const catalog: Record<string, ModelEntry[]> = { ...STATIC_MODELS };\n\n const jobs: Promise<void>[] = [];\n\n const anthropicKey = getApiKeyForEngine(\"anthropic-api\", config);\n if (anthropicKey) {\n jobs.push(\n fetchAnthropicModels(anthropicKey)\n .then((models) => { if (models.length) catalog[\"anthropic-api\"] = models; })\n .catch(() => {}),\n );\n }\n\n const openaiKey = getApiKeyForEngine(\"openai-api\", config);\n if (openaiKey) {\n jobs.push(\n fetchOpenAIModels(openaiKey)\n .then((models) => { if (models.length) catalog[\"openai-api\"] = models; })\n .catch(() => {}),\n );\n }\n\n const geminiKey = getApiKeyForEngine(\"gemini-api\", config);\n if (geminiKey) {\n jobs.push(\n fetchGeminiModels(geminiKey)\n .then((models) => {\n if (models.length) {\n catalog[\"gemini-api\"] = models;\n catalog[\"gemini-cli\"] = models;\n }\n })\n .catch(() => {}),\n );\n }\n\n await Promise.all(jobs);\n\n modelCache.data = catalog;\n modelCache.ts = Date.now();\n return catalog;\n}\n\nfunction handleSettingsStatusRoute(res: ServerResponse): void {\n const env = detectEnvironment();\n const config = loadConfig();\n\n // Start model fetch in background; return status immediately with models when ready\n getModelCatalog().then((models) => {\n jsonResponse(res, 200, {\n environment: env,\n config: {\n aiEngine: config.aiEngine || null,\n claudeCodeModel: config.claudeCodeModel || null,\n anthropicApiModel: config.anthropicApiModel || null,\n openaiApiModel: config.openaiApiModel || null,\n },\n models,\n });\n }).catch(() => {\n jsonResponse(res, 200, {\n environment: env,\n config: {\n aiEngine: config.aiEngine || null,\n claudeCodeModel: config.claudeCodeModel || null,\n anthropicApiModel: config.anthropicApiModel || null,\n openaiApiModel: config.openaiApiModel || null,\n },\n models: STATIC_MODELS,\n });\n });\n}\n\nfunction handleSettingsEngineRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { engine, model } = JSON.parse(body);\n\n const validEngines: AIEngineType[] = [\n \"claude-code\", \"anthropic-api\", \"openai-api\", \"gemini-cli\", \"gemini-api\", \"codex-cli\",\n ];\n if (!validEngines.includes(engine)) {\n jsonResponse(res, 400, { error: `Invalid engine: ${engine}` });\n return;\n }\n\n const configUpdate: Record<string, unknown> = { aiEngine: engine };\n if (model) {\n switch (engine) {\n case \"claude-code\":\n configUpdate.claudeCodeModel = model;\n break;\n case \"anthropic-api\":\n configUpdate.anthropicApiModel = model;\n break;\n case \"openai-api\":\n configUpdate.openaiApiModel = model;\n break;\n }\n }\n\n saveConfig(configUpdate as any);\n jsonResponse(res, 200, { ok: true, engine });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsApiKeyRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { provider, apiKey } = JSON.parse(body);\n\n if (!provider || typeof provider !== \"string\") {\n jsonResponse(res, 400, { error: \"provider is required\" });\n return;\n }\n\n // Handle deletion (apiKey is null or empty)\n if (!apiKey) {\n const configUpdate: Record<string, unknown> = {};\n switch (provider) {\n case \"anthropic\": configUpdate.anthropicApiKey = \"\"; break;\n case \"openai\": configUpdate.openaiApiKey = \"\"; break;\n case \"gemini\": configUpdate.geminiApiKey = \"\"; break;\n default:\n jsonResponse(res, 400, { error: `Unknown provider: ${provider}` });\n return;\n }\n saveConfig(configUpdate as any);\n jsonResponse(res, 200, { ok: true, provider, deleted: true });\n return;\n }\n\n // Save the key\n const configUpdate: Record<string, unknown> = {};\n switch (provider) {\n case \"anthropic\": configUpdate.anthropicApiKey = apiKey; break;\n case \"openai\": configUpdate.openaiApiKey = apiKey; break;\n case \"gemini\": configUpdate.geminiApiKey = apiKey; break;\n default:\n jsonResponse(res, 400, { error: `Unknown provider: ${provider}` });\n return;\n }\n\n saveConfig(configUpdate as any);\n\n // Auto-select engine if none is currently configured\n let autoSelectedEngine: string | null = null;\n const currentConfig = loadConfig();\n if (!currentConfig.aiEngine) {\n const engineMap: Record<string, string> = {\n anthropic: \"anthropic-api\",\n openai: \"openai-api\",\n gemini: \"gemini-api\",\n };\n const engine = engineMap[provider];\n if (engine) {\n saveConfig({ aiEngine: engine } as any);\n autoSelectedEngine = engine;\n }\n }\n\n jsonResponse(res, 200, { ok: true, provider, autoSelectedEngine });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsInstallRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { tool } = JSON.parse(body);\n\n const installCommands: Record<string, { cmd: string; desc: string }> = {\n hubspot: { cmd: \"npm install -g @hubspot/cli\", desc: \"Installing HubSpot CLI\" },\n claude: { cmd: \"npm install -g @anthropic-ai/claude-code\", desc: \"Installing Claude Code\" },\n gemini: { cmd: \"npm install -g @google/gemini-cli\", desc: \"Installing Gemini CLI\" },\n codex: { cmd: process.platform === \"darwin\" ? \"brew install --cask codex\" : \"npm install -g @openai/codex\", desc: \"Installing OpenAI Codex\" },\n gh: { cmd: process.platform === \"darwin\" ? \"brew install gh\" : \"npm install -g @cli/gh\", desc: \"Installing GitHub CLI\" },\n };\n\n const config = installCommands[tool];\n if (!config) {\n jsonResponse(res, 400, { error: `Unknown tool: ${tool}. Valid: ${Object.keys(installCommands).join(\", \")}` });\n return;\n }\n\n const jobId = startJob(config.cmd, config.desc, { timeout: 120_000 });\n jsonResponse(res, 200, { ok: true, jobId });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsHsAuthRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const parsed = JSON.parse(body || \"{}\");\n\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n jsonResponse(res, 400, { error: \"HubSpot CLI not installed\", needsInstall: true });\n return;\n }\n\n // Check if already authenticated\n const auth = detectHubSpotAuth();\n if (auth.authenticated && !parsed.force) {\n jsonResponse(res, 200, {\n ok: true,\n alreadyAuthenticated: true,\n portalName: auth.portalName,\n portalId: auth.portalId,\n });\n return;\n }\n\n if (parsed.personalAccessKey) {\n // Non-interactive auth with provided key\n const jobId = startJob(\n `hs auth --pak=\"${parsed.personalAccessKey}\"`,\n \"Authenticating with HubSpot\",\n { timeout: 30_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n\n // No key provided — return instructions for user to get one\n jsonResponse(res, 200, {\n needsKey: true,\n instructions: \"Create a personal access key in HubSpot\",\n url: \"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key\",\n steps: [\n \"Click the link above to open HubSpot\",\n \"Select your account\",\n \"Create a Personal Access Key with CMS permissions\",\n \"Copy the key and paste it below\",\n ],\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsGhAuthRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const parsed = JSON.parse(body || \"{}\");\n\n const gh = detectGitHubCLI();\n if (!gh.found) {\n jsonResponse(res, 400, { error: \"GitHub CLI not installed\", needsInstall: true });\n return;\n }\n\n // Check if already authenticated\n const auth = detectGitHubAuth();\n if (auth.authenticated && !parsed.force) {\n jsonResponse(res, 200, {\n ok: true,\n alreadyAuthenticated: true,\n username: auth.username,\n });\n return;\n }\n\n if (parsed.token) {\n // Auth with provided token\n const jobId = startJob(\n `echo \"${parsed.token}\" | gh auth login --with-token`,\n \"Authenticating with GitHub\",\n { timeout: 30_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n\n // Start browser-based auth flow\n const jobId = startJob(\n \"gh auth login --web --git-protocol https\",\n \"GitHub authentication (check your browser)\",\n { timeout: 300_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, browserAuthRequired: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsHsSwitchRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { portalId, action } = JSON.parse(body);\n\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n jsonResponse(res, 400, { error: \"HubSpot CLI not installed\" });\n return;\n }\n\n if (action === \"remove\" && portalId) {\n // Remove account: hs accounts clean --account=<portalId>\n const jobId = startJob(\n `hs accounts remove ${portalId}`,\n `Removing HubSpot account ${portalId}`,\n { timeout: 15_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n\n if (portalId) {\n // Switch default account: hs accounts use <portalId>\n const jobId = startJob(\n `hs accounts use ${portalId}`,\n `Switching to HubSpot account ${portalId}`,\n { timeout: 15_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n\n jsonResponse(res, 400, { error: \"portalId required\" });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsGhLogoutRoute(res: ServerResponse): void {\n const jobId = startJob(\n \"gh auth logout --hostname github.com -y\",\n \"Logging out of GitHub\",\n { timeout: 15_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n}\n\nfunction handleSettingsCLIAuthRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { cli, apiKey } = JSON.parse(body || \"{}\");\n\n switch (cli) {\n case \"claude\": {\n // Claude Code auth — launch interactive login\n // We need to run `claude` without CLAUDECODE env to avoid nesting error\n const jobId = startJob(\n \"CLAUDECODE= claude --print -p 'reply OK'\",\n \"Authenticating Claude Code (check your browser if prompted)\",\n { timeout: 120_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, hint: \"If Claude Code opens a browser window, complete the sign-in there.\" });\n break;\n }\n case \"gemini\": {\n // Gemini CLI auth — launch a simple prompt to trigger login\n const jobId = startJob(\n \"gemini -p 'reply OK'\",\n \"Authenticating Gemini CLI (check your browser if prompted)\",\n { timeout: 120_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, hint: \"If Gemini opens a browser window, complete the sign-in there.\" });\n break;\n }\n case \"codex\": {\n // Codex CLI — two auth paths: OAuth (codex login) or API key\n if (apiKey && apiKey.trim()) {\n // API key path — save to env, config, and shell profile\n const key = apiKey.trim();\n process.env.OPENAI_API_KEY = key;\n saveConfig({ openaiApiKey: key } as any);\n if (process.platform !== \"win32\") {\n const profileLine = `export OPENAI_API_KEY=\"${key}\"`;\n const shellProfile = process.env.SHELL?.includes(\"zsh\")\n ? join(homedir(), \".zshrc\")\n : join(homedir(), \".bashrc\");\n try {\n const existing = existsSync(shellProfile)\n ? readFileSync(shellProfile, \"utf-8\")\n : \"\";\n if (!existing.includes(\"OPENAI_API_KEY\")) {\n appendFileSync(shellProfile, `\\n# Added by vibeSpot\\n${profileLine}\\n`);\n }\n } catch { /* ignore profile write errors */ }\n }\n jsonResponse(res, 200, { ok: true, message: \"API key saved\" });\n } else {\n // OAuth path — run `codex login` as background job\n const jobId = startJob(\n \"codex login\",\n \"Authenticating Codex CLI (check your browser if prompted)\",\n { timeout: 120_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, hint: \"Complete the sign-in in your browser.\" });\n }\n break;\n }\n default:\n jsonResponse(res, 400, { error: `Unknown CLI: ${cli}` });\n }\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleSettingsJobRoute(path: string, res: ServerResponse): void {\n const jobId = path.replace(\"/api/settings/job/\", \"\");\n if (!jobId) {\n jsonResponse(res, 400, { error: \"Job ID required\" });\n return;\n }\n\n const job = getJob(jobId);\n if (!job) {\n jsonResponse(res, 404, { error: \"Job not found\" });\n return;\n }\n\n jsonResponse(res, 200, {\n id: job.id,\n status: job.status,\n description: job.description,\n output: job.output,\n exitCode: job.exitCode,\n startedAt: job.startedAt,\n completedAt: job.completedAt,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Theme routes\n// ---------------------------------------------------------------------------\n\nfunction handleThemesRoute(method: string, req: IncomingMessage, res: ServerResponse): void {\n if (method === \"GET\") {\n const session = getSession();\n const sessions = listSessions()\n .sort((a, b) => b.updatedAt - a.updatedAt);\n\n jsonResponse(res, 200, {\n activeTheme: session\n ? { id: session.id, themeName: session.themeName }\n : null,\n sessions,\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n try {\n const { sessionId, deleteFiles } = JSON.parse(body);\n deleteSession(sessionId, deleteFiles);\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\nfunction handleThemeSwitchRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { sessionId } = JSON.parse(body);\n const session = loadSession(sessionId);\n if (!session) {\n jsonResponse(res, 404, { error: \"Session not found\" });\n return;\n }\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: session.themeName,\n themePath: session.themePath,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleDeleteLocalThemeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { themeName } = JSON.parse(body);\n if (!themeName || typeof themeName !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n const themePath = join(WORKSPACE_DIR, themeName);\n if (!existsSync(themePath)) {\n jsonResponse(res, 404, { error: \"Theme not found on disk\" });\n return;\n }\n rmSync(themePath, { recursive: true, force: true });\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleRenameThemeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { sessionId, newName } = JSON.parse(body);\n if (!sessionId || !newName || typeof newName !== \"string\") {\n jsonResponse(res, 400, { error: \"sessionId and newName are required\" });\n return;\n }\n const sanitized = newName.toLowerCase().replace(/[^a-z0-9-]/g, \"-\").replace(/^-|-$/g, \"\").replace(/-{2,}/g, \"-\");\n if (!sanitized) {\n jsonResponse(res, 400, { error: \"Invalid name\" });\n return;\n }\n const result = renameSession(sessionId, sanitized);\n if (result.ok) {\n jsonResponse(res, 200, { ok: true, newName: sanitized });\n } else {\n jsonResponse(res, 400, { error: result.error });\n }\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Version history routes\n// ---------------------------------------------------------------------------\n\nfunction handleHistoryRoute(req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n if (!isGitAvailable()) {\n jsonResponse(res, 200, { available: false, commits: [] });\n return;\n }\n\n // Parse templateId from query string for per-template filtering\n const url = new URL(req.url || \"/\", \"http://localhost\");\n const templateId = url.searchParams.get(\"templateId\");\n\n const commits = templateId\n ? getTemplateHistory(session.themePath, templateId, 50)\n : getHistory(session.themePath, 50);\n jsonResponse(res, 200, { available: true, commits, filtered: !!templateId });\n}\n\nfunction handleRollbackRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n const { hash, templateId } = JSON.parse(body);\n if (!hash || typeof hash !== \"string\") {\n jsonResponse(res, 400, { error: \"Commit hash is required\" });\n return;\n }\n\n // Add a system message to chat (chat is immutable, always grows)\n addMessage(\"assistant\", `Rolled back to version ${hash.slice(0, 7)}.`);\n\n if (templateId) {\n // Scoped rollback: only restore this template's files\n const tpl = session.templates.find((t) => t.id === templateId);\n if (!tpl) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n const filePaths = tpl.moduleOrder.map((n) => `modules/${n}.module`);\n if (tpl.templateFile) filePaths.push(tpl.templateFile);\n\n const result = rollbackTemplateToCommit(session.themePath, templateId, hash, filePaths);\n if (!result.success) {\n jsonResponse(res, 500, { error: result.error || \"Rollback failed\" });\n return;\n }\n reloadActiveTemplateFromDisk();\n } else {\n // Full theme rollback (legacy / \"Show all\" mode)\n const result = rollbackToCommit(session.themePath, hash);\n if (!result.success) {\n jsonResponse(res, 500, { error: result.error || \"Rollback failed\" });\n return;\n }\n reloadModulesFromDisk();\n }\n\n saveSession();\n jsonResponse(res, 200, {\n ok: true,\n modules: getOrderedModules().map((m) => m.moduleName),\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Dashboard & template routes\n// ---------------------------------------------------------------------------\n\nfunction handleDashboardRoute(res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n const library = getModuleLibrary();\n jsonResponse(res, 200, {\n themeName: session.themeName,\n themePath: session.themePath,\n templates: session.templates.map((t) => ({\n id: t.id,\n label: t.label,\n pageType: t.pageType,\n moduleCount: t.modules.length,\n messageCount: t.messages.length,\n })),\n activeTemplateId: session.activeTemplateId,\n moduleLibrary: library.map((entry) => ({\n moduleName: entry.module.moduleName,\n usedIn: entry.usedIn,\n })),\n brandAssets: {\n hasStyleguide: !!session.brandAssets?.styleguide,\n hasBrandvoice: !!session.brandAssets?.brandvoice,\n humanify: session.brandAssets?.humanify !== false,\n },\n });\n}\n\nfunction handleDownloadZipRoute(res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n const themePath = session.themePath;\n if (!existsSync(themePath)) {\n jsonResponse(res, 404, { error: \"Theme directory not found\" });\n return;\n }\n\n const themeName = session.themeName || \"theme\";\n const parentDir = join(themePath, \"..\");\n const folderName = basename(themePath);\n\n try {\n // Create zip in a temp location using the system zip command\n const zipFileName = `${themeName}.zip`;\n const tmpZip = join(parentDir, zipFileName);\n\n // Remove old zip if it exists\n if (existsSync(tmpZip)) rmSync(tmpZip);\n\n execSync(\n `zip -r \"${zipFileName}\" \"${folderName}\" -x \"${folderName}/.git/*\" \"${folderName}/.vibespot/*\" \"${folderName}/node_modules/*\"`,\n { cwd: parentDir, timeout: 30_000 }\n );\n\n const zipData = readFileSync(tmpZip);\n // Clean up temp zip\n rmSync(tmpZip);\n\n res.writeHead(200, {\n \"Content-Type\": \"application/zip\",\n \"Content-Disposition\": `attachment; filename=\"${zipFileName}\"`,\n \"Content-Length\": zipData.length,\n });\n res.end(zipData);\n } catch (err: any) {\n console.warn(\"[download-zip] Failed:\", err.message);\n jsonResponse(res, 500, { error: \"Failed to create zip archive\" });\n }\n}\n\nfunction handleTemplatesRoute(method: string, req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n if (method === \"GET\") {\n jsonResponse(res, 200, {\n templates: session.templates.map((t) => ({\n id: t.id,\n label: t.label,\n pageType: t.pageType,\n moduleCount: t.modules.length,\n })),\n activeTemplateId: session.activeTemplateId,\n });\n return;\n }\n\n if (method === \"POST\") {\n readBody(req, (body) => {\n try {\n const { pageType, label } = JSON.parse(body);\n if (!pageType || !label) {\n jsonResponse(res, 400, { error: \"pageType and label are required\" });\n return;\n }\n const validTypes: PageType[] = [\"landing_page\", \"blog_post\", \"website_page\", \"module_only\"];\n if (!validTypes.includes(pageType)) {\n jsonResponse(res, 400, { error: `Invalid pageType: ${pageType}` });\n return;\n }\n\n const entry = addTemplate(pageType, label);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n template: {\n id: entry.id,\n label: entry.label,\n pageType: entry.pageType,\n },\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n try {\n const { templateId } = JSON.parse(body);\n if (!templateId) {\n jsonResponse(res, 400, { error: \"templateId is required\" });\n return;\n }\n const removed = removeTemplate(templateId);\n if (!removed) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\nfunction handleTemplateActivateRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { templateId } = JSON.parse(body);\n if (!templateId) {\n jsonResponse(res, 400, { error: \"templateId is required\" });\n return;\n }\n const success = setActiveTemplate(templateId);\n if (!success) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n saveSession();\n const session = getSession();\n jsonResponse(res, 200, {\n ok: true,\n modules: getOrderedModules().map((m) => m.moduleName),\n messageCount: session?.messages.length || 0,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleTemplateRenameRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { templateId, newLabel } = JSON.parse(body);\n if (!templateId || !newLabel || typeof newLabel !== \"string\") {\n jsonResponse(res, 400, { error: \"templateId and newLabel are required\" });\n return;\n }\n const success = renameTemplate(templateId, newLabel.trim());\n if (!success) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n saveSession();\n jsonResponse(res, 200, { ok: true, newLabel: newLabel.trim() });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleModuleLibraryRoute(res: ServerResponse): void {\n const library = getModuleLibrary();\n jsonResponse(res, 200, {\n modules: library.map((entry) => ({\n moduleName: entry.module.moduleName,\n usedIn: entry.usedIn,\n fieldsJson: entry.module.fieldsJson,\n })),\n });\n}\n\nfunction handleAddModuleToTemplateRoute(path: string, req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n readBody(req, (body) => {\n try {\n const { moduleName } = JSON.parse(body);\n if (!moduleName) {\n jsonResponse(res, 400, { error: \"moduleName is required\" });\n return;\n }\n\n // Find the module in the library (across all templates)\n const library = getModuleLibrary();\n const entry = library.find((e) => e.module.moduleName === moduleName);\n if (!entry) {\n jsonResponse(res, 404, { error: `Module \"${moduleName}\" not found in library` });\n return;\n }\n\n // Copy the module into the active template / session\n const modCopy = { ...entry.module };\n const existing = session.modules.find((m) => m.moduleName === modCopy.moduleName);\n if (!existing) {\n session.modules.push(modCopy);\n session.moduleOrder.push(modCopy.moduleName);\n session.updatedAt = Date.now();\n }\n\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nfunction handleBrandAssetsRoute(method: string, req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n if (method === \"GET\") {\n jsonResponse(res, 200, {\n styleguide: session.brandAssets?.styleguide || null,\n brandvoice: session.brandAssets?.brandvoice || null,\n });\n return;\n }\n\n if (method === \"POST\") {\n readBody(req, (body) => {\n try {\n const { type, content } = JSON.parse(body);\n if (!type) {\n jsonResponse(res, 400, { error: \"type is required\" });\n return;\n }\n\n if (!session.brandAssets) session.brandAssets = {};\n\n // Humanify toggle (boolean, no file)\n if (type === \"humanify\") {\n session.brandAssets.humanify = content === \"on\";\n session.updatedAt = Date.now();\n saveSession();\n jsonResponse(res, 200, { ok: true });\n return;\n }\n\n if (!content) {\n jsonResponse(res, 400, { error: \"content is required\" });\n return;\n }\n if (type !== \"styleguide\" && type !== \"brandvoice\") {\n jsonResponse(res, 400, { error: `Invalid type: ${type}. Must be \"styleguide\" or \"brandvoice\"` });\n return;\n }\n\n session.brandAssets[type] = content;\n session.updatedAt = Date.now();\n\n // Also persist to theme directory\n const assetDir = join(session.themePath, \".vibespot\");\n ensureDir(assetDir);\n writeFile(join(assetDir, `${type}.md`), content);\n\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n try {\n const { type } = JSON.parse(body);\n if (type !== \"styleguide\" && type !== \"brandvoice\") {\n jsonResponse(res, 400, { error: `Invalid type: ${type}` });\n return;\n }\n\n if (session.brandAssets) {\n delete session.brandAssets[type];\n }\n session.updatedAt = Date.now();\n\n // Remove from disk too\n const filePath = join(session.themePath, \".vibespot\", `${type}.md`);\n if (existsSync(filePath)) rmSync(filePath);\n\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\n// ---------------------------------------------------------------------------\n// WebSocket handler\n// ---------------------------------------------------------------------------\n\nfunction handleWsConnection(ws: WebSocket): void {\n ws.on(\"message\", async (data) => {\n let msg: { type: string; [key: string]: unknown };\n try {\n msg = JSON.parse(data.toString());\n } catch {\n ws.send(JSON.stringify({ type: \"error\", message: \"Invalid JSON\" }));\n return;\n }\n\n switch (msg.type) {\n case \"chat\": {\n const userMessage = String(msg.message || \"\");\n if (!userMessage.trim()) return;\n\n addMessage(\"user\", userMessage);\n saveSession();\n\n // Set up parse warning callback for this generation\n setParseWarningCallback((warning) => {\n ws.send(JSON.stringify({ type: \"parse_warning\", message: warning }));\n });\n\n // Stream AI response back via WebSocket\n try {\n await handleGenerateStream(\n userMessage,\n (chunk) => {\n ws.send(JSON.stringify({ type: \"stream\", content: chunk }));\n },\n (status) => {\n ws.send(JSON.stringify({ type: \"stream_status\", content: status }));\n }\n );\n\n // Write modules to disk and commit for version history\n const currentSession = getSession();\n if (currentSession) {\n writeModulesToDisk();\n const activeTpl = getActiveTemplate();\n let commitHash: string | null = null;\n if (activeTpl) {\n const filePaths = activeTpl.moduleOrder.map((n: string) => `modules/${n}.module`);\n if (activeTpl.templateFile) filePaths.push(activeTpl.templateFile);\n if (activeTpl.sharedCss) filePaths.push(`css/${currentSession.themeName}-theme.css`);\n if (activeTpl.sharedJs) filePaths.push(`js/${currentSession.themeName}-animations.js`);\n commitHash = commitTemplateState(currentSession.themePath, activeTpl.id, userMessage, filePaths);\n } else {\n commitHash = commitThemeState(currentSession.themePath, userMessage);\n }\n if (commitHash) {\n ws.send(JSON.stringify({ type: \"version_created\", hash: commitHash }));\n }\n }\n\n // After generation, send updated preview\n ws.send(JSON.stringify({ type: \"generation_complete\" }));\n ws.send(JSON.stringify({\n type: \"modules_updated\",\n modules: getOrderedModules().map((m) => m.moduleName),\n }));\n } catch (err) {\n ws.send(JSON.stringify({\n type: \"error\",\n message: err instanceof Error ? err.message : String(err),\n }));\n }\n break;\n }\n\n case \"start_upload\": {\n const session = getSession();\n if (!session) {\n ws.send(JSON.stringify({ type: \"error\", message: \"No active session\" }));\n break;\n }\n\n try {\n writeModulesToDisk();\n\n // Apply auto-fixes before uploading\n const fixes = applyAutoFixes(session.themePath);\n if (fixes.length > 0) {\n ws.send(JSON.stringify({ type: \"upload_status\", phase: \"autofix\", fixes }));\n }\n\n // Start streaming upload job\n const jobId = startStreamingJob(\n `hs cms upload \"${session.themePath}\" \"${session.themeName}\"`,\n \"Uploading to HubSpot\",\n { cwd: join(session.themePath, \"..\"), timeout: 180_000 }\n );\n\n ws.send(JSON.stringify({ type: \"upload_started\", jobId }));\n\n // Stream output chunks to the client\n const chunkListener = (chunk: string) => {\n ws.send(JSON.stringify({ type: \"upload_output\", chunk }));\n };\n addJobListener(jobId, chunkListener);\n\n // Poll for job completion\n const pollInterval = setInterval(() => {\n const job = getJob(jobId);\n if (!job || job.status === \"running\") return;\n\n clearInterval(pollInterval);\n removeJobListener(jobId, chunkListener);\n\n if (job.status === \"completed\") {\n const auth = detectHubSpotAuth();\n const dc = auth.portalId ? detectDataCenter(auth.portalId) : \"na1\";\n ws.send(JSON.stringify({\n type: \"upload_complete\",\n output: job.output,\n portalId: auth.portalId || \"\",\n dataCenter: dc,\n themeName: session.themeName,\n }));\n } else {\n const errors = parseUploadErrors(job.output);\n ws.send(JSON.stringify({\n type: \"upload_failed\",\n output: job.output,\n errors,\n exitCode: job.exitCode,\n }));\n }\n }, 500);\n } catch (err) {\n ws.send(JSON.stringify({\n type: \"error\",\n message: err instanceof Error ? err.message : String(err),\n }));\n }\n break;\n }\n\n case \"upload_fix_with_ai\": {\n const errorContext = String(msg.errorContext || \"\");\n if (!errorContext.trim()) {\n ws.send(JSON.stringify({ type: \"error\", message: \"No error context provided\" }));\n break;\n }\n\n const fixPrompt = `The HubSpot upload (\"hs cms upload\") failed. Below is the upload log output containing the errors.\n\nIMPORTANT: Be verbose in your response. For each error:\n1. State exactly which file has the problem and what the error is\n2. Explain WHY this error occurs (e.g. \"HubSpot doesn't support textarea field type\" or \"field name 'name' is reserved in HubSpot modules\")\n3. Describe the specific fix you're applying (e.g. \"Changing field type from textarea to text\" or \"Renaming field from 'name' to 'item_name'\")\n4. Apply the fix to the module files\n\nCRITICAL: After fixing the reported errors, scan ALL other module files in the theme for the same issues. For example, if you fix \"name\" → \"item_name\" in one module, check every other module's fields.json for the same problem. Fix all occurrences, not just the ones in the error log.\n\nAfter fixing all errors, summarize the changes you made.\n\nUpload log:\n${errorContext}`;\n addMessage(\"user\", fixPrompt);\n saveSession();\n\n ws.send(JSON.stringify({ type: \"upload_fix_started\" }));\n\n try {\n await handleGenerateStream(fixPrompt, (chunk) => {\n // Stream to both the chat panel and the upload panel\n ws.send(JSON.stringify({ type: \"stream\", content: chunk }));\n ws.send(JSON.stringify({ type: \"upload_fix_stream\", content: chunk }));\n });\n\n // Write fixes to disk and commit\n const fixSession = getSession();\n if (fixSession) {\n writeModulesToDisk();\n const fixHash = commitThemeState(fixSession.themePath, \"AI fix: upload errors\");\n if (fixHash) {\n ws.send(JSON.stringify({ type: \"version_created\", hash: fixHash }));\n }\n }\n\n ws.send(JSON.stringify({ type: \"upload_fix_complete\" }));\n ws.send(JSON.stringify({\n type: \"modules_updated\",\n modules: getOrderedModules().map((m) => m.moduleName),\n }));\n } catch (err) {\n ws.send(JSON.stringify({\n type: \"upload_failed\",\n output: err instanceof Error ? err.message : String(err),\n errors: [{ file: \"AI fix\", message: err instanceof Error ? err.message : String(err), fixable: false }],\n }));\n }\n break;\n }\n\n case \"ping\":\n ws.send(JSON.stringify({ type: \"pong\" }));\n break;\n\n default:\n ws.send(JSON.stringify({ type: \"error\", message: `Unknown type: ${msg.type}` }));\n }\n });\n\n // Send initial state\n const session = getSession();\n if (session) {\n const cfg = loadConfig();\n const engineLabels: Record<string, string> = {\n \"claude-code\": \"Claude Code\",\n \"anthropic-api\": \"Anthropic API\",\n \"openai-api\": \"OpenAI API\",\n \"gemini-cli\": \"Gemini CLI\",\n \"gemini-api\": \"Gemini API\",\n \"codex-cli\": \"Codex CLI\",\n \"api\": \"Anthropic API\",\n };\n const activeTpl = getActiveTemplate();\n ws.send(JSON.stringify({\n type: \"init\",\n sessionId: session.id,\n themeName: session.themeName,\n modules: getOrderedModules().map((m) => m.moduleName),\n messageCount: session.messages.length,\n messages: session.messages,\n gitAvailable: isGitAvailable(),\n engine: cfg.aiEngine ? engineLabels[cfg.aiEngine] || cfg.aiEngine : \"\",\n // Multi-template context\n templateId: activeTpl?.id || null,\n pageType: activeTpl?.pageType || null,\n templates: (session.templates || []).map((t) => ({\n id: t.id,\n label: t.label,\n pageType: t.pageType,\n moduleCount: t.modules.length,\n })),\n }));\n } else {\n ws.send(JSON.stringify({ type: \"needs_setup\" }));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Static file serving\n// ---------------------------------------------------------------------------\n\nfunction serveStatic(pathname: string, uiDir: string, res: ServerResponse): void {\n // Default to index.html\n let filePath = pathname === \"/\" ? \"/index.html\" : pathname;\n const fullPath = join(uiDir, filePath);\n\n if (!existsSync(fullPath)) {\n // SPA fallback — serve index.html for unknown routes\n const indexPath = join(uiDir, \"index.html\");\n if (existsSync(indexPath)) {\n const content = readFileSync(indexPath);\n res.writeHead(200, { \"Content-Type\": \"text/html\", \"Cache-Control\": \"no-store\" });\n res.end(content);\n } else {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not found\");\n }\n return;\n }\n\n const ext = extname(fullPath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n\n try {\n const content = readFileSync(fullPath);\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"no-store\",\n });\n res.end(content);\n } catch {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction jsonResponse(res: ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n}\n\nfunction readBody(req: IncomingMessage, callback: (body: string) => void): void {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk) => chunks.push(chunk));\n req.on(\"end\", () => callback(Buffer.concat(chunks).toString(\"utf-8\")));\n}\n","/**\n * Session state for the vibe coding workspace.\n * Tracks conversation history, generated modules, and theme state.\n */\n\nimport { readFileSync, readdirSync, existsSync, writeFileSync, mkdirSync, rmSync, renameSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { ModuleFiles, GeneratedAssets } from \"../ai/engine.js\";\nimport { ensureGitRepo } from \"./project-git.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\";\n content: string;\n timestamp: number;\n}\n\nexport type PageType = \"landing_page\" | \"blog_post\" | \"website_page\" | \"module_only\";\n\nexport interface TemplateEntry {\n id: string; // e.g. \"lp-main\", \"blog-post\"\n label: string; // \"Main Landing Page\"\n pageType: PageType;\n templateFile: string; // \"templates/lp-main.html\"\n modules: ModuleFiles[];\n moduleOrder: string[];\n sharedCss: string;\n sharedJs: string;\n template: string; // HubL template content\n messages: ChatMessage[]; // per-template chat history\n}\n\nexport interface VibeSession {\n id: string;\n themePath: string;\n themeName: string;\n\n // Multi-template support\n templates: TemplateEntry[];\n activeTemplateId: string;\n brandAssets?: {\n styleguide?: string;\n brandvoice?: string;\n humanify?: boolean;\n };\n\n // Legacy flat fields — kept for backward compat, redirected to active template\n messages: ChatMessage[];\n modules: ModuleFiles[];\n sharedCss: string;\n sharedJs: string;\n template: string;\n moduleOrder: string[];\n createdAt: number;\n updatedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Session management\n// ---------------------------------------------------------------------------\n\nconst SESSIONS_DIR = join(homedir(), \".vibespot\", \"sessions\");\nconst INDEX_PATH = join(SESSIONS_DIR, \"_index.json\");\n\ninterface SessionIndexEntry {\n id: string;\n themeName: string;\n updatedAt: number;\n moduleCount: number;\n templateCount: number;\n}\n\nfunction readIndex(): SessionIndexEntry[] {\n try {\n if (!existsSync(INDEX_PATH)) return rebuildIndex();\n return JSON.parse(readFileSync(INDEX_PATH, \"utf-8\"));\n } catch {\n return rebuildIndex();\n }\n}\n\nfunction writeIndex(entries: SessionIndexEntry[]): void {\n try {\n mkdirSync(SESSIONS_DIR, { recursive: true });\n writeFileSync(INDEX_PATH, JSON.stringify(entries), \"utf-8\");\n } catch { /* non-critical */ }\n}\n\nfunction rebuildIndex(): SessionIndexEntry[] {\n if (!existsSync(SESSIONS_DIR)) return [];\n const entries: SessionIndexEntry[] = [];\n for (const f of readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(\".json\") && f !== \"_index.json\")) {\n try {\n const data = JSON.parse(readFileSync(join(SESSIONS_DIR, f), \"utf-8\"));\n const templates = data.templates || [];\n entries.push({\n id: data.id,\n themeName: data.themeName,\n updatedAt: data.updatedAt,\n moduleCount: templates.reduce((n: number, t: any) => n + (t.modules?.length || 0), 0),\n templateCount: templates.length,\n });\n } catch { /* skip corrupt files */ }\n }\n writeIndex(entries);\n return entries;\n}\n\nfunction upsertIndex(session: VibeSession): void {\n const entries = readIndex();\n const templates = session.templates || [];\n const entry: SessionIndexEntry = {\n id: session.id,\n themeName: session.themeName,\n updatedAt: session.updatedAt,\n moduleCount: templates.reduce((n, t) => n + (t.modules?.length || 0), 0),\n templateCount: templates.length,\n };\n const idx = entries.findIndex((e) => e.id === session.id);\n if (idx >= 0) entries[idx] = entry;\n else entries.push(entry);\n writeIndex(entries);\n}\n\nfunction removeFromIndex(sessionId: string): void {\n const entries = readIndex().filter((e) => e.id !== sessionId);\n writeIndex(entries);\n}\n\nfunction removeFromIndexByTheme(themeName: string): void {\n const entries = readIndex().filter((e) => e.themeName !== themeName);\n writeIndex(entries);\n}\n\nlet activeSession: VibeSession | null = null;\n\nexport function createSession(themePath: string, themeName: string): VibeSession {\n const session: VibeSession = {\n id: generateId(),\n themePath,\n themeName,\n templates: [],\n activeTemplateId: \"\",\n messages: [],\n modules: [],\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n moduleOrder: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n activeSession = session;\n ensureGitRepo(themePath);\n return session;\n}\n\n// ---------------------------------------------------------------------------\n// Template management\n// ---------------------------------------------------------------------------\n\n/**\n * Migrate a legacy flat session (v0.3.0) into the templates array.\n * Called when loading a session that has modules but no templates.\n */\nexport function migrateSession(session: VibeSession): void {\n if (session.templates && session.templates.length > 0) return;\n if (!session.modules || session.modules.length === 0) {\n session.templates = [];\n session.activeTemplateId = \"\";\n return;\n }\n\n const templateId = `lp-${session.themeName}`;\n const entry: TemplateEntry = {\n id: templateId,\n label: `${session.themeName} Landing Page`,\n pageType: \"landing_page\",\n templateFile: `templates/lp-${session.themeName}.html`,\n modules: [...session.modules],\n moduleOrder: [...session.moduleOrder],\n sharedCss: session.sharedCss || \"\",\n sharedJs: session.sharedJs || \"\",\n template: session.template || \"\",\n messages: [...session.messages],\n };\n\n session.templates = [entry];\n session.activeTemplateId = templateId;\n}\n\n/**\n * Get the active template entry, or null if none set.\n */\nexport function getActiveTemplate(): TemplateEntry | null {\n if (!activeSession) return null;\n if (!activeSession.activeTemplateId || !activeSession.templates?.length) return null;\n return activeSession.templates.find((t) => t.id === activeSession!.activeTemplateId) || null;\n}\n\n/**\n * Set the active template by ID. Syncs flat fields from the template.\n */\nexport function setActiveTemplate(templateId: string): boolean {\n if (!activeSession) return false;\n const tpl = activeSession.templates.find((t) => t.id === templateId);\n if (!tpl) return false;\n\n activeSession.activeTemplateId = templateId;\n syncFlatFieldsFromTemplate(tpl);\n activeSession.updatedAt = Date.now();\n return true;\n}\n\n/**\n * Create a new template entry and add it to the session.\n */\nexport function addTemplate(pageType: PageType, label: string): TemplateEntry {\n if (!activeSession) throw new Error(\"No active session\");\n\n const slug = label\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n const prefix = pageType === \"blog_post\" ? \"bp\" :\n pageType === \"website_page\" ? \"wp\" :\n pageType === \"module_only\" ? \"mo\" : \"lp\";\n const id = `${prefix}-${slug}`;\n\n const entry: TemplateEntry = {\n id,\n label,\n pageType,\n templateFile: pageType === \"module_only\" ? \"\" : `templates/${id}.html`,\n modules: [],\n moduleOrder: [],\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n messages: [],\n };\n\n activeSession.templates.push(entry);\n activeSession.activeTemplateId = id;\n syncFlatFieldsFromTemplate(entry);\n activeSession.updatedAt = Date.now();\n return entry;\n}\n\n/**\n * Rename a template's display label.\n */\nexport function renameTemplate(templateId: string, newLabel: string): boolean {\n if (!activeSession) return false;\n const tpl = activeSession.templates.find((t) => t.id === templateId);\n if (!tpl) return false;\n tpl.label = newLabel;\n activeSession.updatedAt = Date.now();\n return true;\n}\n\n/**\n * Remove a template by ID.\n */\nexport function removeTemplate(templateId: string): boolean {\n if (!activeSession) return false;\n const idx = activeSession.templates.findIndex((t) => t.id === templateId);\n if (idx < 0) return false;\n\n activeSession.templates.splice(idx, 1);\n\n // If we removed the active template, switch to the first remaining one\n if (activeSession.activeTemplateId === templateId) {\n if (activeSession.templates.length > 0) {\n setActiveTemplate(activeSession.templates[0].id);\n } else {\n activeSession.activeTemplateId = \"\";\n activeSession.modules = [];\n activeSession.moduleOrder = [];\n activeSession.sharedCss = \"\";\n activeSession.sharedJs = \"\";\n activeSession.template = \"\";\n activeSession.messages = [];\n }\n }\n\n activeSession.updatedAt = Date.now();\n return true;\n}\n\n/**\n * Get deduplicated modules across all templates (the module library).\n */\nexport function getModuleLibrary(): Array<{ module: ModuleFiles; usedIn: string[] }> {\n if (!activeSession) return [];\n const map = new Map<string, { module: ModuleFiles; usedIn: string[] }>();\n\n for (const tpl of activeSession.templates) {\n for (const mod of tpl.modules) {\n const existing = map.get(mod.moduleName);\n if (existing) {\n existing.usedIn.push(tpl.label);\n } else {\n map.set(mod.moduleName, { module: mod, usedIn: [tpl.label] });\n }\n }\n }\n\n return Array.from(map.values());\n}\n\n/**\n * Sync flat session fields from a template (compatibility layer).\n * Existing code reads session.modules, session.messages, etc.\n * This keeps those in sync with the active template.\n */\nfunction syncFlatFieldsFromTemplate(tpl: TemplateEntry): void {\n if (!activeSession) return;\n activeSession.modules = tpl.modules;\n activeSession.moduleOrder = tpl.moduleOrder;\n activeSession.sharedCss = tpl.sharedCss;\n activeSession.sharedJs = tpl.sharedJs;\n activeSession.template = tpl.template;\n activeSession.messages = tpl.messages;\n}\n\n/**\n * Sync changes from flat session fields back to the active template.\n * Called after any mutation to session.modules/sharedCss/etc.\n */\nfunction syncFlatFieldsToTemplate(): void {\n if (!activeSession) return;\n const tpl = getActiveTemplate();\n if (!tpl) return;\n tpl.modules = activeSession.modules;\n tpl.moduleOrder = activeSession.moduleOrder;\n tpl.sharedCss = activeSession.sharedCss;\n tpl.sharedJs = activeSession.sharedJs;\n tpl.template = activeSession.template;\n tpl.messages = activeSession.messages;\n}\n\nexport function getSession(): VibeSession | null {\n return activeSession;\n}\n\nexport function addMessage(role: \"user\" | \"assistant\", content: string): void {\n if (!activeSession) return;\n activeSession.messages.push({ role, content, timestamp: Date.now() });\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n saveChatToTheme();\n}\n\n/**\n * Update session with newly generated/modified modules.\n * Merges new modules into existing state (updates existing, adds new).\n */\nexport function updateModules(assets: Partial<GeneratedAssets>): void {\n if (!activeSession) return;\n\n if (assets.sharedCss !== undefined) activeSession.sharedCss = assets.sharedCss;\n if (assets.sharedJs !== undefined) activeSession.sharedJs = assets.sharedJs;\n if (assets.template !== undefined) activeSession.template = assets.template;\n\n if (assets.modules) {\n for (const newMod of assets.modules) {\n const idx = activeSession.modules.findIndex(\n (m) => m.moduleName === newMod.moduleName\n );\n if (idx >= 0) {\n activeSession.modules[idx] = newMod;\n } else {\n activeSession.modules.push(newMod);\n activeSession.moduleOrder.push(newMod.moduleName);\n }\n }\n }\n\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Reorder modules (used by drag-and-drop in the UI).\n */\nexport function reorderModules(newOrder: string[]): void {\n if (!activeSession) return;\n activeSession.moduleOrder = newOrder;\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Remove a module by name.\n */\nexport function removeModule(moduleName: string): void {\n if (!activeSession) return;\n activeSession.modules = activeSession.modules.filter(\n (m) => m.moduleName !== moduleName\n );\n activeSession.moduleOrder = activeSession.moduleOrder.filter(\n (n) => n !== moduleName\n );\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Detach a module from the current template (remove from moduleOrder only).\n * The module data stays in the session so it can be re-added later.\n */\nexport function detachModule(moduleName: string): void {\n if (!activeSession) return;\n activeSession.moduleOrder = activeSession.moduleOrder.filter(\n (n) => n !== moduleName\n );\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Update a single field value in a module's fields.json.\n * Used by the field editor sidebar.\n */\nexport function updateFieldValue(\n moduleName: string,\n fieldPath: string,\n value: unknown\n): void {\n if (!activeSession) return;\n\n const mod = activeSession.modules.find((m) => m.moduleName === moduleName);\n if (!mod) return;\n\n try {\n const fields = JSON.parse(mod.fieldsJson);\n setFieldDefault(fields, fieldPath, value);\n mod.fieldsJson = JSON.stringify(fields, null, 2);\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n } catch {\n // Invalid JSON — skip\n }\n}\n\n/**\n * Get modules in display order.\n */\nexport function getOrderedModules(): ModuleFiles[] {\n if (!activeSession) return [];\n\n const ordered: ModuleFiles[] = [];\n for (const name of activeSession.moduleOrder) {\n const mod = activeSession.modules.find((m) => m.moduleName === name);\n if (mod) ordered.push(mod);\n }\n\n // Append any modules not in the order list\n for (const mod of activeSession.modules) {\n if (!activeSession.moduleOrder.includes(mod.moduleName)) {\n ordered.push(mod);\n }\n }\n\n return ordered;\n}\n\n// ---------------------------------------------------------------------------\n// Scan modules from disk (for loading existing themes)\n// ---------------------------------------------------------------------------\n\n/**\n * Scan a theme directory on disk and load existing modules into the session.\n */\nexport function scanThemeFromDisk(themePath: string): void {\n if (!activeSession) return;\n\n // Load persisted chat from theme directory (if session has no messages yet)\n const chatFromDisk = loadChatFromTheme(themePath);\n if (chatFromDisk.length > 0 && activeSession.messages.length === 0) {\n activeSession.messages = chatFromDisk;\n }\n\n // Ensure git repo exists (handles themes created before this feature)\n ensureGitRepo(themePath);\n\n const modulesDir = join(themePath, \"modules\");\n if (!existsSync(modulesDir)) return;\n\n const entries = readdirSync(modulesDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith(\".module\")) continue;\n\n const modDir = join(modulesDir, entry.name);\n const moduleName = entry.name.replace(/\\.module$/, \"\");\n\n const mod: ModuleFiles = {\n moduleName,\n fieldsJson: safeRead(join(modDir, \"fields.json\")),\n metaJson: safeRead(join(modDir, \"meta.json\")),\n moduleHtml: safeRead(join(modDir, \"module.html\")),\n moduleCss: safeRead(join(modDir, \"module.css\")),\n moduleJs: safeRead(join(modDir, \"module.js\")) || undefined,\n };\n\n if (mod.fieldsJson && mod.moduleHtml) {\n activeSession.modules.push(mod);\n activeSession.moduleOrder.push(moduleName);\n }\n }\n\n // Load shared CSS/JS\n const cssDir = join(themePath, \"css\");\n const jsDir = join(themePath, \"js\");\n\n if (existsSync(cssDir)) {\n const cssFiles = readdirSync(cssDir).filter(\n (f) => f.endsWith(\"-theme.css\") || f.endsWith(\"-theme.css\")\n );\n if (cssFiles.length > 0) {\n activeSession.sharedCss = safeRead(join(cssDir, cssFiles[0]));\n }\n }\n\n if (existsSync(jsDir)) {\n const jsFiles = readdirSync(jsDir).filter(\n (f) => f.endsWith(\"-animations.js\")\n );\n if (jsFiles.length > 0) {\n activeSession.sharedJs = safeRead(join(jsDir, jsFiles[0]));\n }\n }\n\n // Load brand assets from .vibespot/ directory\n const sgPath = join(themePath, \".vibespot\", \"styleguide.md\");\n const bvPath = join(themePath, \".vibespot\", \"brandvoice.md\");\n if (existsSync(sgPath) || existsSync(bvPath)) {\n if (!activeSession.brandAssets) activeSession.brandAssets = {};\n if (existsSync(sgPath)) activeSession.brandAssets.styleguide = safeRead(sgPath);\n if (existsSync(bvPath)) activeSession.brandAssets.brandvoice = safeRead(bvPath);\n }\n\n // Migrate flat fields to templates if this is a pre-existing theme\n if (!activeSession.templates) activeSession.templates = [];\n if (!activeSession.activeTemplateId) activeSession.activeTemplateId = \"\";\n migrateSession(activeSession);\n}\n\n// ---------------------------------------------------------------------------\n// Persistence — save/load sessions across restarts\n// ---------------------------------------------------------------------------\n\nexport function saveSession(): void {\n if (!activeSession) return;\n\n mkdirSync(SESSIONS_DIR, { recursive: true });\n const filePath = join(SESSIONS_DIR, `${activeSession.id}.json`);\n writeFileSync(filePath, JSON.stringify(activeSession, null, 2), \"utf-8\");\n upsertIndex(activeSession);\n}\n\nexport function loadSession(sessionId: string): VibeSession | null {\n const filePath = join(SESSIONS_DIR, sessionId + \".json\");\n if (!existsSync(filePath)) return null;\n\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n\n // Ensure templates array exists (backward compat with v0.3.0 sessions)\n if (!data.templates) data.templates = [];\n if (!data.activeTemplateId) data.activeTemplateId = \"\";\n\n // Migrate flat fields into templates if needed\n migrateSession(data);\n\n activeSession = data;\n return data;\n } catch {\n return null;\n }\n}\n\nexport function listSessions(): Array<{ id: string; themeName: string; updatedAt: number; moduleCount: number; templateCount: number }> {\n if (!existsSync(SESSIONS_DIR)) return [];\n return readIndex();\n}\n\nexport function deleteSession(sessionId: string, deleteFiles = false): void {\n const filePath = join(SESSIONS_DIR, sessionId + \".json\");\n\n // Read the session to get themeName (needed to find sibling sessions)\n let themeName = \"\";\n if (deleteFiles) {\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n themeName = data.themeName || \"\";\n if (data.themePath && existsSync(data.themePath)) {\n rmSync(data.themePath, { recursive: true, force: true });\n }\n } catch { /* ignore */ }\n } else {\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n themeName = data.themeName || \"\";\n } catch { /* ignore */ }\n }\n\n try {\n if (existsSync(filePath)) rmSync(filePath);\n } catch { /* ignore */ }\n\n // Also delete all other sessions for the same theme (prevents ghost entries)\n if (themeName && existsSync(SESSIONS_DIR)) {\n for (const f of readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(\".json\") && f !== \"_index.json\")) {\n try {\n const data = JSON.parse(readFileSync(join(SESSIONS_DIR, f), \"utf-8\"));\n if (data.themeName === themeName) {\n rmSync(join(SESSIONS_DIR, f));\n }\n } catch { /* ignore */ }\n }\n removeFromIndexByTheme(themeName);\n } else {\n removeFromIndex(sessionId);\n }\n\n if (activeSession?.id === sessionId) {\n activeSession = null;\n }\n}\n\n/**\n * Rename a project: update themeName in all sessions, rename disk folder,\n * rename CSS/JS files, and update the session index.\n */\nexport function renameSession(sessionId: string, newName: string): { ok: boolean; error?: string } {\n // Load the session to get the current theme name\n const filePath = join(SESSIONS_DIR, sessionId + \".json\");\n if (!existsSync(filePath)) return { ok: false, error: \"Session not found\" };\n\n let session: VibeSession;\n try {\n session = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return { ok: false, error: \"Failed to read session\" };\n }\n\n const oldName = session.themeName;\n if (oldName === newName) return { ok: true };\n\n const oldPath = session.themePath;\n const newPath = join(dirname(oldPath), newName);\n\n // Rename the folder on disk\n if (existsSync(oldPath)) {\n if (existsSync(newPath)) return { ok: false, error: \"A project with that name already exists\" };\n try {\n renameSync(oldPath, newPath);\n } catch (err) {\n return { ok: false, error: `Failed to rename folder: ${err instanceof Error ? err.message : String(err)}` };\n }\n\n // Rename CSS/JS files inside the new folder\n const cssOld = join(newPath, \"css\", `${oldName}-theme.css`);\n const cssNew = join(newPath, \"css\", `${newName}-theme.css`);\n if (existsSync(cssOld)) try { renameSync(cssOld, cssNew); } catch { /* non-critical */ }\n\n const jsOld = join(newPath, \"js\", `${oldName}-animations.js`);\n const jsNew = join(newPath, \"js\", `${newName}-animations.js`);\n if (existsSync(jsOld)) try { renameSync(jsOld, jsNew); } catch { /* non-critical */ }\n\n // Update theme.json label/name\n const themeJsonPath = join(newPath, \"theme.json\");\n if (existsSync(themeJsonPath)) {\n try {\n const themeData = JSON.parse(readFileSync(themeJsonPath, \"utf-8\"));\n themeData.label = newName;\n themeData.name = newName;\n writeFileSync(themeJsonPath, JSON.stringify(themeData, null, 2), \"utf-8\");\n } catch { /* non-critical */ }\n }\n }\n\n // Update all sessions that reference this theme\n if (existsSync(SESSIONS_DIR)) {\n for (const f of readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(\".json\") && f !== \"_index.json\")) {\n try {\n const data = JSON.parse(readFileSync(join(SESSIONS_DIR, f), \"utf-8\"));\n if (data.themeName === oldName) {\n data.themeName = newName;\n data.themePath = newPath;\n data.updatedAt = Date.now();\n writeFileSync(join(SESSIONS_DIR, f), JSON.stringify(data, null, 2), \"utf-8\");\n }\n } catch { /* skip corrupt files */ }\n }\n }\n\n // Update the in-memory active session\n if (activeSession && activeSession.themeName === oldName) {\n activeSession.themeName = newName;\n activeSession.themePath = newPath;\n activeSession.updatedAt = Date.now();\n }\n\n // Rebuild the index\n rebuildIndex();\n\n return { ok: true };\n}\n\n// ---------------------------------------------------------------------------\n// Write modules back to disk (for upload)\n// ---------------------------------------------------------------------------\n\nexport function writeModulesToDisk(): void {\n if (!activeSession) return;\n\n const themePath = activeSession.themePath;\n\n // Collect all modules from all templates (deduplicated by name)\n const allModules = new Map<string, ModuleFiles>();\n if (activeSession.templates.length > 0) {\n for (const tpl of activeSession.templates) {\n for (const mod of tpl.modules) {\n allModules.set(mod.moduleName, mod);\n }\n }\n }\n // Also include flat session modules (backward compat / active template)\n for (const mod of activeSession.modules) {\n allModules.set(mod.moduleName, mod);\n }\n\n for (const mod of allModules.values()) {\n const modDir = join(themePath, \"modules\", `${mod.moduleName}.module`);\n mkdirSync(modDir, { recursive: true });\n\n writeFileSync(join(modDir, \"fields.json\"), mod.fieldsJson, \"utf-8\");\n writeFileSync(join(modDir, \"meta.json\"), mod.metaJson, \"utf-8\");\n writeFileSync(join(modDir, \"module.html\"), mod.moduleHtml, \"utf-8\");\n writeFileSync(join(modDir, \"module.css\"), mod.moduleCss, \"utf-8\");\n if (mod.moduleJs) {\n writeFileSync(join(modDir, \"module.js\"), mod.moduleJs, \"utf-8\");\n }\n }\n\n // Write shared CSS/JS\n if (activeSession.sharedCss) {\n const cssDir = join(themePath, \"css\");\n mkdirSync(cssDir, { recursive: true });\n writeFileSync(\n join(cssDir, `${activeSession.themeName}-theme.css`),\n activeSession.sharedCss,\n \"utf-8\"\n );\n }\n\n if (activeSession.sharedJs) {\n const jsDir = join(themePath, \"js\");\n mkdirSync(jsDir, { recursive: true });\n writeFileSync(\n join(jsDir, `${activeSession.themeName}-animations.js`),\n activeSession.sharedJs,\n \"utf-8\"\n );\n }\n\n // Write page templates for all templates in the session\n if (activeSession.templates.length > 0) {\n const templatesDir = join(themePath, \"templates\");\n mkdirSync(templatesDir, { recursive: true });\n\n for (const tpl of activeSession.templates) {\n if (tpl.pageType === \"module_only\") continue; // No template for module-only\n if (tpl.modules.length === 0) continue;\n\n const templateContent = tpl.template || generateTemplateForEntry(tpl);\n const annotated = ensureTemplateAnnotations(templateContent, tpl.label, tpl.pageType);\n writeFileSync(\n join(templatesDir, `${tpl.id}.html`),\n annotated,\n \"utf-8\"\n );\n\n // For blog posts, also generate a listing template\n if (tpl.pageType === \"blog_post\") {\n writeBlogListingTemplate(templatesDir, tpl);\n }\n }\n } else if (activeSession.modules.length > 0) {\n // Legacy fallback: single template from flat fields\n const template = activeSession.template || generateTemplateFromModules();\n const templatesDir = join(themePath, \"templates\");\n mkdirSync(templatesDir, { recursive: true });\n const annotated = ensureTemplateAnnotations(template, `${activeSession.themeName} Landing Page`);\n writeFileSync(\n join(templatesDir, `lp-${activeSession.themeName}.html`),\n annotated,\n \"utf-8\"\n );\n }\n\n // Patch base.html to load template_js (animations won't work without this)\n patchBaseTemplate();\n\n // Populate theme.json with proper metadata\n updateThemeJson();\n}\n\n// ---------------------------------------------------------------------------\n// Chat persistence — store chat in theme directory\n// ---------------------------------------------------------------------------\n\n/**\n * Persist chat to {themePath}/.vibespot/chat.json (gitignored).\n */\nfunction saveChatToTheme(): void {\n if (!activeSession) return;\n try {\n const chatDir = join(activeSession.themePath, \".vibespot\");\n mkdirSync(chatDir, { recursive: true });\n const chatData = {\n sessionId: activeSession.id,\n themeName: activeSession.themeName,\n messages: activeSession.messages,\n updatedAt: Date.now(),\n };\n writeFileSync(join(chatDir, \"chat.json\"), JSON.stringify(chatData, null, 2), \"utf-8\");\n } catch {\n // Non-critical — don't block on chat persistence errors\n }\n}\n\n/**\n * Load chat history from a theme's .vibespot/chat.json.\n */\nfunction loadChatFromTheme(themePath: string): ChatMessage[] {\n const chatPath = join(themePath, \".vibespot\", \"chat.json\");\n if (!existsSync(chatPath)) return [];\n try {\n const data = JSON.parse(readFileSync(chatPath, \"utf-8\"));\n return Array.isArray(data.messages) ? data.messages : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Clear in-memory modules and re-scan from disk.\n * Used after a git rollback to sync session state with restored files.\n */\nexport function reloadModulesFromDisk(): void {\n if (!activeSession) return;\n activeSession.modules = [];\n activeSession.moduleOrder = [];\n activeSession.sharedCss = \"\";\n activeSession.sharedJs = \"\";\n activeSession.template = \"\";\n scanThemeFromDisk(activeSession.themePath);\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Reload only the active template's modules from disk.\n * Used after a scoped rollback to avoid affecting other templates.\n */\nexport function reloadActiveTemplateFromDisk(): void {\n if (!activeSession) return;\n const tpl = getActiveTemplate();\n if (!tpl) return;\n\n const themePath = activeSession.themePath;\n const modulesDir = join(themePath, \"modules\");\n\n // Reload modules that belong to this template\n tpl.modules = [];\n for (const name of tpl.moduleOrder) {\n const modDir = join(modulesDir, `${name}.module`);\n if (!existsSync(modDir)) continue;\n const mod: ModuleFiles = {\n moduleName: name,\n fieldsJson: safeRead(join(modDir, \"fields.json\")),\n metaJson: safeRead(join(modDir, \"meta.json\")),\n moduleHtml: safeRead(join(modDir, \"module.html\")),\n moduleCss: safeRead(join(modDir, \"module.css\")),\n moduleJs: safeRead(join(modDir, \"module.js\")) || undefined,\n };\n if (mod.fieldsJson && mod.moduleHtml) {\n tpl.modules.push(mod);\n }\n }\n\n // Reload template file\n if (tpl.templateFile) {\n const tplPath = join(themePath, tpl.templateFile);\n if (existsSync(tplPath)) {\n tpl.template = safeRead(tplPath);\n }\n }\n\n // Sync flat fields from the updated template\n syncFlatFieldsFromTemplate(tpl);\n activeSession.updatedAt = Date.now();\n}\n\n// ---------------------------------------------------------------------------\n// Theme metadata — populate theme.json + validate template annotations\n// ---------------------------------------------------------------------------\n\n/**\n * Patch base.html to load template_js (the boilerplate only loads template_css).\n * Without this, shared animations JS never runs and scroll-animate elements stay invisible.\n */\nfunction patchBaseTemplate(): void {\n if (!activeSession) return;\n const basePath = join(activeSession.themePath, \"templates\", \"layouts\", \"base.html\");\n if (!existsSync(basePath)) return;\n\n try {\n let content = readFileSync(basePath, \"utf-8\");\n // Already patched?\n if (content.includes(\"template_js\")) return;\n\n // Insert {% if template_js %} block right after the main.js require line\n const mainJsLine = '{{ require_js(get_asset_url(\"../../js/main.js\")) }}';\n if (content.includes(mainJsLine)) {\n content = content.replace(\n mainJsLine,\n mainJsLine + '\\n {% if template_js %}\\n {{ require_js(get_asset_url(template_js)) }}\\n {% endif %}'\n );\n } else {\n // Fallback: insert before standard_footer_includes\n content = content.replace(\n \"{{ standard_footer_includes }}\",\n '{% if template_js %}\\n {{ require_js(get_asset_url(template_js)) }}\\n {% endif %}\\n {{ standard_footer_includes }}'\n );\n }\n\n writeFileSync(basePath, content, \"utf-8\");\n } catch {\n // Non-critical — the generated template has its own require_js fallback\n }\n}\n\n/**\n * Update theme.json with proper name/label and ensure template annotations.\n * Called during writeModulesToDisk.\n */\nfunction updateThemeJson(): void {\n if (!activeSession) return;\n const themeJsonPath = join(activeSession.themePath, \"theme.json\");\n if (!existsSync(themeJsonPath)) return;\n\n try {\n const themeData = JSON.parse(readFileSync(themeJsonPath, \"utf-8\"));\n themeData.label = activeSession.themeName;\n themeData.name = activeSession.themeName;\n writeFileSync(themeJsonPath, JSON.stringify(themeData, null, 2), \"utf-8\");\n } catch {\n // Non-critical\n }\n}\n\n/**\n * Ensure the page template has proper HubSpot annotations.\n */\nfunction ensureTemplateAnnotations(templateContent: string, label: string, pageType: PageType = \"landing_page\"): string {\n // Check if annotations already exist\n if (templateContent.includes(\"templateType\")) return templateContent;\n\n const templateType = pageType === \"blog_post\" ? \"blog_post\" : \"page\";\n const annotations = `<!--\n templateType: ${templateType}\n isAvailableForNewContent: true\n label: \"${label}\"\n-->\\n`;\n return annotations + templateContent;\n}\n\n// ---------------------------------------------------------------------------\n// Template generation — build page templates from module data\n// ---------------------------------------------------------------------------\n\n/**\n * Build a HubSpot page template for a specific TemplateEntry.\n */\nfunction generateTemplateForEntry(tpl: TemplateEntry): string {\n if (tpl.modules.length === 0) return \"\";\n\n const name = activeSession!.themeName;\n const ordered = getOrderedModulesFrom(tpl);\n\n const sections = ordered.map((mod) => {\n return ` {% dnd_section padding={\"top\":\"0\",\"bottom\":\"0\",\"left\":\"0\",\"right\":\"0\"}, full_width=true %}\n {% dnd_module path=\"../modules/${mod.moduleName}.module\" %}\n {% end_dnd_module %}\n {% end_dnd_section %}`;\n }).join(\"\\n\\n\");\n\n const templateType = tpl.pageType === \"blog_post\" ? \"blog_post\" : \"page\";\n\n return `<!--\n templateType: ${templateType}\n isAvailableForNewContent: true\n label: \"${tpl.label}\"\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% set template_css = \"../../css/${name}-theme.css\" %}\n{% set template_js = \"../../js/${name}-animations.js\" %}\n\n{% block header %}\n{% endblock header %}\n\n{% block body %}\n<div class=\"${name}-page\">\n {% dnd_area \"main_content\" label=\"${tpl.label}\" %}\n\n${sections}\n\n {% end_dnd_area %}\n</div>\n{{ require_js(get_asset_url(\"../../js/${name}-animations.js\")) }}\n{% endblock body %}\n\n{% block footer %}\n{% endblock footer %}\n`;\n}\n\n/**\n * Write a blog listing template alongside a blog post template.\n */\nfunction writeBlogListingTemplate(templatesDir: string, tpl: TemplateEntry): void {\n const listingContent = `<!--\n templateType: blog_listing\n isAvailableForNewContent: true\n label: \"${tpl.label} - Listing\"\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% block body %}\n<div class=\"blog-listing\">\n <h1>{{ group.public_title }}</h1>\n {% for content in contents %}\n <article class=\"blog-listing__post\">\n <h2><a href=\"{{ content.absolute_url }}\">{{ content.name }}</a></h2>\n {% if content.featured_image %}\n <img src=\"{{ content.featured_image }}\" alt=\"{{ content.featured_image_alt_text }}\">\n {% endif %}\n <p>{{ content.post_summary|truncatewords(30) }}</p>\n <span class=\"blog-listing__date\">{{ content.publish_date|datetimeformat('%B %d, %Y') }}</span>\n </article>\n {% endfor %}\n {% if next_page_num %}\n <a href=\"{{ next_page_url }}\">Next Page</a>\n {% endif %}\n</div>\n{% endblock body %}\n`;\n writeFileSync(\n join(templatesDir, `${tpl.id}-listing.html`),\n listingContent,\n \"utf-8\"\n );\n}\n\n/**\n * Get modules in display order for a specific template entry.\n */\nfunction getOrderedModulesFrom(tpl: TemplateEntry): ModuleFiles[] {\n const ordered: ModuleFiles[] = [];\n for (const name of tpl.moduleOrder) {\n const mod = tpl.modules.find((m) => m.moduleName === name);\n if (mod) ordered.push(mod);\n }\n for (const mod of tpl.modules) {\n if (!tpl.moduleOrder.includes(mod.moduleName)) {\n ordered.push(mod);\n }\n }\n return ordered;\n}\n\n/**\n * Build a HubSpot page template that assembles all modules in display order.\n * Legacy — used when no templates array exists (flat session).\n */\nfunction generateTemplateFromModules(): string {\n if (!activeSession || activeSession.modules.length === 0) return \"\";\n\n const name = activeSession.themeName;\n const ordered = getOrderedModules();\n\n const sections = ordered.map((mod) => {\n return ` {% dnd_section padding={\"top\":\"0\",\"bottom\":\"0\",\"left\":\"0\",\"right\":\"0\"}, full_width=true %}\n {% dnd_module path=\"../modules/${mod.moduleName}.module\" %}\n {% end_dnd_module %}\n {% end_dnd_section %}`;\n }).join(\"\\n\\n\");\n\n return `<!--\n templateType: page\n isAvailableForNewContent: true\n label: \"${name} Landing Page\"\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% set template_css = \"../../css/${name}-theme.css\" %}\n{% set template_js = \"../../js/${name}-animations.js\" %}\n\n{% block header %}\n{% endblock header %}\n\n{% block body %}\n<div class=\"${name}-page\">\n {% dnd_area \"main_content\" label=\"${name} Landing Page\" %}\n\n${sections}\n\n {% end_dnd_area %}\n</div>\n{{ require_js(get_asset_url(\"../../js/${name}-animations.js\")) }}\n{% endblock body %}\n\n{% block footer %}\n{% endblock footer %}\n`;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generateId(): string {\n return `vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction safeRead(filePath: string): string {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return \"\";\n }\n}\n\n/**\n * Set a default value at a dot-separated field path in a fields.json array.\n */\nfunction setFieldDefault(fields: FieldDef[], path: string, value: unknown): void {\n const parts = path.split(\".\");\n const fieldName = parts[0];\n const field = fields.find((f: FieldDef) => f.name === fieldName);\n if (!field) return;\n\n if (parts.length === 1) {\n field.default = value;\n } else if (field.children) {\n setFieldDefault(field.children, parts.slice(1).join(\".\"), value);\n }\n}\n\ninterface FieldDef {\n name: string;\n default?: unknown;\n children?: FieldDef[];\n}\n","/**\n * Per-project local git — auto-commits, version history, rollback.\n * All operations are local-only. Git is optional; if unavailable,\n * every function degrades gracefully (returns null / false / []).\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\n\nexport interface GitCommitInfo {\n hash: string; // short hash (7 chars)\n fullHash: string; // full SHA\n message: string; // first line of commit message\n timestamp: number; // unix epoch ms\n date: string; // ISO string for display\n}\n\n// ---------------------------------------------------------------------------\n// Git availability (cached)\n// ---------------------------------------------------------------------------\n\nlet gitAvailableCache: boolean | null = null;\n\nexport function isGitAvailable(): boolean {\n if (gitAvailableCache !== null) return gitAvailableCache;\n const result = run(\"git --version\");\n gitAvailableCache = result.success;\n return gitAvailableCache;\n}\n\n// ---------------------------------------------------------------------------\n// Repo initialization\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure a git repo exists in the theme directory.\n * Creates .gitignore, .vibespot/ dir, and initial commit if needed.\n * Safe to call multiple times (idempotent).\n */\nexport function ensureGitRepo(themePath: string): boolean {\n if (!isGitAvailable()) return false;\n\n // Already initialized\n if (existsSync(join(themePath, \".git\"))) {\n ensureVibeSpotDir(themePath);\n return true;\n }\n\n // Init repo\n const init = run(\"git init\", { cwd: themePath });\n if (!init.success) {\n console.warn(`[project-git] git init failed in ${themePath}: ${init.stderr}`);\n return false;\n }\n\n // Create .gitignore\n writeGitIgnore(themePath);\n\n // Create .vibespot/ dir for chat persistence\n ensureVibeSpotDir(themePath);\n\n // Initial commit\n run(\"git add -A\", { cwd: themePath });\n run('git commit -m \"Initial theme\"', { cwd: themePath });\n\n return true;\n}\n\nfunction ensureVibeSpotDir(themePath: string): void {\n const dir = join(themePath, \".vibespot\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nfunction writeGitIgnore(themePath: string): void {\n const gitignorePath = join(themePath, \".gitignore\");\n const lines = [\".vibespot/\", \"node_modules/\", \"\"];\n writeFileSync(gitignorePath, lines.join(\"\\n\"), \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// Committing\n// ---------------------------------------------------------------------------\n\n/**\n * Stage all changes and commit with the given message.\n * Returns the short commit hash, or null if nothing to commit or error.\n */\nexport function commitThemeState(themePath: string, message: string): string | null {\n if (!isGitAvailable()) return null;\n if (!existsSync(join(themePath, \".git\"))) return null;\n\n // Stage everything\n run(\"git add -A\", { cwd: themePath });\n\n // Check if there are staged changes\n const diff = run(\"git diff --cached --quiet\", { cwd: themePath });\n if (diff.success) return null; // exit 0 = nothing staged\n\n // Truncate message to 72 chars\n const truncated = message.length > 72\n ? message.slice(0, 69) + \"...\"\n : message;\n\n // Commit (use -- to prevent message from being interpreted as flags)\n const commitResult = run(`git commit -m \"${truncated.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n if (!commitResult.success) {\n console.warn(`[project-git] commit failed: ${commitResult.stderr}`);\n return null;\n }\n\n // Get short hash\n const hashResult = run(\"git rev-parse --short HEAD\", { cwd: themePath });\n return hashResult.success ? hashResult.stdout : null;\n}\n\n/**\n * Stage only specific files and commit with a template-scoped message.\n * Used for per-template version history so rollback doesn't affect other templates.\n */\nexport function commitTemplateState(\n themePath: string,\n templateId: string,\n message: string,\n filePaths: string[]\n): string | null {\n if (!isGitAvailable()) return null;\n if (!existsSync(join(themePath, \".git\"))) return null;\n\n // Stage only the specified paths\n for (const fp of filePaths) {\n const fullPath = join(themePath, fp);\n if (existsSync(fullPath)) {\n run(`git add \"${fp}\"`, { cwd: themePath });\n }\n }\n\n // Check if there are staged changes\n const diff = run(\"git diff --cached --quiet\", { cwd: themePath });\n if (diff.success) return null; // nothing staged\n\n // Build prefixed message: [templateId] user message\n const prefix = `[${templateId}] `;\n const maxMsg = 72 - prefix.length;\n const truncated = message.length > maxMsg\n ? message.slice(0, maxMsg - 3) + \"...\"\n : message;\n const fullMessage = prefix + truncated;\n\n const commitResult = run(`git commit -m \"${fullMessage.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n if (!commitResult.success) {\n console.warn(`[project-git] template commit failed: ${commitResult.stderr}`);\n return null;\n }\n\n const hashResult = run(\"git rev-parse --short HEAD\", { cwd: themePath });\n return hashResult.success ? hashResult.stdout : null;\n}\n\n// ---------------------------------------------------------------------------\n// History\n// ---------------------------------------------------------------------------\n\n/**\n * Get commit history (most recent first).\n */\nexport function getHistory(themePath: string, limit: number = 50): GitCommitInfo[] {\n if (!isGitAvailable()) return [];\n if (!existsSync(join(themePath, \".git\"))) return [];\n\n const result = run(\n `git log --pretty=format:\"%h|%H|%s|%at\" -n ${limit}`,\n { cwd: themePath }\n );\n if (!result.success || !result.stdout.trim()) return [];\n\n const commits: GitCommitInfo[] = [];\n for (const line of result.stdout.split(\"\\n\")) {\n const parts = line.split(\"|\");\n if (parts.length < 4) continue;\n const timestamp = parseInt(parts[3], 10) * 1000;\n commits.push({\n hash: parts[0],\n fullHash: parts[1],\n message: parts[2],\n timestamp,\n date: new Date(timestamp).toISOString(),\n });\n }\n return commits;\n}\n\n/**\n * Get commit history filtered to a specific template (by commit message prefix).\n */\nexport function getTemplateHistory(\n themePath: string,\n templateId: string,\n limit: number = 50\n): GitCommitInfo[] {\n if (!isGitAvailable()) return [];\n if (!existsSync(join(themePath, \".git\"))) return [];\n\n const escapedId = templateId.replace(/[[\\]\\\\]/g, \"\\\\$&\");\n const result = run(\n `git log --grep=\"\\\\[${escapedId}\\\\]\" --pretty=format:\"%h|%H|%s|%at\" -n ${limit}`,\n { cwd: themePath }\n );\n if (!result.success || !result.stdout.trim()) return [];\n\n const commits: GitCommitInfo[] = [];\n for (const line of result.stdout.split(\"\\n\")) {\n const parts = line.split(\"|\");\n if (parts.length < 4) continue;\n const timestamp = parseInt(parts[3], 10) * 1000;\n commits.push({\n hash: parts[0],\n fullHash: parts[1],\n message: parts[2],\n timestamp,\n date: new Date(timestamp).toISOString(),\n });\n }\n return commits;\n}\n\n// ---------------------------------------------------------------------------\n// Rollback\n// ---------------------------------------------------------------------------\n\n/**\n * Restore theme files to a specific commit's state.\n * Creates a new commit (\"Rollback to: <original message>\") to keep linear history.\n * Does NOT touch .vibespot/ (gitignored) — chat is preserved.\n */\nexport function rollbackToCommit(\n themePath: string,\n commitHash: string\n): { success: boolean; error?: string } {\n if (!isGitAvailable()) return { success: false, error: \"Git not available\" };\n if (!existsSync(join(themePath, \".git\"))) return { success: false, error: \"Not a git repo\" };\n\n // Verify commit exists\n const verify = run(`git cat-file -t ${commitHash}`, { cwd: themePath });\n if (!verify.success || verify.stdout.trim() !== \"commit\") {\n return { success: false, error: `Commit ${commitHash} not found` };\n }\n\n // Get original commit message\n const msgResult = run(`git log --format=\"%s\" -1 ${commitHash}`, { cwd: themePath });\n const origMessage = msgResult.success ? msgResult.stdout : commitHash;\n\n // Restore all files from that commit\n const checkout = run(`git checkout ${commitHash} -- .`, { cwd: themePath });\n if (!checkout.success) {\n return { success: false, error: `Checkout failed: ${checkout.stderr}` };\n }\n\n // Commit the rollback\n const rollbackMsg = `Rollback to: ${origMessage}`.slice(0, 72);\n run(`git commit -m \"${rollbackMsg.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n\n return { success: true };\n}\n\n/**\n * Restore only specific template files to a commit's state.\n * Other templates' files are left untouched.\n */\nexport function rollbackTemplateToCommit(\n themePath: string,\n templateId: string,\n commitHash: string,\n filePaths: string[]\n): { success: boolean; error?: string } {\n if (!isGitAvailable()) return { success: false, error: \"Git not available\" };\n if (!existsSync(join(themePath, \".git\"))) return { success: false, error: \"Not a git repo\" };\n\n // Verify commit exists\n const verify = run(`git cat-file -t ${commitHash}`, { cwd: themePath });\n if (!verify.success || verify.stdout.trim() !== \"commit\") {\n return { success: false, error: `Commit ${commitHash} not found` };\n }\n\n // Get original commit message\n const msgResult = run(`git log --format=\"%s\" -1 ${commitHash}`, { cwd: themePath });\n const origMessage = msgResult.success ? msgResult.stdout : commitHash;\n\n // Restore only the specified paths from that commit\n let restored = 0;\n for (const fp of filePaths) {\n const checkout = run(`git checkout ${commitHash} -- \"${fp}\"`, { cwd: themePath });\n if (checkout.success) restored++;\n // Skip paths that didn't exist at that commit (git errors silently ignored)\n }\n\n if (restored === 0) {\n return { success: false, error: \"No files could be restored from that commit\" };\n }\n\n // Stage and commit the scoped rollback\n run(\"git add -A\", { cwd: themePath });\n const prefix = `[${templateId}] `;\n const rollbackMsg = `${prefix}Rollback to: ${origMessage}`.slice(0, 72);\n run(`git commit -m \"${rollbackMsg.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n\n return { success: true };\n}\n","/**\n * Lightweight HubL subset renderer for local preview.\n *\n * Supports the constructs that AI-generated HubSpot modules actually use:\n * {{ module.field }} — variable access\n * {{ module.group.child }} — nested access\n * {% if module.field %}...{% endif %} — conditionals (+ {% else %})\n * {% for item in module.list %}...{% endfor %} — loops\n * {{ item.field }} — loop variable access\n *\n * Everything else (require_css, get_asset_url, dnd_area, etc.) is stripped.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface FieldDef {\n name: string;\n type: string;\n default?: unknown;\n children?: FieldDef[];\n occurrence?: { min: number; max: number };\n tab?: string;\n}\n\nexport interface RenderContext {\n module: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a render context from a fields.json array, using each field's default.\n */\nexport function buildContextFromFields(fields: FieldDef[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const field of fields) {\n if (field.type === \"group\" && field.occurrence && Array.isArray(field.default)) {\n // Repeater group — default is an array of objects\n result[field.name] = field.default;\n } else if (field.type === \"group\" && field.children) {\n // Nested group (e.g. styles) — recurse into children\n result[field.name] = buildContextFromFields(field.children);\n } else {\n result[field.name] = field.default ?? \"\";\n }\n }\n\n return result;\n}\n\n/**\n * Render a HubL template string with the given context.\n * Returns plain HTML suitable for browser rendering.\n */\nexport function renderHubL(template: string, context: RenderContext): string {\n let output = template;\n\n // 1. Strip HubSpot-only directives that don't apply in preview\n output = stripDirectives(output);\n\n // 2. Process {% for %} loops (must come before if/expressions)\n output = processForLoops(output, context);\n\n // 3. Process {% if %} / {% else %} / {% endif %} conditionals\n output = processConditionals(output, context);\n\n // 4. Resolve {{ expression }} variable references\n output = resolveExpressions(output, context);\n\n // 5. Clean up any remaining unresolved tags\n output = cleanupRemaining(output);\n\n return output;\n}\n\n/**\n * Assemble a full preview HTML page from rendered modules + CSS/JS.\n */\nexport function assemblePreview(opts: {\n renderedModules: string[];\n sharedCss?: string;\n moduleCssArray: string[];\n sharedJs?: string;\n moduleJsArray: string[];\n}): string {\n const styleBlocks = [\n opts.sharedCss || \"\",\n ...opts.moduleCssArray,\n ]\n .filter(Boolean)\n .map((css) => `<style>${css}</style>`)\n .join(\"\\n\");\n\n const scriptBlocks = [\n opts.sharedJs || \"\",\n ...opts.moduleJsArray,\n ]\n .filter(Boolean)\n .map((js) => `<script>${js}</script>`)\n .join(\"\\n\");\n\n const body = opts.renderedModules.join(\"\\n\");\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n${styleBlocks}\n<style>\nhtml{scroll-behavior:smooth}\n.vsp-img-wrap{position:relative;display:inline-block}\n.vsp-img-badge{position:absolute;top:8px;right:8px;background:rgba(0,0,0,.75);color:#fff;font:500 11px/1 -apple-system,sans-serif;padding:5px 8px;border-radius:4px;pointer-events:none;opacity:.85;white-space:nowrap;z-index:10}\n</style>\n</head>\n<body>\n${body}\n${scriptBlocks}\n<script>\n// Anchor link handler — smooth scroll to module sections\ndocument.addEventListener('click',function(e){\n var a=e.target.closest('a[href^=\"#\"]');\n if(!a)return;\n var id=a.getAttribute('href').slice(1);\n if(!id)return;\n var el=document.getElementById(id);\n if(el){\n e.preventDefault();\n el.scrollIntoView({behavior:'smooth',block:'start'});\n }\n});\n// Placeholder image badges\ndocument.querySelectorAll('img').forEach(function(img){\n var src=img.src||img.getAttribute('src')||'';\n if(src.indexOf('placehold')!==-1){\n var w=document.createElement('span');\n w.className='vsp-img-wrap';\n img.parentNode.insertBefore(w,img);\n w.appendChild(img);\n var b=document.createElement('span');\n b.className='vsp-img-badge';\n b.textContent='Placeholder — replace in HubSpot';\n w.appendChild(b);\n }\n});\n</script>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\n/**\n * Strip HubSpot-specific directives that have no meaning in local preview.\n */\nfunction stripDirectives(tpl: string): string {\n // Remove {% require_css %}, {% require_js %}, {% end_require_css %}, etc.\n tpl = tpl.replace(/\\{%[-\\s]*require_(css|js)\\b.*?%\\}/gs, \"\");\n tpl = tpl.replace(/\\{%[-\\s]*end_require_(css|js)\\s*%\\}/gs, \"\");\n\n // Remove {{ require_css(...) }}, {{ require_js(...) }}\n tpl = tpl.replace(/\\{\\{[-\\s]*require_(css|js)\\(.*?\\)\\s*\\}\\}/gs, \"\");\n\n // Remove {{ get_asset_url(...) }}\n tpl = tpl.replace(/\\{\\{[-\\s]*get_asset_url\\(.*?\\)\\s*\\}\\}/gs, \"\");\n\n // Remove {% dnd_area %}, {% dnd_section %}, {% dnd_column %}, {% dnd_row %} and their end tags\n tpl = tpl.replace(/\\{%[-\\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\\b.*?%\\}/gs, \"\");\n\n // Remove {% module ... %} tags (standalone module includes)\n tpl = tpl.replace(/\\{%[-\\s]*module\\b.*?%\\}/gs, \"\");\n\n // Remove {% extends %}, {% block %}, {% endblock %}, {% set %} — template-level\n tpl = tpl.replace(/\\{%[-\\s]*(extends|block|endblock|set)\\b.*?%\\}/gs, \"\");\n\n // Remove template annotations {# ... #}\n tpl = tpl.replace(/\\{#.*?#\\}/gs, \"\");\n\n // Remove {{ content.* }} page-level variables\n tpl = tpl.replace(/\\{\\{[-\\s]*content\\.\\w+.*?\\}\\}/gs, \"\");\n\n return tpl;\n}\n\n/**\n * Process {% for VAR in PATH %}...{% endfor %} loops.\n * Uses balanced tag matching to handle nested for-loops correctly.\n */\nfunction processForLoops(tpl: string, context: RenderContext): string {\n let result = tpl;\n let safety = 0;\n\n while (safety < 30) {\n safety++;\n const match = findOutermostFor(result);\n if (!match) break;\n\n const { varName, iterExpr, body, start, end } = match;\n const items = resolveIterable(iterExpr, context);\n\n let rendered = \"\";\n if (Array.isArray(items)) {\n rendered = items\n .map((item, index) => {\n const loopContext: RenderContext = {\n ...context,\n [varName]: item,\n loop: { index: index + 1, index0: index, first: index === 0, last: index === items.length - 1, length: items.length },\n };\n\n let out = processForLoops(body, loopContext);\n out = processConditionals(out, loopContext);\n out = resolveExpressions(out, loopContext);\n return out;\n })\n .join(\"\");\n }\n\n result = result.slice(0, start) + rendered + result.slice(end);\n }\n\n return result;\n}\n\n/**\n * Find the first outermost {% for %}...{% endfor %} block with balanced nesting.\n */\nfunction findOutermostFor(tpl: string): { varName: string; iterExpr: string; body: string; start: number; end: number } | null {\n const openTag = /\\{%[-\\s]*for\\s+(\\w+)\\s+in\\s+([\\w.]+(?:\\([^)]*\\))?(?:\\|[\\w(),\"' ]+)*)\\s*-?%\\}/g;\n const forOrEndfor = /\\{%[-\\s]*(for\\s|endfor)\\s*.*?-?%\\}/g;\n\n const firstOpen = openTag.exec(tpl);\n if (!firstOpen) return null;\n\n const varName = firstOpen[1];\n const iterExpr = firstOpen[2];\n const bodyStart = firstOpen.index + firstOpen[0].length;\n\n // Find matching endfor by counting nesting depth\n forOrEndfor.lastIndex = bodyStart;\n let depth = 1;\n let m: RegExpExecArray | null;\n\n while ((m = forOrEndfor.exec(tpl)) !== null) {\n if (m[1].startsWith(\"for\")) {\n depth++;\n } else {\n depth--;\n if (depth === 0) {\n const body = tpl.slice(bodyStart, m.index);\n return { varName, iterExpr, body, start: firstOpen.index, end: m.index + m[0].length };\n }\n }\n }\n\n return null; // Unmatched for-loop\n}\n\n/**\n * Process {% if EXPR %}...{% else %}...{% endif %} conditionals.\n * Supports {% elif %} as well.\n */\nfunction processConditionals(tpl: string, context: RenderContext): string {\n // Process from innermost out\n const ifPattern = /\\{%[-\\s]*if\\s+(.*?)\\s*-?%\\}([\\s\\S]*?)\\{%[-\\s]*endif\\s*-?%\\}/g;\n\n let result = tpl;\n let safety = 0;\n\n while (ifPattern.test(result) && safety < 50) {\n safety++;\n result = result.replace(ifPattern, (_match, condition: string, body: string) => {\n // Split on {% else %} and {% elif %}\n const elseMatch = body.split(/\\{%[-\\s]*else\\s*-?%\\}/);\n const ifBody = elseMatch[0];\n const elseBody = elseMatch[1] || \"\";\n\n // Check for {% elif %} (treat as nested if-else)\n const elifParts = ifBody.split(/\\{%[-\\s]*elif\\s+(.*?)\\s*-?%\\}/);\n\n if (elifParts.length > 1) {\n // Has elif branches\n if (evaluateCondition(condition, context)) {\n return elifParts[0];\n }\n // Check elif branches\n for (let i = 1; i < elifParts.length; i += 2) {\n const elifCondition = elifParts[i];\n const elifBody = elifParts[i + 1] || \"\";\n if (evaluateCondition(elifCondition, context)) {\n return elifBody;\n }\n }\n return elseBody;\n }\n\n if (evaluateCondition(condition, context)) {\n return ifBody;\n }\n return elseBody;\n });\n\n ifPattern.lastIndex = 0;\n }\n\n return result;\n}\n\n/**\n * Resolve all {{ expression }} references in the template.\n */\nfunction resolveExpressions(tpl: string, context: RenderContext): string {\n return tpl.replace(/\\{\\{[-\\s]*(.*?)[-\\s]*\\}\\}/g, (_match, expr: string) => {\n const trimmed = expr.trim();\n\n // Handle filters: {{ value|filter }}\n const filterParts = trimmed.split(\"|\");\n const path = filterParts[0].trim();\n\n let value = resolvePath(context, path);\n\n // Apply basic filters\n for (let i = 1; i < filterParts.length; i++) {\n value = applyFilter(value, filterParts[i].trim());\n }\n\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n });\n}\n\n/**\n * Clean up any remaining HubL tags that weren't handled.\n */\nfunction cleanupRemaining(tpl: string): string {\n // Remove any remaining {% ... %} tags\n tpl = tpl.replace(/\\{%.*?%\\}/gs, \"\");\n // Remove any remaining {{ ... }} that reference unknown paths\n tpl = tpl.replace(/\\{\\{.*?\\}\\}/gs, \"\");\n return tpl;\n}\n\n/**\n * Resolve an iterable expression for {% for %} loops.\n * Handles dotted paths (module.services) and range(start, end) calls.\n */\nfunction resolveIterable(expr: string, context: RenderContext): unknown {\n // Handle range(start, end) — with possible filter on args\n const rangeMatch = expr.match(/^range\\(\\s*(.+?)\\s*,\\s*(.+?)\\s*\\)$/);\n if (rangeMatch) {\n const start = resolveNumericArg(rangeMatch[1], context);\n const end = resolveNumericArg(rangeMatch[2], context);\n const arr: number[] = [];\n for (let i = start; i < end; i++) arr.push(i);\n return arr;\n }\n\n // Handle split('...') filter: \"value|split('\\n')\"\n const splitMatch = expr.match(/^(.+?)\\|split\\(['\"](.+?)['\"]\\)$/);\n if (splitMatch) {\n const val = resolvePath(context, splitMatch[1].trim());\n if (typeof val === \"string\") return val.split(splitMatch[2]);\n return [];\n }\n\n return resolvePath(context, expr);\n}\n\n/**\n * Resolve a numeric argument that may be a literal, a path, or a path|filter.\n */\nfunction resolveNumericArg(arg: string, context: RenderContext): number {\n const trimmed = arg.trim();\n\n // Apply filters (e.g. \"item.rating|int\")\n const filterParts = trimmed.split(\"|\");\n const path = filterParts[0].trim();\n\n // Literal number\n if (!isNaN(Number(path))) return Number(path);\n\n // Path lookup\n let value = resolvePath(context, path);\n for (let i = 1; i < filterParts.length; i++) {\n value = applyFilter(value, filterParts[i].trim());\n }\n return Number(value) || 0;\n}\n\n/**\n * Resolve a dot-path expression against a context object.\n * E.g. \"module.styles.bg_color.color\" → context.module.styles.bg_color.color\n */\nfunction resolvePath(context: RenderContext, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = context;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n\n/**\n * Evaluate a simple condition expression.\n * Supports: path truthiness, \"not path\", \"path == value\", \"path != value\"\n */\nfunction evaluateCondition(expr: string, context: RenderContext): boolean {\n const trimmed = expr.trim();\n\n // Handle \"not\" prefix\n if (trimmed.startsWith(\"not \")) {\n return !evaluateCondition(trimmed.slice(4), context);\n }\n\n // Handle \"and\" / \"or\"\n if (trimmed.includes(\" and \")) {\n return trimmed.split(\" and \").every((part) => evaluateCondition(part, context));\n }\n if (trimmed.includes(\" or \")) {\n return trimmed.split(\" or \").some((part) => evaluateCondition(part, context));\n }\n\n // Handle comparison operators\n const eqMatch = trimmed.match(/^(.+?)\\s*(==|!=|>=|<=|>|<)\\s*(.+)$/);\n if (eqMatch) {\n const left = resolvePath(context, eqMatch[1].trim());\n const operator = eqMatch[2];\n let right: unknown = eqMatch[3].trim();\n\n // Parse right side: string literal, number, or path\n if (\n (typeof right === \"string\" && right.startsWith('\"') && right.endsWith('\"')) ||\n (typeof right === \"string\" && right.startsWith(\"'\") && right.endsWith(\"'\"))\n ) {\n right = (right as string).slice(1, -1);\n } else if (!isNaN(Number(right))) {\n right = Number(right);\n } else {\n right = resolvePath(context, right as string);\n }\n\n switch (operator) {\n case \"==\": return left == right;\n case \"!=\": return left != right;\n case \">\": return Number(left) > Number(right);\n case \"<\": return Number(left) < Number(right);\n case \">=\": return Number(left) >= Number(right);\n case \"<=\": return Number(left) <= Number(right);\n }\n }\n\n // Simple truthiness\n const value = resolvePath(context, trimmed);\n return isTruthy(value);\n}\n\n/**\n * Check HubL-style truthiness (empty strings and 0 are falsy).\n */\nfunction isTruthy(value: unknown): boolean {\n if (value === null || value === undefined) return false;\n if (value === \"\") return false;\n if (value === 0) return false;\n if (value === false) return false;\n if (Array.isArray(value) && value.length === 0) return false;\n return true;\n}\n\n/**\n * Apply a basic HubL filter.\n */\nfunction applyFilter(value: unknown, filter: string): unknown {\n const str = value === null || value === undefined ? \"\" : String(value);\n\n // Handle filters with arguments: truncate(100), default(\"fallback\")\n const argMatch = filter.match(/^(\\w+)\\((.*)\\)$/);\n const filterName = argMatch ? argMatch[1] : filter;\n const filterArg = argMatch ? argMatch[2].replace(/^[\"']|[\"']$/g, \"\") : undefined;\n\n switch (filterName) {\n case \"escape\":\n case \"e\":\n return str.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n case \"lower\":\n return str.toLowerCase();\n case \"upper\":\n return str.toUpperCase();\n case \"capitalize\":\n return str.charAt(0).toUpperCase() + str.slice(1);\n case \"trim\":\n return str.trim();\n case \"truncate\":\n if (filterArg) {\n const len = parseInt(filterArg, 10);\n return str.length > len ? str.slice(0, len) + \"...\" : str;\n }\n return str;\n case \"default\":\n return isTruthy(value) ? value : (filterArg ?? \"\");\n case \"length\":\n if (Array.isArray(value)) return value.length;\n return str.length;\n case \"join\":\n if (Array.isArray(value)) return value.join(filterArg ?? \", \");\n return str;\n case \"int\":\n case \"float\":\n return Number(str) || 0;\n case \"abs\":\n return Math.abs(Number(str));\n case \"round\":\n return Math.round(Number(str));\n default:\n // Unknown filter — pass through\n return value;\n }\n}\n","/**\n * Preview builder — assembles rendered HubL modules into a full HTML page.\n */\n\nimport {\n renderHubL,\n buildContextFromFields,\n assemblePreview,\n type FieldDef,\n} from \"../hubl/renderer.js\";\nimport { getSession, getOrderedModules } from \"./session.js\";\n\n/**\n * Build a full preview HTML page from the current session state.\n * Each module's HubL template is rendered with its fields.json defaults,\n * then assembled with shared CSS/JS into a complete page.\n */\nexport function buildPreviewHtml(): string {\n const session = getSession();\n if (!session) {\n return welcomePreview();\n }\n\n const modules = getOrderedModules();\n if (modules.length === 0) {\n return welcomePreview();\n }\n\n const renderedModules: string[] = [];\n const moduleCssArray: string[] = [];\n const moduleJsArray: string[] = [];\n\n for (const mod of modules) {\n // Skip template-like content that was accidentally stored as a module\n if (mod.moduleHtml.includes(\"dnd_area\") || mod.moduleHtml.includes(\"extends \")) {\n continue;\n }\n\n // Build context from fields.json defaults\n let context: { module: Record<string, unknown> };\n try {\n const fields: FieldDef[] = JSON.parse(mod.fieldsJson);\n context = { module: buildContextFromFields(fields) };\n } catch {\n context = { module: {} };\n }\n\n // Render HubL template with context\n const rendered = renderHubL(mod.moduleHtml, context);\n\n // Wrap each module in a container with id + data attribute for anchor links\n const anchorId = mod.moduleName.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-|-$/g, \"\");\n renderedModules.push(\n `<div class=\"vibespot-module\" id=\"${anchorId}\" data-module=\"${mod.moduleName}\">${rendered}</div>`\n );\n\n if (mod.moduleCss) moduleCssArray.push(mod.moduleCss);\n if (mod.moduleJs) moduleJsArray.push(mod.moduleJs);\n }\n\n return assemblePreview({\n renderedModules,\n sharedCss: session.sharedCss,\n moduleCssArray,\n sharedJs: session.sharedJs,\n moduleJsArray,\n });\n}\n\n/**\n * Static welcome screen — shown before first generation.\n */\nfunction welcomePreview(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n background: #0f0f14;\n color: #888;\n }\n .welcome {\n text-align: center;\n padding: 2rem;\n }\n .welcome__wave {\n font-size: 4rem;\n margin-bottom: 1.2rem;\n opacity: 0.4;\n animation: float 3s ease-in-out infinite;\n }\n @keyframes float {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-6px); }\n }\n .welcome__title {\n font-size: 1.4rem;\n font-weight: 600;\n color: #bbb;\n letter-spacing: 0.5px;\n margin-bottom: 0.4rem;\n }\n .welcome__sub {\n font-size: 1rem;\n color: #666;\n font-weight: 300;\n }\n</style>\n</head>\n<body>\n<div class=\"welcome\">\n <div class=\"welcome__wave\">\\u224B</div>\n <div class=\"welcome__title\">vibeSpot</div>\n <div class=\"welcome__sub\">Build Something Great</div>\n</div>\n</body>\n</html>`;\n}\n\n/**\n * Build a preview HTML page for a single module (used by the dashboard module library).\n */\nexport function buildModulePreviewHtml(moduleName: string): string {\n const session = getSession();\n if (!session) return \"\";\n\n // Find the module across all templates\n let mod: typeof session.modules[0] | undefined;\n for (const tpl of session.templates) {\n mod = tpl.modules.find((m) => m.moduleName === moduleName);\n if (mod) break;\n }\n // Fallback: check flat modules array\n if (!mod) {\n mod = session.modules.find((m) => m.moduleName === moduleName);\n }\n if (!mod) return \"\";\n\n let context: { module: Record<string, unknown> };\n try {\n const fields: FieldDef[] = JSON.parse(mod.fieldsJson);\n context = { module: buildContextFromFields(fields) };\n } catch {\n context = { module: {} };\n }\n\n const rendered = renderHubL(mod.moduleHtml, context);\n\n return assemblePreview({\n renderedModules: [\n `<div class=\"vibespot-module\" data-module=\"${mod.moduleName}\">${rendered}</div>`,\n ],\n sharedCss: session.sharedCss,\n moduleCssArray: mod.moduleCss ? [mod.moduleCss] : [],\n sharedJs: session.sharedJs,\n moduleJsArray: mod.moduleJs ? [mod.moduleJs] : [],\n });\n}\n\n// Note: The generating screen (spinner + rotating messages) is now\n// rendered client-side in preview.js to avoid an extra server round-trip.\n","/**\n * AI handler for vibe coding mode.\n * Supports multiple AI engines: Anthropic API, OpenAI API, Gemini API,\n * Claude Code, Gemini CLI, and Codex CLI.\n */\n\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport { spawn, execSync } from \"node:child_process\";\nimport { getConversionGuide, getDesignGuide, getContentGuide, getHubspotRules, getPageTypeGuide, getHumanifyGuide } from \"../ai/prompts.js\";\nimport { loadConfig, getApiKeyForEngine, type AIEngineType } from \"../utils/config.js\";\nimport {\n getSession,\n addMessage,\n updateModules,\n saveSession,\n getActiveTemplate,\n getModuleLibrary,\n type ChatMessage,\n} from \"./session.js\";\nimport type { ModuleFiles } from \"../ai/engine.js\";\n\n/**\n * Get the active template's page type and brand assets from the session.\n * Used when building the system prompt.\n */\nfunction getPromptContext(): { pageType?: string; brandAssets?: { styleguide?: string; brandvoice?: string; humanify?: boolean } } {\n const session = getSession();\n if (!session) return {};\n const tpl = getActiveTemplate();\n return {\n pageType: tpl?.pageType,\n brandAssets: session.brandAssets,\n };\n}\n\n// ---------------------------------------------------------------------------\n// System prompt for vibe coding mode\n// ---------------------------------------------------------------------------\n\nfunction buildVibeSystemPrompt(\n conversionGuide: string,\n themeName: string,\n editMode: boolean = false,\n pageType?: string,\n brandAssets?: { styleguide?: string; brandvoice?: string; humanify?: boolean }\n): string {\n const core = `You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.\n\n## Your Role\nYou generate native HubSpot CMS modules directly from user descriptions. Every module you create is immediately compatible with HubSpot's drag-and-drop page editor.\n\n## Output Format — CRITICAL\nYou MUST include a \\`\\`\\`vibespot-modules code block with ALL module data as JSON. This is the ONLY way modules get created. A text summary, table, or description of modules does NOT work — you must output the actual JSON.\n\n\\`\\`\\`vibespot-modules\n{\n \"modules\": [\n {\n \"moduleName\": \"Hero\",\n \"fieldsJson\": \"...\",\n \"metaJson\": \"...\",\n \"moduleHtml\": \"...\",\n \"moduleCss\": \"...\",\n \"moduleJs\": null\n }\n ],\n \"sharedCss\": \"...\",\n \"sharedJs\": \"...\"\n}\n\\`\\`\\`\n\nNEVER respond with only a text summary. The vibespot-modules JSON block is mandatory.\n\n## Rules\n- fieldsJson, metaJson must be valid JSON strings\n- moduleHtml uses HubL template syntax ({{ module.field_name }})\n- moduleCss is vanilla CSS (no Tailwind, no Sass)\n- moduleJs is optional vanilla JS (wrapped in IIFE)\n- NEVER use CDN imports (@import url(), <link> to external CDNs like Google Fonts, cdnjs, unpkg, jsdelivr)\n- For fonts, use system font stacks with good fallbacks. Define them as CSS custom properties in sharedCss:\n --font-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --font-mono: 'SF Mono', SFMono-Regular, Consolas, monospace;\n- All assets must be self-contained — no external HTTP requests in CSS or HTML\n- Use \"type\": \"text\" (NEVER \"textarea\" — it's deprecated)\n- NEVER use \"name\": \"name\" (reserved) — use \"item_name\" instead\n- Wrap style fields in a \"styles\" group with \"tab\": \"STYLE\"\n- All CSS classes must use a unique prefix \"${themeName}-\" to avoid theme conflicts\n- Use BEM naming: ${themeName}-module__element--modifier\n- metaJson must include: host_template_types: [\"PAGE\"], is_available_for_new_content: true\n- For repeater groups, use \"occurrence\": { \"min\": 0, \"max\": 100 } and iterate with {% for %}\n- Color fields: type \"color\", default { \"color\": \"#hex\", \"opacity\": 100 }\n- Link fields: type \"link\", default { \"url\": { \"href\": \"#\", \"type\": \"EXTERNAL\" }, \"open_in_new_tab\": false, \"no_follow\": false }\n- Image fields: type \"image\", default { \"src\": \"https://placehold.co/800x600/1a1a2e/ffffff?text=Replace+in+HubSpot\", \"alt\": \"Placeholder image\", \"width\": 800, \"height\": 600 }\n\n## Images & Media\n- All images are managed through HubSpot's file manager — users will replace placeholders after publishing\n- ALWAYS use image fields (type \"image\") so users can swap images in the page editor\n- Use placehold.co URLs as defaults so the preview looks complete (e.g. https://placehold.co/800x600/1a1a2e/ffffff?text=Hero+Image)\n- In module.html, render images with: <img src=\"{{ module.field_name.src }}\" alt=\"{{ module.field_name.alt }}\" width=\"{{ module.field_name.width }}\" height=\"{{ module.field_name.height }}\">\n- For background images in CSS, use inline styles: style=\"background-image: url('{{ module.field_name.src }}')\"\n- Size placeholders appropriately for their context (hero: 1920x800, cards: 600x400, icons: 200x200, avatars: 150x150)\n\n## Navigation & Anchor Links\n- Each module is automatically wrapped with an id derived from its moduleName (lowercase, hyphens for spaces)\n- For navigation/menu modules, use anchor links that match module names: e.g. if a module is named \"Features\", link to href=\"#features\"\n- The id is the moduleName lowercased with non-alphanumeric chars replaced by hyphens (e.g. \"Pricing Cards\" → id=\"pricing-cards\")\n- Always include smooth scrolling behavior in navigation link clicks\n- For nav modules, make menu items editable via a repeater group with \"label\" (text) and \"anchor\" (text) fields\n\n## When modifying existing modules\nWhen the user asks to change something, include ONLY the modules that changed. Keep module names consistent.\nIf the change affects shared CSS or JS, include those too.`;\n\n // Page type context (included in both edit and full mode)\n const pageTypeSection = pageType ? getPageTypeGuide(pageType) : \"\";\n const pageTypePrompt = pageTypeSection ? `\\n\\n## Page Type Context\\n${pageTypeSection}` : \"\";\n\n // Brand assets (only in full mode to keep edits lean)\n let brandPrompt = \"\";\n if (!editMode) {\n if (brandAssets?.styleguide) {\n brandPrompt += `\\n\\n## Brand Style Guide\\n${brandAssets.styleguide}`;\n }\n if (brandAssets?.brandvoice) {\n brandPrompt += `\\n\\n## Brand Voice\\n${brandAssets.brandvoice}`;\n }\n // Humanify defaults to ON (even when brandAssets is undefined)\n if (brandAssets?.humanify !== false) {\n const humanifyGuide = getHumanifyGuide();\n if (humanifyGuide) {\n brandPrompt += `\\n\\n## Anti-AI Copy Rules (Humanify)\\n${humanifyGuide}`;\n }\n }\n }\n\n // For follow-up edits (modules already exist), skip the heavy guides\n if (editMode) {\n return core + pageTypePrompt + `\n\n## HubSpot CMS Rules\n${getHubspotRules()}`;\n }\n\n // Full prompt for initial generation\n return core + pageTypePrompt + brandPrompt + `\n\n## Design Quality\n- Use modern, clean design with proper spacing and typography\n- Include responsive CSS (mobile breakpoint at 767px)\n- Add scroll animation classes where appropriate\n- Use CSS custom properties for the design system\n- Make content editable through fields.json (headlines, text, colors, images, links)\n\n## Scroll Animation CSS Fallback (IMPORTANT)\nWhen using scroll-animate classes (opacity: 0 → visible), you MUST include a CSS-only fallback animation in sharedCss that auto-reveals elements after a delay. This ensures content is visible even if the JS file fails to load:\n\\`\\`\\`css\n@keyframes scroll-animate-fallback {\n to { opacity: 1; transform: none; }\n}\n.scroll-animate {\n animation: scroll-animate-fallback 0.1s 3s forwards;\n}\n.scroll-animate.visible {\n animation: none;\n}\n\\`\\`\\`\nThis makes elements appear after 3 seconds if JS never adds the .visible class. Once JS runs normally and adds .visible, the animation is cancelled.\n\n## Design Guide\n${getDesignGuide()}\n\n## Content & Copywriting Guide\n${getContentGuide()}\n\n## HubSpot CMS Rules\n${getHubspotRules()}\n\n## Conversion Guide Reference\n${conversionGuide}`;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Stream an AI response for a chat message.\n * Calls onChunk with text fragments as they arrive.\n * After the full response, parses module JSON blocks and updates the session.\n */\nexport async function handleGenerateStream(\n userMessage: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void\n): Promise<void> {\n const session = getSession();\n if (!session) throw new Error(\"No active session\");\n\n const capturedSessionId = session.id;\n generatingSessionId = capturedSessionId;\n\n try {\n const config = loadConfig();\n const engine = config.aiEngine || detectDefaultEngine();\n\n switch (engine) {\n case \"anthropic-api\":\n case \"api\": {\n const apiKey = getApiKeyForEngine(\"anthropic-api\", config);\n if (!apiKey) throw new Error(\"Anthropic API key not configured. Open Settings to add one.\");\n await streamWithAnthropicAPI(userMessage, apiKey, session.themeName,\n config.anthropicApiModel || \"claude-sonnet-4-6\", onChunk, onStatus);\n break;\n }\n case \"openai-api\": {\n const apiKey = getApiKeyForEngine(\"openai-api\", config);\n if (!apiKey) throw new Error(\"OpenAI API key not configured. Open Settings to add one.\");\n await streamWithOpenAIAPI(userMessage, apiKey, session.themeName,\n config.openaiApiModel || \"gpt-4o\", onChunk, onStatus);\n break;\n }\n case \"gemini-api\": {\n const apiKey = getApiKeyForEngine(\"gemini-api\", config);\n if (!apiKey) throw new Error(\"Gemini API key not configured. Open Settings to add one.\");\n await streamWithGeminiAPI(userMessage, apiKey, session.themeName, onChunk, onStatus);\n break;\n }\n case \"claude-code\":\n await generateWithClaudeCode(userMessage, session.themeName, onChunk, onStatus);\n break;\n case \"gemini-cli\":\n await generateWithCLI(\"gemini\", userMessage, session.themeName, onChunk, onStatus);\n break;\n case \"codex-cli\":\n await generateWithCLI(\"codex\", userMessage, session.themeName, onChunk, onStatus);\n break;\n default:\n throw new Error(`Unknown AI engine: ${engine}. Open Settings to configure one.`);\n }\n } finally {\n generatingSessionId = null;\n parseWarningCallback = null;\n }\n}\n\n/**\n * Detect the best available engine when none is configured.\n */\nfunction detectDefaultEngine(): AIEngineType {\n const config = loadConfig();\n if (config.anthropicApiKey || process.env.ANTHROPIC_API_KEY) return \"anthropic-api\";\n if (config.openaiApiKey || process.env.OPENAI_API_KEY) return \"openai-api\";\n if (config.geminiApiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY) return \"gemini-api\";\n try { execSync(\"claude --version\", { stdio: \"pipe\" }); return \"claude-code\"; } catch {}\n try { execSync(\"gemini --version\", { stdio: \"pipe\" }); return \"gemini-cli\"; } catch {}\n try { execSync(\"codex --version\", { stdio: \"pipe\" }); return \"codex-cli\"; } catch {}\n throw new Error(\"No AI engine available. Open Settings to configure one.\");\n}\n\n/**\n * Non-streaming generation (used by REST API fallback).\n */\nexport async function handleGenerate(userMessage: string): Promise<string> {\n let fullResponse = \"\";\n await handleGenerateStream(userMessage, (chunk) => {\n fullResponse += chunk;\n });\n return fullResponse;\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction buildStateContext(): string {\n const session = getSession()!;\n let stateContext = \"\";\n if (session.modules.length > 0) {\n stateContext = \"\\n\\n## Current Module State\\n\";\n for (const mod of session.modules) {\n stateContext += `\\n### ${mod.moduleName}.module\\n`;\n stateContext += `**fields.json:**\\n\\`\\`\\`json\\n${mod.fieldsJson}\\n\\`\\`\\`\\n`;\n stateContext += `**module.html:**\\n\\`\\`\\`html\\n${mod.moduleHtml}\\n\\`\\`\\`\\n`;\n stateContext += `**module.css:**\\n\\`\\`\\`css\\n${mod.moduleCss}\\n\\`\\`\\`\\n`;\n if (mod.moduleJs) {\n stateContext += `**module.js:**\\n\\`\\`\\`js\\n${mod.moduleJs}\\n\\`\\`\\`\\n`;\n }\n }\n if (session.sharedCss) {\n stateContext += `\\n### Shared CSS\\n\\`\\`\\`css\\n${session.sharedCss}\\n\\`\\`\\`\\n`;\n }\n if (session.sharedJs) {\n stateContext += `\\n### Shared JS\\n\\`\\`\\`js\\n${session.sharedJs}\\n\\`\\`\\`\\n`;\n }\n }\n\n // Add module library context (modules from other templates the user can reuse)\n const library = getModuleLibrary();\n const currentModuleNames = new Set(session.modules.map((m) => m.moduleName));\n const otherModules = library.filter((e) => !currentModuleNames.has(e.module.moduleName));\n if (otherModules.length > 0) {\n stateContext += \"\\n\\n## Available modules in this theme (reusable)\\n\";\n for (const entry of otherModules) {\n stateContext += `- ${entry.module.moduleName} (used in: ${entry.usedIn.join(\", \")})\\n`;\n }\n stateContext += \"\\nThe user can ask to reuse any of these modules by name.\\n\";\n }\n\n return stateContext;\n}\n\nfunction buildMessagesWithContext(userMessage: string): Array<{ role: \"user\" | \"assistant\"; content: string }> {\n const session = getSession()!;\n const messages: Array<{ role: \"user\" | \"assistant\"; content: string }> =\n session.messages.slice(-20).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const stateContext = buildStateContext();\n const userContent = stateContext\n ? `${userMessage}\\n\\n---\\n${stateContext}`\n : userMessage;\n\n messages.push({ role: \"user\", content: userContent });\n return messages;\n}\n\n/** Callback for parse warnings — set by the WebSocket handler. */\nlet parseWarningCallback: ((warning: string) => void) | null = null;\n\nexport function setParseWarningCallback(cb: ((warning: string) => void) | null): void {\n parseWarningCallback = cb;\n}\n\nfunction finishResponse(fullResponse: string): void {\n if (generatingSessionId) {\n const current = getSession();\n if (!current || current.id !== generatingSessionId) {\n console.warn(\"[ai-handler] Session changed during generation — discarding AI output\");\n return;\n }\n }\n addMessage(\"assistant\", fullResponse);\n parseAndApplyModules(fullResponse);\n saveSession();\n}\n\n// ---------------------------------------------------------------------------\n// Generation lock — prevents session switching while AI is generating\n// ---------------------------------------------------------------------------\n\nlet generatingSessionId: string | null = null;\n\nexport function isGenerating(): boolean {\n return generatingSessionId !== null;\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic Streaming API\n// ---------------------------------------------------------------------------\n\nconst RATE_LIMIT_DELAYS = [10, 20, 40, 60, 120]; // seconds\n\nasync function streamWithAnthropicAPI(\n userMessage: string,\n apiKey: string,\n themeName: string,\n model: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void\n): Promise<void> {\n const client = new Anthropic({ apiKey });\n const conversionGuide = getConversionGuide();\n const session = getSession()!;\n const editMode = session.modules.length > 0;\n const messages = buildMessagesWithContext(userMessage);\n const systemPrompt = buildVibeSystemPrompt(conversionGuide, themeName, editMode, getPromptContext().pageType, getPromptContext().brandAssets);\n\n for (let attempt = 0; ; attempt++) {\n try {\n let fullResponse = \"\";\n\n // Send periodic status updates (like CLI modes) so the user sees a spinner\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n const heartbeat = setInterval(() => {\n statusIndex++;\n sendStatus(CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)]);\n }, 6000);\n\n try {\n const stream = client.messages.stream({\n model,\n max_tokens: 48000,\n system: systemPrompt,\n messages,\n });\n\n for await (const event of stream) {\n if (\n event.type === \"content_block_delta\" &&\n event.delta.type === \"text_delta\"\n ) {\n const text = event.delta.text;\n fullResponse += text;\n onChunk(text);\n }\n }\n } finally {\n clearInterval(heartbeat);\n }\n\n finishResponse(fullResponse);\n return;\n } catch (err: unknown) {\n const status = (err as { status?: number }).status;\n const errType = (err as { error?: { type?: string } }).error?.type;\n const is429 = status === 429\n || errType === \"rate_limit_error\"\n || (err instanceof Error && err.message.includes(\"429\"));\n\n if (!is429 || attempt >= RATE_LIMIT_DELAYS.length) throw err;\n\n const wait = RATE_LIMIT_DELAYS[attempt];\n console.warn(`[ai-handler] Rate limited (429), attempt ${attempt + 1}/${RATE_LIMIT_DELAYS.length} — waiting ${wait}s`);\n if (onStatus) onStatus(`Rate limited by Anthropic API — retrying in ${wait}s...`);\n await new Promise((r) => setTimeout(r, wait * 1000));\n if (onStatus) onStatus(\"Retrying...\");\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI Streaming API (uses native fetch — no npm dependency)\n// ---------------------------------------------------------------------------\n\nasync function streamWithOpenAIAPI(\n userMessage: string,\n apiKey: string,\n themeName: string,\n model: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const editMode = getSession()!.modules.length > 0;\n const messages = buildMessagesWithContext(userMessage);\n\n const response = await fetch(\"https://api.openai.com/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n max_tokens: 48000,\n stream: true,\n messages: [\n { role: \"system\", content: buildVibeSystemPrompt(conversionGuide, themeName, editMode, getPromptContext().pageType, getPromptContext().brandAssets) },\n ...messages,\n ],\n }),\n });\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`OpenAI API error (${response.status}): ${err}`);\n }\n\n // Send periodic status updates so the user sees a spinner\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n const heartbeat = setInterval(() => {\n statusIndex++;\n sendStatus(CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)]);\n }, 6000);\n\n let fullResponse = \"\";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const data = line.slice(6).trim();\n if (data === \"[DONE]\") break;\n\n try {\n const parsed = JSON.parse(data);\n const delta = parsed.choices?.[0]?.delta?.content;\n if (delta) {\n fullResponse += delta;\n onChunk(delta);\n }\n } catch { /* skip malformed SSE lines */ }\n }\n }\n } finally {\n clearInterval(heartbeat);\n }\n\n finishResponse(fullResponse);\n}\n\n// ---------------------------------------------------------------------------\n// Gemini Streaming API (uses native fetch — no npm dependency)\n// ---------------------------------------------------------------------------\n\nasync function streamWithGeminiAPI(\n userMessage: string,\n apiKey: string,\n themeName: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const session = getSession()!;\n const editMode = session.modules.length > 0;\n const stateContext = buildStateContext();\n\n // Build conversation for Gemini format\n const contents: Array<{ role: string; parts: Array<{ text: string }> }> = [];\n\n // Add system instruction as first user message (Gemini uses systemInstruction separately)\n for (const m of session.messages.slice(-20)) {\n contents.push({\n role: m.role === \"assistant\" ? \"model\" : \"user\",\n parts: [{ text: m.content }],\n });\n }\n\n const userContent = stateContext\n ? `${userMessage}\\n\\n---\\n${stateContext}`\n : userMessage;\n contents.push({ role: \"user\", parts: [{ text: userContent }] });\n\n const model = \"gemini-2.5-flash\";\n const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${apiKey}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n systemInstruction: { parts: [{ text: buildVibeSystemPrompt(conversionGuide, themeName, editMode, getPromptContext().pageType, getPromptContext().brandAssets) }] },\n contents,\n generationConfig: { maxOutputTokens: 48000 },\n }),\n });\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`Gemini API error (${response.status}): ${err}`);\n }\n\n // Send periodic status updates so the user sees a spinner\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n const heartbeat = setInterval(() => {\n statusIndex++;\n sendStatus(CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)]);\n }, 6000);\n\n let fullResponse = \"\";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const data = line.slice(6).trim();\n\n try {\n const parsed = JSON.parse(data);\n const text = parsed.candidates?.[0]?.content?.parts?.[0]?.text;\n if (text) {\n fullResponse += text;\n onChunk(text);\n }\n } catch { /* skip malformed SSE lines */ }\n }\n }\n } finally {\n clearInterval(heartbeat);\n }\n\n finishResponse(fullResponse);\n}\n\n// ---------------------------------------------------------------------------\n// CLI subprocess helper — sends prompt via stdin to avoid shell arg limits\n// ---------------------------------------------------------------------------\n\nfunction spawnCLI(\n bin: string,\n args: string[],\n prompt: string,\n onChunk?: (chunk: string) => void\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const env = { ...process.env };\n delete env.CLAUDECODE; // allow nesting when running inside Claude Code\n\n const child = spawn(bin, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n shell: true,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout.on(\"data\", (d: Buffer) => {\n const chunk = d.toString();\n stdout += chunk;\n if (onChunk) onChunk(chunk);\n });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) =>\n reject(new Error(`${bin} failed to start: ${err.message}`))\n );\n\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(\n `${bin} exited with code ${code}.\\n` +\n (stderr ? `Stderr: ${stderr.slice(0, 500)}\\n` : \"\") +\n (stdout ? `Output: ${stdout.slice(0, 500)}` : \"No output\")\n ));\n } else {\n resolve(stdout);\n }\n });\n\n // Send prompt via stdin to avoid shell argument length limits\n child.stdin.on(\"error\", () => {}); // handle EPIPE if child exits early\n child.stdin.write(prompt);\n child.stdin.end();\n\n // 10 min timeout (complex pages need time)\n setTimeout(() => {\n child.kill();\n reject(new Error(`${bin} timed out after 10 minutes`));\n }, 600_000);\n });\n}\n\n// ---------------------------------------------------------------------------\n// CLI status messages (shown while waiting for buffered CLI output)\n// ---------------------------------------------------------------------------\n\nconst CLI_STATUS_MESSAGES = [\n \"Analyzing your request...\",\n \"Reading the conversion guide...\",\n \"Planning module structure...\",\n \"Generating HTML templates...\",\n \"Writing CSS styles...\",\n \"Creating field definitions...\",\n \"Building module metadata...\",\n \"Assembling theme assets...\",\n \"Polishing the output...\",\n \"Almost there — hang tight...\",\n];\n\n// ---------------------------------------------------------------------------\n// Claude Code subprocess\n// ---------------------------------------------------------------------------\n\nasync function generateWithClaudeCode(\n userMessage: string,\n themeName: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const config = loadConfig();\n const editMode = getSession()!.modules.length > 0;\n\n let prompt = buildVibeSystemPrompt(conversionGuide, themeName, editMode, getPromptContext().pageType, getPromptContext().brandAssets);\n prompt += \"\\n\\n## User Request\\n\" + userMessage;\n prompt += buildStateContext();\n\n const args = [\"--print\"];\n if (config.claudeCodeModel) args.push(\"--model\", config.claudeCodeModel);\n\n // Claude --print buffers output until completion, so send periodic\n // status updates so the user knows what's happening\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n\n const heartbeat = setInterval(() => {\n statusIndex++;\n const msg = CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)];\n sendStatus(msg);\n }, 6000);\n\n try {\n const result = await spawnCLI(\"claude\", args, prompt, (chunk) => {\n onChunk(chunk);\n });\n finishResponse(result);\n } finally {\n clearInterval(heartbeat);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Generic CLI subprocess (Gemini CLI, Codex CLI)\n// ---------------------------------------------------------------------------\n\nasync function generateWithCLI(\n cli: \"gemini\" | \"codex\",\n userMessage: string,\n themeName: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const editMode = getSession()!.modules.length > 0;\n\n let prompt = buildVibeSystemPrompt(conversionGuide, themeName, editMode, getPromptContext().pageType, getPromptContext().brandAssets);\n prompt += \"\\n\\n## User Request\\n\" + userMessage;\n prompt += buildStateContext();\n\n let bin: string;\n let args: string[];\n if (cli === \"gemini\") {\n bin = \"gemini\";\n args = [];\n } else {\n bin = \"codex\";\n args = [\"exec\", \"--full-auto\"];\n }\n\n // CLI may buffer output — send status updates so user knows what's happening\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n\n const heartbeat = setInterval(() => {\n statusIndex++;\n const msg = CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)];\n sendStatus(msg);\n }, 6000);\n\n try {\n const result = await spawnCLI(bin, args, prompt, (chunk) => {\n onChunk(chunk);\n });\n finishResponse(result);\n } finally {\n clearInterval(heartbeat);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Module parsing\n// ---------------------------------------------------------------------------\n\n/**\n * Try JSON.parse, and if it fails, attempt to repair common AI JSON issues\n * (unescaped quotes inside string values) and retry.\n */\nfunction tryParseJSON(raw: string): unknown | null {\n try {\n return JSON.parse(raw);\n } catch {\n // Fall through to repair\n }\n\n // Repair: the AI often forgets to escape literal \" chars inside JSON string values\n // (e.g. \">\"{{ some_var }}\"\" where the inner quotes are decorative HTML).\n // Strategy: iteratively find the parse error position, escape the offending quote, retry.\n let repaired = raw;\n for (let attempt = 0; attempt < 20; attempt++) {\n try {\n return JSON.parse(repaired);\n } catch (err) {\n if (!(err instanceof SyntaxError)) return null;\n // Extract position from error message\n const posMatch = /position (\\d+)/.exec(err.message);\n if (!posMatch) return null;\n const pos = parseInt(posMatch[1], 10);\n // Check if there's an unescaped quote nearby that should be escaped\n // Look backwards from pos for the offending \"\n const searchStart = Math.max(0, pos - 5);\n const nearSlice = repaired.slice(searchStart, pos + 1);\n const lastQuote = nearSlice.lastIndexOf('\"');\n if (lastQuote === -1) return null;\n const absPos = searchStart + lastQuote;\n // Don't escape if preceded by backslash (already escaped)\n if (absPos > 0 && repaired[absPos - 1] === \"\\\\\") return null;\n // Escape this quote\n repaired = repaired.slice(0, absPos) + '\\\\\"' + repaired.slice(absPos + 1);\n // Shift won't cause infinite loop because we move past the fixed position\n }\n }\n return null;\n}\n\n/**\n * Attempt to salvage a truncated JSON response by finding complete module objects.\n * Works by progressively trimming from the end until we find valid JSON.\n */\nfunction tryRepairTruncatedJSON(raw: string): Record<string, unknown> | null {\n // Strategy: find the last complete module object by looking for complete \"moduleName\" entries\n // and closing the arrays/objects needed to make valid JSON\n const modulesIdx = raw.indexOf('\"modules\"');\n if (modulesIdx === -1) return null;\n\n const arrayStart = raw.indexOf(\"[\", modulesIdx);\n if (arrayStart === -1) return null;\n\n // Find complete module objects — each ends with a } that closes the module object\n // We look for },{ or },] patterns to find module boundaries\n let lastCompleteModule = -1;\n let braceDepth = 0;\n let inString = false;\n let escaped = false;\n\n for (let i = arrayStart + 1; i < raw.length; i++) {\n const ch = raw[i];\n if (escaped) { escaped = false; continue; }\n if (ch === \"\\\\\") { escaped = true; continue; }\n if (ch === '\"') { inString = !inString; continue; }\n if (inString) continue;\n\n if (ch === \"{\") braceDepth++;\n if (ch === \"}\") {\n braceDepth--;\n if (braceDepth === 0) {\n // Found end of a top-level object inside the modules array\n lastCompleteModule = i;\n }\n }\n }\n\n if (lastCompleteModule === -1) return null;\n\n // Build repaired JSON: everything up to the last complete module, then close the structure\n const upToLastModule = raw.slice(0, lastCompleteModule + 1);\n const repaired = upToLastModule + \"]}\";\n\n // Wrap in the outer object if needed\n const jsonStr = repaired.trimStart().startsWith(\"{\") ? repaired : \"{\" + repaired;\n return tryParseJSON(jsonStr) as Record<string, unknown> | null;\n}\n\n/**\n * Parse vibespot-modules JSON blocks from an AI response and update the session.\n */\nfunction parseAndApplyModules(response: string): void {\n let modulesApplied = false;\n\n // Look for ```vibespot-modules ... ``` blocks\n const blockPattern = /```vibespot-modules\\s*\\n?([\\s\\S]*?)```/g;\n let match;\n\n while ((match = blockPattern.exec(response)) !== null) {\n try {\n console.log(\"[parse] Found vibespot-modules block, length:\", match[1].length);\n console.log(\"[parse] Block start:\", JSON.stringify(match[1].slice(0, 100)));\n console.log(\"[parse] Block end:\", JSON.stringify(match[1].slice(-100)));\n const data = tryParseJSON(match[1]);\n if (!data || typeof data !== \"object\") {\n console.warn(\"[parse] tryParseJSON returned:\", data);\n throw new Error(\"Invalid JSON after repair\");\n }\n\n const obj = data as Record<string, unknown>;\n if (obj.modules && Array.isArray(obj.modules)) {\n const modules: ModuleFiles[] = obj.modules.map((m: Record<string, unknown>) => ({\n moduleName: String(m.moduleName || \"\"),\n fieldsJson: typeof m.fieldsJson === \"string\"\n ? m.fieldsJson\n : JSON.stringify(m.fieldsJson, null, 2),\n metaJson: typeof m.metaJson === \"string\"\n ? m.metaJson\n : JSON.stringify(m.metaJson, null, 2),\n moduleHtml: String(m.moduleHtml || \"\"),\n moduleCss: String(m.moduleCss || \"\"),\n moduleJs: m.moduleJs ? String(m.moduleJs) : undefined,\n }));\n\n updateModules({\n modules,\n sharedCss: obj.sharedCss !== undefined ? String(obj.sharedCss) : undefined,\n sharedJs: obj.sharedJs !== undefined ? String(obj.sharedJs) : undefined,\n });\n modulesApplied = true;\n }\n } catch (err) {\n console.warn(\"[parse] Failed to parse vibespot-modules block:\", err instanceof Error ? err.message : String(err));\n console.warn(\"[parse] Block content (first 200 chars):\", match[1].slice(0, 200));\n }\n }\n\n // Also try to find standalone JSON that looks like module data\n if (!modulesApplied) {\n const jsonPattern = /```(?:json)?\\s*\\n([\\s\\S]*?)```/g;\n while ((match = jsonPattern.exec(response)) !== null) {\n // Only try blocks that look like they contain module data\n if (!match[1].includes('\"modules\"')) continue;\n try {\n const data = tryParseJSON(match[1]);\n if (!data || typeof data !== \"object\") throw new Error(\"Invalid JSON after repair\");\n const obj = data as Record<string, unknown>;\n if (obj.modules && Array.isArray(obj.modules)) {\n const modules: ModuleFiles[] = obj.modules.map((m: Record<string, unknown>) => ({\n moduleName: String(m.moduleName || \"\"),\n fieldsJson: typeof m.fieldsJson === \"string\"\n ? m.fieldsJson\n : JSON.stringify(m.fieldsJson, null, 2),\n metaJson: typeof m.metaJson === \"string\"\n ? m.metaJson\n : JSON.stringify(m.metaJson, null, 2),\n moduleHtml: String(m.moduleHtml || \"\"),\n moduleCss: String(m.moduleCss || \"\"),\n moduleJs: m.moduleJs ? String(m.moduleJs) : undefined,\n }));\n\n updateModules({\n modules,\n sharedCss: obj.sharedCss !== undefined ? String(obj.sharedCss) : undefined,\n sharedJs: obj.sharedJs !== undefined ? String(obj.sharedJs) : undefined,\n });\n modulesApplied = true;\n }\n } catch (err) {\n console.warn(\"[parse] Failed to parse JSON module block:\", err instanceof Error ? err.message : String(err));\n }\n }\n }\n\n // Handle truncated responses (hit max_tokens — unclosed code fence)\n if (!modulesApplied) {\n const fenceCount = (response.match(/```/g) || []).length;\n if (fenceCount % 2 !== 0 && response.includes('\"modules\"')) {\n console.log(\"[parse] Detected truncated response (odd fence count), attempting salvage...\");\n // Extract content after the last opening fence\n const lastFenceIdx = response.lastIndexOf(\"```\");\n let truncated = response.slice(lastFenceIdx + 3);\n // Strip fence language label (e.g. \"vibespot-modules\\n\" or \"json\\n\")\n truncated = truncated.replace(/^[\\w-]*\\s*\\n?/, \"\");\n // Try to close the truncated JSON by finding complete modules\n const salvaged = tryRepairTruncatedJSON(truncated);\n if (salvaged) {\n const obj = salvaged as Record<string, unknown>;\n if (obj.modules && Array.isArray(obj.modules) && obj.modules.length > 0) {\n console.log(\"[parse] Salvaged\", obj.modules.length, \"modules from truncated response\");\n const modules: ModuleFiles[] = (obj.modules as Record<string, unknown>[]).map((m) => ({\n moduleName: String(m.moduleName || \"\"),\n fieldsJson: typeof m.fieldsJson === \"string\"\n ? m.fieldsJson\n : JSON.stringify(m.fieldsJson, null, 2),\n metaJson: typeof m.metaJson === \"string\"\n ? m.metaJson\n : JSON.stringify(m.metaJson, null, 2),\n moduleHtml: String(m.moduleHtml || \"\"),\n moduleCss: String(m.moduleCss || \"\"),\n moduleJs: m.moduleJs ? String(m.moduleJs) : undefined,\n }));\n updateModules({\n modules,\n sharedCss: obj.sharedCss !== undefined ? String(obj.sharedCss) : undefined,\n sharedJs: obj.sharedJs !== undefined ? String(obj.sharedJs) : undefined,\n });\n modulesApplied = true;\n if (parseWarningCallback) {\n parseWarningCallback(\"Response was truncated — some modules may be incomplete. Try sending your request again for the full set.\");\n }\n }\n }\n }\n }\n\n // Warn user if the response looked like it should contain modules but parsing failed\n if (!modulesApplied) {\n console.log(\"[parse] No modules applied. Response length:\", response.length);\n console.log(\"[parse] Contains 'vibespot-modules':\", response.includes(\"vibespot-modules\"));\n console.log(\"[parse] Contains '\\\"modules\\\"':\", response.includes('\"modules\"'));\n console.log(\"[parse] Fence count:\", (response.match(/```/g) || []).length);\n console.log(\"[parse] Response preview:\", response.slice(0, 500));\n const hasModuleRef = response.includes(\"vibespot-modules\") || response.includes('\"modules\"');\n // Detect when the AI describes modules in prose (e.g. a summary table) without providing JSON\n const describesProse = /\\bmodule|modul/i.test(response) &&\n (/\\bcreated?\\b|\\berstellt\\b|\\bgenerat/i.test(response) || /\\|.*\\|.*\\|/m.test(response));\n\n if (hasModuleRef || describesProse) {\n const msg = hasModuleRef\n ? \"Module changes could not be applied — the AI response contained invalid JSON. Try sending your request again.\"\n : \"The AI described modules but did not include the required structured data. Try sending your request again.\";\n console.warn(\"[parse] \" + msg);\n if (parseWarningCallback) {\n parseWarningCallback(msg);\n }\n }\n }\n}\n","/**\n * Background process manager for long-running CLI operations\n * (tool installation, OAuth flows, etc.)\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\n\nexport interface ProcessJob {\n id: string;\n command: string;\n description: string;\n status: \"running\" | \"completed\" | \"failed\";\n output: string;\n exitCode: number | null;\n startedAt: number;\n completedAt: number | null;\n}\n\nconst jobs = new Map<string, ProcessJob>();\n\nexport function startJob(\n command: string,\n description: string,\n opts?: { cwd?: string; env?: Record<string, string>; timeout?: number }\n): string {\n const id = `job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n\n const job: ProcessJob = {\n id,\n command,\n description,\n status: \"running\",\n output: \"\",\n exitCode: null,\n startedAt: Date.now(),\n completedAt: null,\n };\n\n jobs.set(id, job);\n\n const parts = command.split(\" \");\n const child: ChildProcess = spawn(parts[0], parts.slice(1), {\n cwd: opts?.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, ...opts?.env },\n shell: true,\n });\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n job.output += d.toString();\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n job.output += d.toString();\n });\n\n child.on(\"close\", (code) => {\n job.status = code === 0 ? \"completed\" : \"failed\";\n job.exitCode = code;\n job.completedAt = Date.now();\n });\n\n child.on(\"error\", (err) => {\n job.status = \"failed\";\n job.output += `\\nProcess error: ${err.message}`;\n job.completedAt = Date.now();\n });\n\n // Timeout safety net\n const timeout = opts?.timeout || 300_000;\n setTimeout(() => {\n if (job.status === \"running\") {\n child.kill();\n job.status = \"failed\";\n job.output += \"\\nProcess timed out\";\n job.completedAt = Date.now();\n }\n }, timeout);\n\n return id;\n}\n\nexport function getJob(id: string): ProcessJob | undefined {\n return jobs.get(id);\n}\n\nexport function cleanupOldJobs(): void {\n const cutoff = Date.now() - 30 * 60 * 1000;\n for (const [id, job] of jobs) {\n if (job.completedAt && job.completedAt < cutoff) {\n jobs.delete(id);\n }\n }\n}\n\n// Clean up periodically\nsetInterval(cleanupOldJobs, 10 * 60 * 1000);\n\n// ---------------------------------------------------------------------------\n// Streaming jobs — same as regular jobs but also emit output chunks to listeners\n// ---------------------------------------------------------------------------\n\nexport interface StreamingJob extends ProcessJob {\n listeners: Set<(chunk: string) => void>;\n}\n\nexport function startStreamingJob(\n command: string,\n description: string,\n opts?: { cwd?: string; env?: Record<string, string>; timeout?: number }\n): string {\n const id = `job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n\n const job: StreamingJob = {\n id,\n command,\n description,\n status: \"running\",\n output: \"\",\n exitCode: null,\n startedAt: Date.now(),\n completedAt: null,\n listeners: new Set(),\n };\n\n jobs.set(id, job);\n\n const parts = command.split(\" \");\n const child: ChildProcess = spawn(parts[0], parts.slice(1), {\n cwd: opts?.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, ...opts?.env },\n shell: true,\n });\n\n const emitChunk = (chunk: string) => {\n for (const listener of job.listeners) {\n try { listener(chunk); } catch { /* listener error — ignore */ }\n }\n };\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n const chunk = d.toString();\n job.output += chunk;\n emitChunk(chunk);\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n const chunk = d.toString();\n job.output += chunk;\n emitChunk(chunk);\n });\n\n child.on(\"close\", (code) => {\n job.status = code === 0 ? \"completed\" : \"failed\";\n job.exitCode = code;\n job.completedAt = Date.now();\n });\n\n child.on(\"error\", (err) => {\n job.status = \"failed\";\n job.output += `\\nProcess error: ${err.message}`;\n job.completedAt = Date.now();\n });\n\n // Timeout safety net\n const timeout = opts?.timeout || 300_000;\n setTimeout(() => {\n if (job.status === \"running\") {\n child.kill();\n job.status = \"failed\";\n job.output += \"\\nProcess timed out\";\n job.completedAt = Date.now();\n }\n }, timeout);\n\n return id;\n}\n\nexport function addJobListener(jobId: string, listener: (chunk: string) => void): void {\n const job = jobs.get(jobId);\n if (!job || !(\"listeners\" in job)) return;\n\n const streamingJob = job as StreamingJob;\n\n // Send buffered output first\n if (streamingJob.output) {\n try { listener(streamingJob.output); } catch { /* ignore */ }\n }\n\n streamingJob.listeners.add(listener);\n}\n\nexport function removeJobListener(jobId: string, listener: (chunk: string) => void): void {\n const job = jobs.get(jobId);\n if (!job || !(\"listeners\" in job)) return;\n\n (job as StreamingJob).listeners.delete(listener);\n}\n","import { buildProgram } from \"./cli/program.js\";\n\nconst program = buildProgram();\nprogram.parseAsync(process.argv).catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":["join","homedir","readFileSync","existsSync","join","p","join","join","homedir","existsSync","readFileSync","intro","outro","note","text","confirm","select","spinner","log","intro","note","confirm","spinner","select","text","outro","readdirSync","join","join","readdirSync","intro","text","s","spinner","note","confirm","outro","join","readdirSync","intro","select","join","text","spinner","readdirSync","outro","join","readdirSync","join","basename","readdirSync","statSync","writeFileSync","join","writeFileSync","basename","readdirSync","statSync","join","basename","readdirSync","basename","join","p","readdirSync","spawn","join","readdirSync","statSync","spawn","join","readdirSync","statSync","spawn","join","readdirSync","statSync","spawn","join","readdirSync","statSync","intro","note","spinner","confirm","join","outro","readdirSync","join","basename","join","readdirSync","rmSync","join","readdirSync","rmSync","hex","intro","basename","spinner","join","outro","confirm","execSync","rmSync","basename","intro","note","confirm","execSync","log","basename","rmSync","outro","text","confirm","intro","log","outro","join","existsSync","execSync","chalk","readFileSync","existsSync","readdirSync","rmSync","renameSync","join","extname","basename","homedir","execSync","readFileSync","readdirSync","existsSync","writeFileSync","mkdirSync","rmSync","renameSync","join","dirname","homedir","existsSync","writeFileSync","mkdirSync","join","existsSync","join","mkdirSync","writeFileSync","join","homedir","existsSync","readFileSync","mkdirSync","writeFileSync","readdirSync","f","rmSync","dirname","renameSync","Anthropic","spawn","execSync","execSync","Anthropic","text","spawn","spawn","join","homedir","execSync","existsSync","readdirSync","rmSync","renameSync","basename","jobs","configUpdate","jobId","readFileSync","session","extname","chalk","execSync","join","existsSync","program"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/program.ts","../src/cli/theme.ts","../src/cli/banner.ts","../src/utils/detect.ts","../src/utils/shell.ts","../src/utils/config.ts","../src/utils/fs.ts","../src/hubspot/api.ts","../src/prompts/prompter.ts","../src/wizard/preflight.ts","../src/wizard/source.ts","../src/wizard/theme-setup.ts","../src/hubspot/theme-scaffold.ts","../src/hubspot/fetcher.ts","../src/wizard/conversion.ts","../src/ai/claude-code.ts","../src/ai/prompts.ts","../src/ai/claude-api.ts","../src/ai/gemini-cli.ts","../src/ai/codex-cli.ts","../src/wizard/uploader.ts","../src/server/auto-fix.ts","../src/hubspot/uploader.ts","../src/wizard/next-steps.ts","../src/commands/wizard.ts","../src/commands/init.ts","../src/commands/convert.ts","../src/commands/upload.ts","../src/commands/doctor.ts","../src/commands/vibe.ts","../src/server/server.ts","../src/server/session.ts","../src/server/project-git.ts","../src/hubl/renderer.ts","../src/server/preview.ts","../src/server/ai-handler.ts","../src/server/log.ts","../src/server/ai-parser.ts","../src/server/ai-engines.ts","../src/server/ai-prompts.ts","../src/server/routes/upload-files.ts","../src/server/route-helpers.ts","../src/server/process-manager.ts","../src/server/routes/setup.ts","../src/server/routes/settings.ts","../src/server/routes/themes.ts","../src/server/routes/templates.ts","../src/server/routes/modules.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { wizardCommand } from \"../commands/wizard.js\";\nimport { initCommand } from \"../commands/init.js\";\nimport { convertCommand } from \"../commands/convert.js\";\nimport { uploadCommand } from \"../commands/upload.js\";\nimport { doctorCommand } from \"../commands/doctor.js\";\nimport { vibeCommand } from \"../commands/vibe.js\";\n\nexport function buildProgram(): Command {\n const program = new Command();\n\n program\n .name(\"vibespot\")\n .description(\n \"AI-powered HubSpot CMS landing page builder\"\n )\n .version(\"0.7.1\")\n .action(vibeCommand);\n\n program\n .command(\"wizard\")\n .description(\"Classic CLI wizard — step-by-step conversion flow\")\n .action(wizardCommand);\n\n program\n .command(\"init\")\n .description(\"Check and install required tools\")\n .action(initCommand);\n\n program\n .command(\"convert\")\n .description(\"Convert a React project to HubSpot modules\")\n .action(convertCommand);\n\n program\n .command(\"upload\")\n .description(\"Upload theme to HubSpot\")\n .action(uploadCommand);\n\n program\n .command(\"doctor\")\n .description(\"Diagnose environment issues\")\n .action(doctorCommand);\n\n return program;\n}\n","import chalk from \"chalk\";\n\nexport const palette = {\n accent: \"#FF7A59\",\n accentBright: \"#FF9A7A\",\n success: \"#00BDA5\",\n info: \"#0066FF\",\n warn: \"#FFB020\",\n error: \"#E23D2D\",\n muted: \"#8B8D91\",\n vibes: \"#00BDD6\",\n};\n\nconst noColor = !!process.env.NO_COLOR;\n\nfunction hex(color: string) {\n return noColor ? chalk : chalk.hex(color);\n}\n\nexport const theme = {\n accent: hex(palette.accent),\n accentBright: hex(palette.accentBright),\n success: hex(palette.success),\n info: hex(palette.info),\n warn: hex(palette.warn),\n error: hex(palette.error),\n muted: hex(palette.muted),\n vibes: hex(palette.vibes),\n heading: noColor ? chalk.bold : chalk.bold.hex(palette.accent),\n command: hex(palette.accentBright),\n dim: chalk.dim,\n bold: chalk.bold,\n};\n","import { theme } from \"./theme.js\";\n\nconst VERSION = \"0.7.1\";\n\nexport function printBanner() {\n const v = theme.vibes;\n const o = theme.accent; // HubSpot orange for \"Spot\"\n const m = theme.muted;\n\n // Block-pixel ASCII art: \"vibe ≋ Spot\"\n const lines = [\n `${v(\"██ ██ ██ █████ ▄▄▄▄▄\")}${v(\" ≋≋≋≋≋≋≋≋ \")}${o(\"▄▄▄▄▄ █████ ▄▄▄▄ ▀▀██▀▀\")}`,\n `${v(\"██ ██ ██ ██ ██ ██ \")}${v(\" ≋≋≋≋≋≋ \")}${o(\"██ ██ ██ ██ ██ ██ \")}`,\n `${v(\"██ ██ ██ █████ ████ \")}${v(\" ≋≋≋≋ \")}${o(\"▀▀▀▄ █████ ██ ██ ██ \")}`,\n `${v(\" █▄▄█▀ ██ ██ ██ ██ \")}${v(\" ≋≋≋≋≋≋ \")}${o(\" ██ ██ ██ ██ ██ \")}`,\n `${v(\" ▀▀▀ ██ █████ ▀▀▀▀▀\")}${v(\" ≋≋≋≋≋≋≋≋ \")}${o(\"▀▀▀▀ ██ ▀▀▀▀ ██ \")}`,\n ];\n\n console.log();\n for (const line of lines) {\n console.log(` ${line}`);\n }\n console.log();\n console.log(` ${m(\"AI-powered HubSpot Landing Pages\")} ${theme.dim(`v${VERSION}`)}`);\n console.log();\n}\n","import { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { readFileSync, existsSync, readdirSync } from \"node:fs\";\nimport { run } from \"./shell.js\";\nimport { loadConfig, maskApiKey, isCliToolEnabled, getActiveHubSpotAccount, type AIEngineType, type HubSpotAccountConfig } from \"./config.js\";\nimport { detectDataCenterFromPak } from \"../hubspot/api.js\";\n\nconst whichCmd = process.platform === \"win32\" ? \"where\" : \"which\";\n\nexport interface ToolInfo {\n name: string;\n found: boolean;\n version: string;\n path: string;\n}\n\nexport function detectNode(): ToolInfo {\n const result = run(\"node --version\");\n return {\n name: \"Node.js\",\n found: result.success,\n version: result.stdout.replace(/^v/, \"\"),\n path: run(`${whichCmd} node`).stdout,\n };\n}\n\nexport function detectGit(): ToolInfo {\n const result = run(\"git --version\");\n return {\n name: \"Git\",\n found: result.success,\n version: result.stdout.replace(\"git version \", \"\"),\n path: run(`${whichCmd} git`).stdout,\n };\n}\n\nexport function detectHubSpotCLI(): ToolInfo {\n const result = run(\"hs --version\");\n return {\n name: \"HubSpot CLI\",\n found: result.success,\n version: result.stdout,\n path: run(`${whichCmd} hs`).stdout,\n };\n}\n\nexport interface CLIToolInfo extends ToolInfo {\n authenticated: boolean;\n authDetail: string;\n}\n\nexport function detectClaudeCode(): CLIToolInfo {\n const result = run(\"claude --version\");\n if (!result.success) {\n return { name: \"Claude Code\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Not installed\" };\n }\n\n // Check for Claude Code auth by looking for credentials\n // Claude Code stores OAuth tokens in ~/.claude/ — if the dir exists with credentials, it's authenticated\n const claudeDir = join(homedir(), \".claude\");\n let authenticated = false;\n let authDetail = \"Not signed in — run `claude` to authenticate\";\n\n try {\n if (existsSync(claudeDir)) {\n // If .claude dir exists with auth files, consider it authenticated\n const files = readdirSync(claudeDir);\n const hasAuth = files.some(f =>\n f.includes(\"credentials\") || f.includes(\"auth\") || f.includes(\"token\") || f === \".credentials.json\"\n );\n if (hasAuth || files.length > 2) {\n // Has some config — likely authenticated\n authenticated = true;\n authDetail = \"Authenticated\";\n }\n }\n } catch { /* ignore */ }\n\n return {\n name: \"Claude Code\",\n found: true,\n version: result.stdout,\n path: run(`${whichCmd} claude`).stdout,\n authenticated,\n authDetail,\n };\n}\n\nexport function detectDataCenter(portalId: string): string {\n try {\n const configPath = join(homedir(), \".hscli\", \"config.yml\");\n if (!existsSync(configPath)) return \"na1\";\n\n const config = readFileSync(configPath, \"utf-8\");\n\n // Find the account block matching this portal ID\n const accountIdx = config.indexOf(`accountId: ${portalId}`);\n if (accountIdx === -1) return \"na1\";\n\n // Look for personalAccessKey after this account entry\n const keyIdx = config.indexOf(\"personalAccessKey:\", accountIdx);\n if (keyIdx === -1) return \"na1\";\n\n // Extract the key value (next non-empty trimmed line after the label)\n const keySection = config.slice(keyIdx, keyIdx + 300);\n const keyMatch = keySection.match(/personalAccessKey:[\\s>-]*\\n\\s+(\\S+)/);\n if (!keyMatch) return \"na1\";\n\n // CiRldTE = base64 prefix for \"eu1\" datacenter in HubSpot personal access keys\n if (keyMatch[1].startsWith(\"CiRldTE\")) return \"eu1\";\n } catch {\n // Fall through to default\n }\n return \"na1\";\n}\n\nexport interface HubSpotAccount {\n name: string;\n portalId: string;\n authType: string;\n isDefault: boolean;\n}\n\nexport function detectHubSpotAuth(): {\n authenticated: boolean;\n portalName: string;\n portalId: string;\n accounts: HubSpotAccount[];\n} {\n const result = run(\"hs accounts list\");\n if (!result.success || !result.stdout) {\n return { authenticated: false, portalName: \"\", portalId: \"\", accounts: [] };\n }\n\n // Parse all accounts from the table\n const accounts: HubSpotAccount[] = [];\n let defaultName = \"\";\n let defaultId = \"\";\n\n // Default account line: \"Account: name [standard] (123456)\"\n const defaultMatch = result.stdout.match(/Account:\\s*(.+?)\\s*\\((\\d+)\\)/);\n if (defaultMatch) {\n defaultName = defaultMatch[1].trim();\n defaultId = defaultMatch[2].trim();\n }\n\n // Parse table rows: \"name [standard] 123456 personalaccesskey\"\n const lines = result.stdout.split(\"\\n\");\n for (const line of lines) {\n const tableMatch = line.match(/^\\s*(.+?)\\s+(\\d{5,})\\s+(.*)/);\n if (tableMatch && !/Account ID/i.test(line) && !/^-+$/.test(line.trim()) && !/^Name\\s/i.test(line.trim())) {\n const name = tableMatch[1].trim();\n const portalId = tableMatch[2].trim();\n const authType = tableMatch[3]?.trim() || \"unknown\";\n accounts.push({\n name,\n portalId,\n authType,\n isDefault: portalId === defaultId,\n });\n }\n }\n\n if (defaultMatch) {\n return {\n authenticated: true,\n portalName: defaultName,\n portalId: defaultId,\n accounts,\n };\n }\n\n // Fallback: at least one account in table\n if (accounts.length > 0) {\n return {\n authenticated: true,\n portalName: accounts[0].name,\n portalId: accounts[0].portalId,\n accounts,\n };\n }\n\n return {\n authenticated: result.stdout.length > 0,\n portalName: \"\",\n portalId: \"\",\n accounts: [],\n };\n}\n\nexport function detectGeminiCLI(): CLIToolInfo {\n const result = run(\"gemini --version\");\n if (!result.success) {\n return { name: \"Gemini CLI\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Not installed\" };\n }\n\n // Gemini CLI uses Google Cloud auth — check for application default credentials\n const adcPath = join(homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\");\n const hasAdc = existsSync(adcPath);\n // Also check GOOGLE_API_KEY / GEMINI_API_KEY env vars\n const hasEnvKey = !!(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || process.env.GOOGLE_AI_API_KEY);\n const authenticated = hasAdc || hasEnvKey;\n\n return {\n name: \"Gemini CLI\",\n found: true,\n version: result.stdout,\n path: run(`${whichCmd} gemini`).stdout,\n authenticated,\n authDetail: authenticated ? \"Authenticated\" : \"Run `gemini` to sign in with Google\",\n };\n}\n\nexport function detectCodexCLI(): CLIToolInfo {\n const result = run(\"codex --version\");\n if (!result.success) {\n return { name: \"OpenAI Codex CLI\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Not installed\" };\n }\n\n // Codex CLI supports OAuth (stored in ~/.codex/auth.json) or OPENAI_API_KEY\n const hasKey = !!(process.env.OPENAI_API_KEY);\n let hasOAuth = false;\n try {\n const authFile = join(homedir(), \".codex\", \"auth.json\");\n if (existsSync(authFile)) {\n const content = readFileSync(authFile, \"utf-8\");\n hasOAuth = content.length > 10; // non-empty auth file\n }\n } catch { /* ignore */ }\n\n const authenticated = hasKey || hasOAuth;\n const detail = hasOAuth ? \"Authenticated (OAuth)\" : hasKey ? \"Authenticated (API key)\" : \"Not authenticated\";\n return {\n name: \"OpenAI Codex CLI\",\n found: true,\n version: result.stdout,\n path: run(`${whichCmd} codex`).stdout,\n authenticated,\n authDetail: detail,\n };\n}\n\nexport function detectGitHubCLI(): ToolInfo {\n const result = run(\"gh --version\");\n return {\n name: \"GitHub CLI\",\n found: result.success,\n version: result.stdout.split(\"\\n\")[0]?.replace(\"gh version \", \"\").split(\" \")[0] || \"\",\n path: run(`${whichCmd} gh`).stdout,\n };\n}\n\nexport function detectGitHubAuth(): { authenticated: boolean; username: string } {\n const result = run(\"gh auth status 2>&1\");\n if (!result.success && !result.stdout) {\n return { authenticated: false, username: \"\" };\n }\n // gh auth status outputs to stderr, but our run() captures both\n const output = result.stdout || result.stderr || \"\";\n const match = output.match(/Logged in to github\\.com.*account\\s+(\\S+)/);\n if (match) {\n return { authenticated: true, username: match[1] };\n }\n // Alternate pattern: \"account borismichel\"\n const altMatch = output.match(/account\\s+(\\S+)/);\n if (altMatch && output.includes(\"Logged in\")) {\n return { authenticated: true, username: altMatch[1] };\n }\n return { authenticated: output.includes(\"Logged in\"), username: \"\" };\n}\n\nexport function hasAnthropicKey(): boolean {\n return !!process.env.ANTHROPIC_API_KEY;\n}\n\nexport function nodeVersionOk(version: string): boolean {\n const major = parseInt(version.split(\".\")[0], 10);\n return major >= 18;\n}\n\nexport function hsCliVersionOk(version: string): boolean {\n const major = parseInt(version.split(\".\")[0], 10);\n return !isNaN(major) && major >= 8;\n}\n\n// ---------------------------------------------------------------------------\n// Comprehensive environment status (used by GET /api/settings/status)\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Config-based HubSpot auth (for API mode — no CLI subprocess)\n// ---------------------------------------------------------------------------\n\nexport function detectHubSpotAuthFromConfig(): {\n authenticated: boolean;\n portalName: string;\n portalId: string;\n dataCenter: string;\n accounts: HubSpotAccount[];\n uploadMode: \"api\" | \"cli\";\n} {\n const config = loadConfig();\n const uploadMode = config.hubspotUploadMode || \"api\";\n const configAccounts = config.hubspotAccounts || [];\n\n const accounts: HubSpotAccount[] = configAccounts.map((a) => ({\n name: a.portalName,\n portalId: a.portalId,\n authType: \"personalaccesskey\",\n isDefault: a.portalId === (config.activeHubSpotAccount || configAccounts[0]?.portalId),\n }));\n\n const active = getActiveHubSpotAccount();\n\n return {\n authenticated: !!active,\n portalName: active?.portalName || \"\",\n portalId: active?.portalId || \"\",\n dataCenter: active ? active.dataCenter : \"na1\",\n accounts,\n uploadMode,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Comprehensive environment status (used by GET /api/settings/status)\n// ---------------------------------------------------------------------------\n\nexport interface EnvironmentStatus {\n tools: {\n node: ToolInfo;\n git: ToolInfo;\n hubspot: ToolInfo & { authenticated: boolean; portalName: string; portalId: string; dataCenter: string; accounts: HubSpotAccount[]; uploadMode: \"api\" | \"cli\" };\n github: ToolInfo & { authenticated: boolean; username: string };\n claudeCode: CLIToolInfo;\n geminiCli: CLIToolInfo;\n codexCli: CLIToolInfo;\n };\n apiKeys: {\n anthropic: { configured: boolean; masked: string; source: \"config\" | \"env\" | null };\n openai: { configured: boolean; masked: string; source: \"config\" | \"env\" | null };\n gemini: { configured: boolean; masked: string; source: \"config\" | \"env\" | null };\n };\n activeEngine: AIEngineType | null;\n availableEngines: AIEngineType[];\n enabledCLITools: string[];\n}\n\nconst DISABLED_CLI: CLIToolInfo = { name: \"\", found: false, version: \"\", path: \"\", authenticated: false, authDetail: \"Disabled\" };\n\nexport function detectEnvironment(): EnvironmentStatus {\n const config = loadConfig();\n\n const node = detectNode();\n const git = detectGit();\n\n // HubSpot: API mode uses config, CLI mode uses hs CLI\n const hsUploadMode = config.hubspotUploadMode || \"api\";\n let hsInfo: ToolInfo & { authenticated: boolean; portalName: string; portalId: string; dataCenter: string; accounts: HubSpotAccount[]; uploadMode: \"api\" | \"cli\" };\n\n if (hsUploadMode === \"cli\") {\n const hs = detectHubSpotCLI();\n const hsAuth = hs.found ? detectHubSpotAuth() : { authenticated: false, portalName: \"\", portalId: \"\", accounts: [] as HubSpotAccount[] };\n const dc = hsAuth.portalId ? detectDataCenter(hsAuth.portalId) : \"na1\";\n hsInfo = { ...hs, ...hsAuth, dataCenter: dc, uploadMode: \"cli\" };\n } else {\n // API mode — read from vibespot config, no subprocess\n const apiAuth = detectHubSpotAuthFromConfig();\n hsInfo = {\n name: \"HubSpot API\",\n found: true, // always available (built-in)\n version: \"v3\",\n path: \"\",\n ...apiAuth,\n };\n }\n\n // GitHub CLI — always checked (lightweight)\n const gh = detectGitHubCLI();\n const ghAuth = gh.found ? detectGitHubAuth() : { authenticated: false, username: \"\" };\n\n // AI CLI tools — only check if enabled in config (lazy loading)\n const enabledTools = config.enabledCLITools || [];\n const claude = isCliToolEnabled(\"claude-code\") ? detectClaudeCode() : { ...DISABLED_CLI, name: \"Claude Code\" };\n const gemini = isCliToolEnabled(\"gemini-cli\") ? detectGeminiCLI() : { ...DISABLED_CLI, name: \"Gemini CLI\" };\n const codex = isCliToolEnabled(\"codex-cli\") ? detectCodexCLI() : { ...DISABLED_CLI, name: \"OpenAI Codex CLI\" };\n\n // Determine API key status\n function keyStatus(configKey: string | undefined, ...envVars: string[]): { configured: boolean; masked: string; source: \"config\" | \"env\" | null } {\n if (configKey) return { configured: true, masked: maskApiKey(configKey), source: \"config\" };\n for (const v of envVars) {\n if (process.env[v]) return { configured: true, masked: maskApiKey(process.env[v]!), source: \"env\" };\n }\n return { configured: false, masked: \"\", source: null };\n }\n\n const anthropicKey = keyStatus(config.anthropicApiKey, \"ANTHROPIC_API_KEY\");\n const openaiKey = keyStatus(config.openaiApiKey, \"OPENAI_API_KEY\");\n const geminiKey = keyStatus(config.geminiApiKey, \"GEMINI_API_KEY\", \"GOOGLE_AI_API_KEY\");\n\n // Build available engines — CLI tools must be enabled + authenticated\n const available: AIEngineType[] = [];\n if (claude.found && claude.authenticated) available.push(\"claude-code\");\n if (anthropicKey.configured) available.push(\"anthropic-api\");\n if (openaiKey.configured) available.push(\"openai-api\");\n if (gemini.found && gemini.authenticated) available.push(\"gemini-cli\");\n if (geminiKey.configured) available.push(\"gemini-api\");\n if (codex.found && codex.authenticated) available.push(\"codex-cli\");\n\n return {\n tools: {\n node,\n git,\n hubspot: hsInfo,\n github: { ...gh, ...ghAuth },\n claudeCode: claude,\n geminiCli: gemini,\n codexCli: codex,\n },\n apiKeys: {\n anthropic: anthropicKey,\n openai: openaiKey,\n gemini: geminiKey,\n },\n activeEngine: config.aiEngine || null,\n availableEngines: available,\n enabledCLITools: enabledTools,\n };\n}\n","import { execSync, type ExecSyncOptions } from \"node:child_process\";\n\nexport interface ShellResult {\n stdout: string;\n stderr: string;\n success: boolean;\n}\n\nexport function run(\n command: string,\n options: ExecSyncOptions = {}\n): ShellResult {\n try {\n const stdout = execSync(command, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120_000,\n ...options,\n }).trim();\n return { stdout, stderr: \"\", success: true };\n } catch (err: unknown) {\n const e = err as { stdout?: Buffer | string; stderr?: Buffer | string };\n const stdout = (e.stdout ?? \"\").toString().trim();\n const stderr = (e.stderr ?? \"\").toString().trim();\n return { stdout, stderr, success: false };\n }\n}\n\nexport function runOrThrow(\n command: string,\n options: ExecSyncOptions = {}\n): string {\n return execSync(command, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120_000,\n ...options,\n }).trim();\n}\n\nexport function runPassthrough(\n command: string,\n options: ExecSyncOptions = {}\n): boolean {\n try {\n execSync(command, {\n stdio: \"inherit\",\n timeout: 300_000,\n ...options,\n });\n return true;\n } catch {\n return false;\n }\n}\n","import { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { readFile, writeFile, fileExists } from \"./fs.js\";\n\nexport type AIEngineType =\n | \"claude-code\"\n | \"anthropic-api\"\n | \"openai-api\"\n | \"gemini-cli\"\n | \"gemini-api\"\n | \"codex-cli\"\n // Legacy value — migrated to \"anthropic-api\" on load\n | \"api\";\n\nexport interface HubSpotAccountConfig {\n portalId: string;\n portalName: string;\n personalAccessKey: string;\n dataCenter: \"na1\" | \"eu1\";\n addedAt: string;\n}\n\nexport interface VibeSpotConfig {\n aiEngine?: AIEngineType;\n anthropicApiKey?: string;\n openaiApiKey?: string;\n geminiApiKey?: string;\n claudeCodeModel?: string;\n anthropicApiModel?: string;\n openaiApiModel?: string;\n lastThemePath?: string;\n lastSourcePath?: string;\n // HubSpot account management\n hubspotAccounts?: HubSpotAccountConfig[];\n activeHubSpotAccount?: string; // portalId\n hubspotUploadMode?: \"api\" | \"cli\"; // default \"api\"\n // CLI tool toggles — only enabled tools get checked on settings load\n enabledCLITools?: string[];\n}\n\nconst CONFIG_DIR = join(homedir(), \".vibespot\");\nconst CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\n\nexport function loadConfig(): VibeSpotConfig {\n if (!fileExists(CONFIG_PATH)) return {};\n\n try {\n const raw = JSON.parse(readFile(CONFIG_PATH));\n // Migrate legacy \"api\" engine type\n if (raw.aiEngine === \"api\") {\n raw.aiEngine = \"anthropic-api\";\n }\n return raw;\n } catch {\n return {};\n }\n}\n\n/**\n * Get the API key for a given engine, checking config first then env vars.\n */\nexport function getApiKeyForEngine(engine: AIEngineType, config?: VibeSpotConfig): string | undefined {\n const c = config || loadConfig();\n switch (engine) {\n case \"anthropic-api\":\n case \"api\":\n return c.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n case \"openai-api\":\n return c.openaiApiKey || process.env.OPENAI_API_KEY;\n case \"gemini-api\":\n return c.geminiApiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY;\n default:\n return undefined;\n }\n}\n\n/**\n * Mask an API key for display (show first 7 + last 4 chars).\n */\nexport function maskApiKey(key: string): string {\n if (key.length <= 12) return \"***\";\n return key.slice(0, 7) + \"...\" + key.slice(-4);\n}\n\nexport function saveConfig(config: VibeSpotConfig): void {\n const existing = loadConfig();\n const merged = { ...existing, ...config };\n writeFile(CONFIG_PATH, JSON.stringify(merged, null, 2));\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR;\n}\n\n// ---------------------------------------------------------------------------\n// HubSpot account helpers\n// ---------------------------------------------------------------------------\n\nexport function getActiveHubSpotAccount(): HubSpotAccountConfig | null {\n const config = loadConfig();\n if (!config.hubspotAccounts?.length) return null;\n const activeId = config.activeHubSpotAccount;\n if (activeId) {\n const found = config.hubspotAccounts.find((a) => a.portalId === activeId);\n if (found) return found;\n }\n // Fallback to first account\n return config.hubspotAccounts[0] || null;\n}\n\nexport function addHubSpotAccount(\n pak: string,\n portalId: string,\n portalName: string,\n dataCenter: \"na1\" | \"eu1\",\n): void {\n const config = loadConfig();\n const accounts = config.hubspotAccounts || [];\n\n // Replace if same portalId exists\n const idx = accounts.findIndex((a) => a.portalId === portalId);\n const entry: HubSpotAccountConfig = {\n portalId,\n portalName,\n personalAccessKey: pak,\n dataCenter,\n addedAt: new Date().toISOString(),\n };\n\n if (idx >= 0) {\n accounts[idx] = entry;\n } else {\n accounts.push(entry);\n }\n\n saveConfig({\n hubspotAccounts: accounts,\n activeHubSpotAccount: portalId,\n } as VibeSpotConfig);\n}\n\nexport function removeHubSpotAccount(portalId: string): void {\n const config = loadConfig();\n const accounts = (config.hubspotAccounts || []).filter((a) => a.portalId !== portalId);\n const update: Partial<VibeSpotConfig> = { hubspotAccounts: accounts };\n\n // If we removed the active account, switch to the first remaining\n if (config.activeHubSpotAccount === portalId) {\n update.activeHubSpotAccount = accounts[0]?.portalId || undefined;\n }\n\n saveConfig(update as VibeSpotConfig);\n}\n\nexport function setActiveHubSpotAccount(portalId: string): void {\n saveConfig({ activeHubSpotAccount: portalId } as VibeSpotConfig);\n}\n\nexport function getHubSpotPak(): string | null {\n const acct = getActiveHubSpotAccount();\n return acct?.personalAccessKey || null;\n}\n\n// ---------------------------------------------------------------------------\n// CLI tool toggle helpers\n// ---------------------------------------------------------------------------\n\nexport function isCliToolEnabled(toolId: string): boolean {\n const config = loadConfig();\n return config.enabledCLITools?.includes(toolId) ?? false;\n}\n\nexport function setCliToolEnabled(toolId: string, enabled: boolean): void {\n const config = loadConfig();\n const tools = new Set(config.enabledCLITools || []);\n if (enabled) tools.add(toolId);\n else tools.delete(toolId);\n saveConfig({ enabledCLITools: [...tools] } as VibeSpotConfig);\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport function readFile(path: string): string {\n return readFileSync(path, \"utf-8\");\n}\n\nexport function writeFile(path: string, content: string): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content, \"utf-8\");\n}\n\nexport function fileExists(path: string): boolean {\n return existsSync(path);\n}\n\nexport function ensureDir(path: string): void {\n mkdirSync(path, { recursive: true });\n}\n\nexport function resolveAsset(name: string): string {\n // In built package, assets/ is at the package root\n // During dev, it's relative to the project root\n const paths = [\n join(import.meta.dirname, \"../../assets\", name),\n join(import.meta.dirname, \"../assets\", name),\n join(process.cwd(), \"assets\", name),\n ];\n\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n\n throw new Error(`Asset not found: ${name}`);\n}\n","/**\n * HubSpot CMS Source Code API v3 client.\n * Direct HTTP calls — no HubSpot CLI dependency.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { basename } from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface HubSpotApiError {\n status: number;\n message: string;\n category?: string;\n detail?: string;\n}\n\nexport interface UploadResult {\n success: boolean;\n path: string;\n error?: HubSpotApiError;\n}\n\nexport interface FileMetadata {\n id: string;\n name: string;\n folder: boolean;\n path: string;\n createdAt?: number;\n updatedAt?: number;\n children?: (FileMetadata | string)[];\n}\n\nexport interface AccountInfo {\n portalId: string;\n portalName: string;\n dataCenter: \"na1\" | \"eu1\";\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** HubSpot API base URL — same for all regions. Cloudflare routes by token. */\nconst BASE_URL = \"https://api.hubapi.com\";\nconst MAX_RETRIES = 3;\nconst RETRY_DELAY_MS = 1000;\n/** Refresh access token 5 minutes before expiry. */\nconst TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;\n\n// ---------------------------------------------------------------------------\n// Token exchange — PAKs are exchanged for short-lived access tokens\n// ---------------------------------------------------------------------------\n\ninterface CachedToken {\n accessToken: string;\n expiresAt: number;\n hubId: number;\n hubName: string;\n}\n\nconst tokenCache = new Map<string, CachedToken>();\n\n/** Exchange a PAK for a short-lived OAuth access token via HubSpot's localdevauth endpoint. */\nasync function exchangePakForToken(pak: string): Promise<CachedToken> {\n const cached = tokenCache.get(pak);\n if (cached && cached.expiresAt - Date.now() > TOKEN_REFRESH_BUFFER_MS) {\n return cached;\n }\n\n const resp = await fetch(`${BASE_URL}/localdevauth/v1/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ encodedOAuthRefreshToken: pak }),\n });\n\n if (!resp.ok) {\n const body = await resp.text().catch(() => \"\");\n throw new Error(\n resp.status === 401 || resp.status === 403\n ? \"Invalid or expired Personal Access Key\"\n : `Token exchange failed (${resp.status}): ${body.slice(0, 200)}`,\n );\n }\n\n const data = await resp.json() as Record<string, unknown>;\n const token: CachedToken = {\n accessToken: data.oauthAccessToken as string,\n expiresAt: data.expiresAtMillis as number,\n hubId: data.hubId as number,\n hubName: (data.hubName as string) || \"\",\n };\n\n tokenCache.set(pak, token);\n return token;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function authHeaders(pak: string): Promise<Record<string, string>> {\n const { accessToken } = await exchangePakForToken(pak);\n return {\n Authorization: `Bearer ${accessToken}`,\n };\n}\n\n/** Encode a remote path for use in HubSpot API URLs — encode each segment but keep slashes. */\nfunction encodePath(remotePath: string): string {\n return remotePath.replace(/^\\/+/, \"\").split(\"/\").filter(Boolean).map(encodeURIComponent).join(\"/\");\n}\n\n/** Detect data center from PAK prefix. */\nexport function detectDataCenterFromPak(pak: string): \"na1\" | \"eu1\" {\n // Modern PAK format: pat-eu1-... or pat-na1-...\n if (pak.startsWith(\"pat-eu1-\")) return \"eu1\";\n if (pak.startsWith(\"pat-na1-\")) return \"na1\";\n // Legacy base64 prefix check\n if (pak.startsWith(\"CiRldTE\")) return \"eu1\";\n return \"na1\";\n}\n\n/** Sleep helper for retry backoff. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Parse error response body into HubSpotApiError. */\nasync function parseErrorResponse(resp: Response, fallbackPath?: string): Promise<HubSpotApiError> {\n let message = `HTTP ${resp.status}`;\n let category: string | undefined;\n let detail: string | undefined;\n\n try {\n const body = await resp.json() as Record<string, unknown>;\n if (body.message && typeof body.message === \"string\") message = body.message;\n if (body.category && typeof body.category === \"string\") category = body.category;\n if (body.errors && Array.isArray(body.errors) && body.errors.length > 0) {\n const firstError = body.errors[0] as Record<string, unknown>;\n detail = firstError.message as string || JSON.stringify(firstError);\n }\n } catch {\n try {\n const text = await resp.text();\n if (text) message = text.slice(0, 500);\n } catch { /* ignore */ }\n }\n\n return {\n status: resp.status,\n message: fallbackPath ? `${message} (${fallbackPath})` : message,\n category,\n detail,\n };\n}\n\n/** Make a fetch request with retry logic for rate limits and transient errors. */\nasync function fetchWithRetry(\n url: string,\n options: RequestInit,\n retries = MAX_RETRIES,\n): Promise<Response> {\n for (let attempt = 0; attempt <= retries; attempt++) {\n const resp = await fetch(url, options);\n\n if (resp.status === 429 || (resp.status >= 500 && attempt < retries)) {\n const delay = RETRY_DELAY_MS * Math.pow(2, attempt);\n await sleep(delay);\n continue;\n }\n\n return resp;\n }\n\n // Should never reach here, but TypeScript needs it\n return fetch(url, options);\n}\n\n// ---------------------------------------------------------------------------\n// API Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a Personal Access Key by fetching account info.\n * Returns portal ID, name, and data center.\n */\nexport async function validatePak(pak: string): Promise<AccountInfo> {\n // Exchange PAK for access token — this validates the key\n const token = await exchangePakForToken(pak);\n\n // Use the access token to get account details\n const url = `${BASE_URL}/account-info/v3/details`;\n const resp = await fetchWithRetry(url, { headers: await authHeaders(pak) });\n\n if (!resp.ok) {\n const err = await parseErrorResponse(resp);\n throw new Error(`Failed to get account info: ${err.message}`);\n }\n\n const data = await resp.json() as Record<string, unknown>;\n const portalId = String(data.portalId || token.hubId || \"\");\n const portalName = token.hubName || (data.uiDomain as string) || portalId;\n\n return {\n portalId,\n portalName,\n dataCenter: detectDataCenterFromPak(pak),\n };\n}\n\n/**\n * Upload a single file to the HubSpot CMS Design Manager.\n * Uses PUT /cms/v3/source-code/{env}/content/{path} with multipart form-data.\n */\nexport async function uploadFile(\n pak: string,\n remotePath: string,\n localFilePath: string,\n): Promise<UploadResult> {\n const fileContent = readFileSync(localFilePath);\n const fileName = basename(localFilePath);\n\n // Build multipart form data\n const formData = new FormData();\n const blob = new Blob([fileContent]);\n formData.append(\"file\", blob, fileName);\n\n const url = `${BASE_URL}/cms/v3/source-code/draft/content/${encodePath(remotePath)}`;\n\n const resp = await fetchWithRetry(url, {\n method: \"PUT\",\n headers: await authHeaders(pak),\n body: formData,\n });\n\n if (!resp.ok) {\n const error = await parseErrorResponse(resp, remotePath);\n return { success: false, path: remotePath, error };\n }\n\n return { success: true, path: remotePath };\n}\n\n/**\n * Delete a file or directory from the HubSpot CMS Design Manager.\n */\nexport async function deleteFile(pak: string, remotePath: string): Promise<void> {\n const url = `${BASE_URL}/cms/v3/source-code/draft/content/${encodePath(remotePath)}`;\n\n const resp = await fetchWithRetry(url, {\n method: \"DELETE\",\n headers: await authHeaders(pak),\n });\n\n if (!resp.ok && resp.status !== 404) {\n const error = await parseErrorResponse(resp, remotePath);\n throw new Error(`Failed to delete ${remotePath}: ${error.message}`);\n }\n}\n\n/**\n * Download a file from the HubSpot CMS Design Manager.\n */\nexport async function downloadFile(pak: string, remotePath: string): Promise<Buffer> {\n const url = `${BASE_URL}/cms/v3/source-code/draft/content/${encodePath(remotePath)}`;\n\n const resp = await fetchWithRetry(url, {\n method: \"GET\",\n headers: await authHeaders(pak),\n });\n\n if (!resp.ok) {\n const error = await parseErrorResponse(resp, remotePath);\n throw new Error(`Failed to download ${remotePath}: ${error.message}`);\n }\n\n const arrayBuffer = await resp.arrayBuffer();\n return Buffer.from(arrayBuffer);\n}\n\n/**\n * Get metadata for a file or directory in the HubSpot CMS Design Manager.\n * Returns null if the path doesn't exist (404).\n */\nexport async function getMetadata(pak: string, remotePath: string): Promise<FileMetadata | null> {\n const url = `${BASE_URL}/cms/v3/source-code/draft/metadata/${encodePath(remotePath)}`;\n\n const resp = await fetchWithRetry(url, {\n method: \"GET\",\n headers: await authHeaders(pak),\n });\n\n if (resp.status === 404) return null;\n\n if (!resp.ok) {\n const error = await parseErrorResponse(resp, remotePath);\n throw new Error(`Failed to get metadata for ${remotePath}: ${error.message}`);\n }\n\n return (await resp.json()) as FileMetadata;\n}\n\n/**\n * List children of a directory in the HubSpot CMS Design Manager.\n * Returns empty array if the directory doesn't exist.\n */\nexport async function listDirectory(pak: string, remotePath: string): Promise<FileMetadata[]> {\n const meta = await getMetadata(pak, remotePath);\n if (!meta) return [];\n if (!meta.folder) return [meta];\n return meta.children || [];\n}\n\n/**\n * List root-level folders in the HubSpot CMS Design Manager.\n * Tries multiple API approaches since the metadata endpoint doesn't support root listing.\n */\nexport async function listRootFolders(pak: string): Promise<FileMetadata[]> {\n const headers = await authHeaders(pak);\n\n // Try different URL patterns for root metadata\n const urlVariants = [\n `${BASE_URL}/cms/v3/source-code/draft/metadata`, // no trailing slash\n `${BASE_URL}/cms/v3/source-code/draft/metadata/`, // trailing slash\n `${BASE_URL}/designmanager/v1/portals/content/listing`, // Design Manager API\n ];\n\n for (const url of urlVariants) {\n try {\n const resp = await fetch(url, { method: \"GET\", headers });\n if (resp.ok) {\n const data = await resp.json() as Record<string, unknown>;\n // Could be { children: [...] } or { objects: [...] } or direct array\n const children = (data.children || data.objects || (Array.isArray(data) ? data : null)) as FileMetadata[] | null;\n if (children && children.length > 0) {\n return children.filter((c: FileMetadata) => c.folder);\n }\n }\n } catch { /* try next */ }\n }\n\n return [];\n}\n","import * as p from \"@clack/prompts\";\nimport { theme } from \"../cli/theme.js\";\n\nexport function isCancel(value: unknown): value is symbol {\n return p.isCancel(value);\n}\n\nexport function handleCancel(value: unknown): void {\n if (p.isCancel(value)) {\n p.cancel(theme.muted(\"Operation cancelled.\"));\n process.exit(0);\n }\n}\n\nexport async function intro(title: string): Promise<void> {\n p.intro(theme.heading(title));\n}\n\nexport async function outro(message: string): Promise<void> {\n p.outro(theme.success(message));\n}\n\nexport async function note(message: string, title?: string): Promise<void> {\n p.note(message, title ? theme.heading(title) : undefined);\n}\n\nexport async function text(opts: {\n message: string;\n placeholder?: string;\n defaultValue?: string;\n validate?: (value: string) => string | undefined;\n}): Promise<string> {\n const result = await p.text({\n message: theme.accent(opts.message),\n placeholder: opts.placeholder,\n defaultValue: opts.defaultValue,\n validate: opts.validate,\n });\n handleCancel(result);\n return result as string;\n}\n\nexport async function confirm(opts: {\n message: string;\n initialValue?: boolean;\n}): Promise<boolean> {\n const result = await p.confirm({\n message: theme.accent(opts.message),\n initialValue: opts.initialValue ?? true,\n });\n handleCancel(result);\n return result as boolean;\n}\n\nexport async function select<T extends string>(opts: {\n message: string;\n options: { value: T; label: string; hint?: string }[];\n}): Promise<T> {\n const result = await p.select({\n message: theme.accent(opts.message),\n options: opts.options,\n });\n handleCancel(result);\n return result as T;\n}\n\nexport async function spinner(): Promise<{\n start: (msg: string) => void;\n stop: (msg: string) => void;\n message: (msg: string) => void;\n}> {\n const s = p.spinner();\n return {\n start: (msg: string) => s.start(theme.muted(msg)),\n stop: (msg: string) => s.stop(theme.success(msg)),\n message: (msg: string) => s.message(theme.muted(msg)),\n };\n}\n\nexport function log(message: string): void {\n p.log.info(message);\n}\n\nexport function logSuccess(message: string): void {\n p.log.success(theme.success(message));\n}\n\nexport function logWarn(message: string): void {\n p.log.warn(theme.warn(message));\n}\n\nexport function logError(message: string): void {\n p.log.error(theme.error(message));\n}\n\nexport function logStep(message: string): void {\n p.log.step(theme.accent(message));\n}\n","import {\n detectNode,\n detectGit,\n detectHubSpotCLI,\n detectClaudeCode,\n detectGeminiCLI,\n detectCodexCLI,\n detectHubSpotAuth,\n hasAnthropicKey,\n nodeVersionOk,\n} from \"../utils/detect.js\";\nimport { run, runPassthrough } from \"../utils/shell.js\";\nimport { saveConfig, loadConfig, getHubSpotPak, getActiveHubSpotAccount, addHubSpotAccount, type AIEngineType } from \"../utils/config.js\";\nimport { validatePak } from \"../hubspot/api.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport interface PreflightResult {\n aiEngine: AIEngineType;\n model?: string;\n portalId: string;\n portalName: string;\n}\n\nexport async function runPreflight(): Promise<PreflightResult> {\n await ui.intro(\"Checking your environment\");\n\n // Node.js\n const node = detectNode();\n if (!node.found) {\n ui.logError(\"Node.js not found. Install it from https://nodejs.org\");\n process.exit(1);\n }\n if (!nodeVersionOk(node.version)) {\n ui.logError(\n `Node.js ${node.version} is too old. Version 18+ required. Update at https://nodejs.org`\n );\n process.exit(1);\n }\n ui.logSuccess(`Node.js v${node.version}`);\n\n // Git\n const git = detectGit();\n if (!git.found) {\n ui.logError(\"Git not found. Install it from https://git-scm.com\");\n process.exit(1);\n }\n ui.logSuccess(`Git ${git.version}`);\n\n // HubSpot connection\n const config = loadConfig();\n const useApi = config.hubspotUploadMode !== \"cli\";\n let portalId = \"\";\n let portalName = \"\";\n\n if (useApi) {\n // API mode — check for PAK in config\n let pak = getHubSpotPak();\n const acct = getActiveHubSpotAccount();\n\n if (!pak) {\n ui.logWarn(\"No HubSpot account connected\");\n await ui.note(\n \"You need a Personal Access Key to deploy themes.\\n\" +\n \"Create one at: https://app.hubspot.com/l/personal-access-key\\n\" +\n \"Make sure the Content scope is enabled.\",\n \"HubSpot connection required\"\n );\n\n const key = await ui.text({\n message: \"Paste your Personal Access Key:\",\n placeholder: \"pat-na1-...\",\n validate: (v) => v.trim() ? undefined : \"Key is required\",\n });\n\n const s = await ui.spinner();\n s.start(\"Validating key...\");\n try {\n const info = await validatePak(key);\n addHubSpotAccount(key, info.portalId, info.portalName, info.dataCenter);\n pak = key;\n portalId = info.portalId;\n portalName = info.portalName;\n s.stop(`Connected to ${info.portalName} (${info.portalId})`);\n } catch (err) {\n s.stop(\"Validation failed\");\n ui.logError(`Invalid key: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n } else {\n portalId = acct?.portalId || \"\";\n portalName = acct?.portalName || \"\";\n ui.logSuccess(\n `HubSpot${portalName ? `: ${portalName}` : \"\"}${portalId ? ` (${portalId})` : \"\"} — API mode`\n );\n }\n } else {\n // CLI mode — require hs CLI\n let hs = detectHubSpotCLI();\n if (!hs.found) {\n ui.logWarn(\"HubSpot CLI not found\");\n const install = await ui.confirm({ message: \"Install HubSpot CLI globally?\" });\n if (!install) {\n ui.logError(\"HubSpot CLI is required in CLI mode. Install: npm install -g @hubspot/cli\");\n process.exit(1);\n }\n const s = await ui.spinner();\n s.start(\"Installing HubSpot CLI...\");\n const result = run(\"npm install -g @hubspot/cli\");\n if (!result.success) {\n s.stop(\"Failed\");\n ui.logError(\"Try: npm install -g @hubspot/cli\");\n process.exit(1);\n }\n hs = detectHubSpotCLI();\n s.stop(`HubSpot CLI v${hs.version} installed`);\n } else {\n ui.logSuccess(`HubSpot CLI v${hs.version}`);\n }\n\n let auth = detectHubSpotAuth();\n if (!auth.authenticated) {\n ui.logWarn(\"HubSpot not authenticated\");\n const doAuth = await ui.confirm({ message: \"Run `hs init` now?\" });\n if (!doAuth) {\n ui.logError(\"Run `hs init` manually.\");\n process.exit(1);\n }\n const s = await ui.spinner();\n s.start(\"Waiting for HubSpot authentication...\");\n const authOk = runPassthrough(\"hs init\");\n if (!authOk) {\n s.stop(\"Authentication failed\");\n process.exit(1);\n }\n auth = detectHubSpotAuth();\n s.stop(`Connected to portal${auth.portalName ? `: ${auth.portalName}` : \"\"} (ID: ${auth.portalId})`);\n } else {\n ui.logSuccess(\n `HubSpot portal${auth.portalName ? `: ${auth.portalName}` : \"\"} (ID: ${auth.portalId})`\n );\n }\n portalId = auth.portalId;\n portalName = auth.portalName;\n }\n\n // AI Engine selection\n const claude = detectClaudeCode();\n const gemini = detectGeminiCLI();\n const codex = detectCodexCLI();\n const hasKey = hasAnthropicKey();\n\n const engineLabels: Record<AIEngineType, string> = {\n \"claude-code\": \"Claude Code\",\n \"api\": \"Anthropic API\",\n \"anthropic-api\": \"Anthropic API\",\n \"openai-api\": \"OpenAI API\",\n \"gemini-api\": \"Gemini API\",\n \"gemini-cli\": \"Gemini CLI\",\n \"codex-cli\": \"OpenAI Codex\",\n };\n\n let aiEngine: AIEngineType;\n const lastUsed = config.aiEngine;\n\n // Always build list of available engines\n const available: { value: AIEngineType; label: string; hint: string }[] = [];\n\n if (claude.found) {\n available.push({\n value: \"claude-code\",\n label: \"Claude Code\",\n hint: lastUsed === \"claude-code\"\n ? \"last used — recommended\"\n : \"uses your existing Claude subscription — recommended\",\n });\n }\n if (gemini.found) {\n available.push({\n value: \"gemini-cli\",\n label: \"Gemini CLI\",\n hint: lastUsed === \"gemini-cli\"\n ? \"last used\"\n : \"uses your existing Gemini setup\",\n });\n }\n if (codex.found) {\n available.push({\n value: \"codex-cli\",\n label: \"OpenAI Codex\",\n hint: lastUsed === \"codex-cli\"\n ? \"last used\"\n : \"uses your existing OpenAI setup\",\n });\n }\n if (hasKey) {\n available.push({\n value: \"api\",\n label: \"Anthropic API\",\n hint: lastUsed === \"api\"\n ? \"last used\"\n : \"uses your API key\",\n });\n }\n\n // Sort last-used engine to the top\n if (lastUsed) {\n available.sort((a, b) =>\n a.value === lastUsed ? -1 : b.value === lastUsed ? 1 : 0\n );\n }\n\n if (available.length === 1) {\n // Only one option — use it automatically\n aiEngine = available[0].value;\n ui.logSuccess(`AI engine: ${engineLabels[aiEngine]} (auto-detected)`);\n } else if (available.length > 1) {\n // Multiple available — always ask\n aiEngine = await ui.select({\n message: \"Choose your AI engine:\",\n options: available,\n });\n } else {\n // None available — guide the user\n await ui.note(\n \"You need an AI coding assistant to power the conversion.\\n\\n\" +\n `${theme.bold(\"Option 1:\")} Install Claude Code ${theme.muted(\"(recommended)\")}\\n` +\n \" https://claude.ai/code\\n\\n\" +\n `${theme.bold(\"Option 2:\")} Install Gemini CLI\\n` +\n \" https://github.com/google-gemini/gemini-cli\\n\\n\" +\n `${theme.bold(\"Option 3:\")} Install OpenAI Codex\\n` +\n \" https://github.com/openai/codex\\n\\n\" +\n `${theme.bold(\"Option 4:\")} Set an Anthropic API key\\n` +\n \" export ANTHROPIC_API_KEY=sk-ant-...\\n\" +\n \" (get one at https://console.anthropic.com)\",\n \"AI engine required\"\n );\n\n aiEngine = await ui.select({\n message: \"Which will you set up?\",\n options: [\n {\n value: \"claude-code\" as const,\n label: \"Claude Code\",\n hint: \"I'll install it now\",\n },\n {\n value: \"gemini-cli\" as const,\n label: \"Gemini CLI\",\n hint: \"I'll install it now\",\n },\n {\n value: \"codex-cli\" as const,\n label: \"OpenAI Codex\",\n hint: \"I'll install it now\",\n },\n {\n value: \"api\" as const,\n label: \"Anthropic API\",\n hint: \"I'll enter my key\",\n },\n ],\n });\n\n if (aiEngine === \"api\") {\n const key = await ui.text({\n message: \"Enter your Anthropic API key:\",\n placeholder: \"sk-ant-api03-...\",\n validate: (v) =>\n v.startsWith(\"sk-ant-\") ? undefined : \"Key should start with sk-ant-\",\n });\n process.env.ANTHROPIC_API_KEY = key;\n saveConfig({ anthropicApiKey: key });\n }\n }\n\n // Model selection for Claude Code\n let model: string | undefined;\n if (aiEngine === \"claude-code\") {\n model = await ui.select({\n message: \"Which model?\",\n options: [\n { value: \"sonnet\", label: \"Sonnet\", hint: \"fast, recommended\" },\n { value: \"opus\", label: \"Opus\", hint: \"most capable\" },\n { value: \"haiku\", label: \"Haiku\", hint: \"fastest, cheapest\" },\n ],\n });\n }\n\n saveConfig({ aiEngine });\n\n await ui.outro(\"Environment ready!\");\n\n return {\n aiEngine,\n model,\n portalId,\n portalName,\n };\n}\n","import { readdirSync, statSync } from \"node:fs\";\nimport { join, basename, extname } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport interface ComponentInfo {\n name: string;\n path: string;\n description: string;\n}\n\nexport interface SourceAnalysis {\n sourceDir: string;\n wasCloned: boolean;\n components: ComponentInfo[];\n hasTailwind: boolean;\n cssVarCount: number;\n fonts: string[];\n interactions: string[];\n}\n\nfunction findComponents(dir: string): ComponentInfo[] {\n const components: ComponentInfo[] = [];\n\n // Common locations for landing page components\n const searchDirs = [\n join(dir, \"src/components/landing\"),\n join(dir, \"src/components/sections\"),\n join(dir, \"src/components\"),\n join(dir, \"src/pages\"),\n join(dir, \"app/components\"),\n join(dir, \"components\"),\n ];\n\n for (const searchDir of searchDirs) {\n if (!fileExists(searchDir)) continue;\n\n try {\n const files = readdirSync(searchDir);\n for (const file of files) {\n const filePath = join(searchDir, file);\n const stat = statSync(filePath);\n if (!stat.isFile()) continue;\n\n const ext = extname(file);\n if (![\".tsx\", \".jsx\"].includes(ext)) continue;\n\n // Skip utility/UI components\n const name = basename(file, ext);\n if (name.startsWith(\"ui\") || name === \"index\") continue;\n\n // Read the file to extract a description\n const content = readFile(filePath);\n const desc = describeComponent(name, content);\n\n components.push({ name, path: filePath, description: desc });\n }\n } catch {\n // Directory read failed, skip\n }\n }\n\n return components;\n}\n\nfunction describeComponent(name: string, content: string): string {\n const hints: string[] = [];\n\n if (/carousel|slider|swiper|embla/i.test(content)) hints.push(\"carousel\");\n if (/accordion|collapsible|expand/i.test(content)) hints.push(\"accordion\");\n if (/form|submit|input.*email/i.test(content)) hints.push(\"form\");\n if (/nav|navigation|menu/i.test(content)) hints.push(\"navigation\");\n if (/hero|headline|tagline/i.test(content)) hints.push(\"hero\");\n if (/footer|copyright/i.test(content)) hints.push(\"footer\");\n if (/testimonial|quote|review/i.test(content)) hints.push(\"testimonials\");\n if (/pricing|plan|tier/i.test(content)) hints.push(\"pricing\");\n if (/faq|question.*answer/i.test(content)) hints.push(\"FAQ\");\n if (/feature|benefit|advantage/i.test(content)) hints.push(\"features\");\n if (/contact|get.in.touch/i.test(content)) hints.push(\"contact\");\n if (/cta|call.to.action/i.test(content)) hints.push(\"CTA\");\n if (/team|member|bio/i.test(content)) hints.push(\"team\");\n\n if (hints.length === 0) {\n // Fallback: infer from component name\n const readable = name\n .replace(/Section$/, \"\")\n .replace(/([A-Z])/g, \" $1\")\n .trim();\n return readable;\n }\n\n return hints.join(\", \");\n}\n\nfunction analyzeCSS(dir: string): { varCount: number; fonts: string[] } {\n const cssFiles = [\n join(dir, \"src/index.css\"),\n join(dir, \"src/globals.css\"),\n join(dir, \"src/app/globals.css\"),\n join(dir, \"app/globals.css\"),\n ];\n\n let varCount = 0;\n const fonts: string[] = [];\n\n for (const cssFile of cssFiles) {\n if (!fileExists(cssFile)) continue;\n\n const content = readFile(cssFile);\n const varMatches = content.match(/--[\\w-]+:/g);\n if (varMatches) varCount += varMatches.length;\n\n const fontMatches = content.match(\n /font-family:\\s*['\"]([^'\"]+)['\"]/g\n );\n if (fontMatches) {\n for (const m of fontMatches) {\n const font = m.match(/['\"]([^'\"]+)['\"]/)?.[1];\n if (font && !fonts.includes(font)) fonts.push(font);\n }\n }\n\n const importMatches = content.match(\n /@import\\s+url\\([^)]*fonts\\.googleapis\\.com[^)]*family=([^&)]+)/g\n );\n if (importMatches) {\n for (const m of importMatches) {\n const font = m.match(/family=([^&)]+)/)?.[1]?.replace(/\\+/g, \" \");\n if (font && !fonts.includes(font)) fonts.push(font);\n }\n }\n }\n\n return { varCount, fonts };\n}\n\nfunction detectInteractions(dir: string): string[] {\n const interactions: string[] = [];\n\n const hooksDir = join(dir, \"src/hooks\");\n if (fileExists(hooksDir)) {\n try {\n const hooks = readdirSync(hooksDir);\n for (const hook of hooks) {\n if (/scroll/i.test(hook)) interactions.push(\"Scroll animations\");\n if (/intersection/i.test(hook)) interactions.push(\"Scroll animations\");\n }\n } catch {\n // Ignore\n }\n }\n\n // Check landing components for patterns\n const componentDir = join(dir, \"src/components/landing\");\n if (fileExists(componentDir)) {\n try {\n const files = readdirSync(componentDir);\n for (const file of files) {\n if (!file.endsWith(\".tsx\") && !file.endsWith(\".jsx\")) continue;\n const content = readFile(join(componentDir, file));\n if (/carousel|embla|swiper/i.test(content) && !interactions.includes(\"Carousel\"))\n interactions.push(\"Carousel\");\n if (/accordion|collapsible/i.test(content) && !interactions.includes(\"Accordion\"))\n interactions.push(\"Accordion\");\n if (/typing|typewriter/i.test(content) && !interactions.includes(\"Typing animation\"))\n interactions.push(\"Typing animation\");\n if (/parallax|requestAnimationFrame/i.test(content) && !interactions.includes(\"Parallax\"))\n interactions.push(\"Parallax\");\n }\n } catch {\n // Ignore\n }\n }\n\n if (interactions.length === 0) {\n interactions.push(\"Scroll animations\");\n }\n\n return interactions;\n}\n\n/**\n * Headless source analysis — called from the vibe server (no interactive prompts).\n * Clones the repo if it's a URL, then analyzes components.\n */\nexport function analyzeSource(input: string): SourceAnalysis {\n let sourceDir: string;\n let wasCloned = false;\n\n if (input.startsWith(\"http\") || input.startsWith(\"git@\")) {\n wasCloned = true;\n const repoName =\n basename(input.replace(/\\.git$/, \"\")) || \"react-source\";\n sourceDir = join(process.cwd(), \"workspace\", repoName);\n\n if (!fileExists(sourceDir)) {\n const result = run(`git clone --depth 1 \"${input}\" \"${sourceDir}\"`);\n if (!result.success) {\n throw new Error(`Failed to clone ${input}: ${result.stderr}`);\n }\n }\n } else {\n sourceDir = input;\n if (!fileExists(sourceDir)) {\n throw new Error(`Directory not found: ${sourceDir}`);\n }\n }\n\n const components = findComponents(sourceDir);\n const hasTailwind =\n fileExists(join(sourceDir, \"tailwind.config.ts\")) ||\n fileExists(join(sourceDir, \"tailwind.config.js\"));\n const { varCount, fonts } = analyzeCSS(sourceDir);\n const interactions = detectInteractions(sourceDir);\n\n return {\n sourceDir,\n wasCloned,\n components,\n hasTailwind,\n cssVarCount: varCount,\n fonts,\n interactions,\n };\n}\n\nexport async function setupSource(): Promise<SourceAnalysis> {\n await ui.intro(\"Source Project\");\n\n const input = await ui.text({\n message: \"GitHub URL or local path to your React project:\",\n placeholder: \"https://github.com/user/my-lovable-page\",\n validate: (v) => {\n if (!v.trim()) return \"Please enter a URL or path\";\n return undefined;\n },\n });\n\n let sourceDir: string;\n let wasCloned = false;\n\n if (input.startsWith(\"http\") || input.startsWith(\"git@\")) {\n wasCloned = true;\n // Clone from GitHub\n const repoName =\n basename(input.replace(/\\.git$/, \"\")) || \"react-source\";\n sourceDir = join(process.cwd(), \"workspace\", repoName);\n\n if (fileExists(sourceDir)) {\n // Already cloned from a previous run — reuse it\n ui.logSuccess(`Using existing clone: ${theme.dim(sourceDir)}`);\n } else {\n const s = await ui.spinner();\n s.start(\"Cloning repository...\");\n\n const result = run(`git clone --depth 1 \"${input}\" \"${sourceDir}\"`);\n if (!result.success) {\n s.stop(\"Clone failed\");\n ui.logError(\n `Failed to clone ${input}. Check the URL and your access permissions.`\n );\n process.exit(1);\n }\n\n s.stop(`Cloned to ${theme.dim(sourceDir)}`);\n }\n } else {\n sourceDir = input;\n if (!fileExists(sourceDir)) {\n ui.logError(`Directory not found: ${sourceDir}`);\n process.exit(1);\n }\n ui.logSuccess(`Using local source: ${theme.dim(sourceDir)}`);\n }\n\n // Analyze\n const s = await ui.spinner();\n s.start(\"Analyzing project structure...\");\n\n const components = findComponents(sourceDir);\n const hasTailwind =\n fileExists(join(sourceDir, \"tailwind.config.ts\")) ||\n fileExists(join(sourceDir, \"tailwind.config.js\"));\n const { varCount, fonts } = analyzeCSS(sourceDir);\n const interactions = detectInteractions(sourceDir);\n\n s.stop(`Found ${components.length} landing page components`);\n\n if (components.length === 0) {\n ui.logWarn(\n \"No components found. Make sure the React source has .tsx/.jsx files in src/components/\"\n );\n process.exit(1);\n }\n\n // Show summary\n const componentList = components\n .map((c, i) => ` ${theme.dim(`${i + 1}.`)} ${theme.bold(c.name)} ${theme.muted(`— ${c.description}`)}`)\n .join(\"\\n\");\n\n const cssInfo = hasTailwind\n ? `Tailwind + custom CSS (${varCount} variables)`\n : `Custom CSS (${varCount} variables)`;\n const fontInfo = fonts.length > 0 ? fonts.join(\", \") : \"System fonts\";\n const jsInfo = interactions.join(\", \");\n\n await ui.note(\n `${componentList}\\n\\n CSS: ${cssInfo}\\n JS: ${jsInfo}\\n Font: ${fontInfo}`,\n `${components.length} components detected`\n );\n\n const ok = await ui.confirm({ message: \"Does this look right?\" });\n if (!ok) {\n ui.logError(\"Please adjust your source directory and try again.\");\n process.exit(0);\n }\n\n await ui.outro(\"Source analyzed!\");\n\n return {\n sourceDir,\n wasCloned,\n components,\n hasTailwind,\n cssVarCount: varCount,\n fonts,\n interactions,\n };\n}\n","import { join } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\nimport { fileExists, readFile, writeFile, ensureDir } from \"../utils/fs.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\nimport { loadConfig, getHubSpotPak } from \"../utils/config.js\";\nimport { createThemeScaffold } from \"../hubspot/theme-scaffold.js\";\nimport { fetchTheme } from \"../hubspot/fetcher.js\";\n\nexport interface ThemeInfo {\n themePath: string;\n themeName: string;\n}\n\nexport async function setupTheme(): Promise<ThemeInfo> {\n await ui.intro(\"HubSpot Theme Setup\");\n\n const choice = await ui.select({\n message: \"Do you have an existing HubSpot theme?\",\n options: [\n {\n value: \"fetch\" as const,\n label: \"Fetch my existing theme from HubSpot\",\n hint: \"downloads your current theme\",\n },\n {\n value: \"create\" as const,\n label: \"Start fresh (HubSpot Boilerplate)\",\n hint: \"creates a new starter theme\",\n },\n ],\n });\n\n let themeName: string;\n let themePath: string;\n\n const workspaceDir = join(process.cwd(), \"workspace\");\n ensureDir(workspaceDir);\n\n if (choice === \"fetch\") {\n themeName = await ui.text({\n message: \"What's your theme name in HubSpot?\",\n placeholder: \"My-Company-Theme\",\n validate: (v) =>\n v.trim() ? undefined : \"Theme name is required\",\n });\n\n themePath = join(workspaceDir, themeName);\n\n const s = await ui.spinner();\n s.start(\"Fetching theme from HubSpot...\");\n\n const config = loadConfig();\n const pak = getHubSpotPak();\n\n if (config.hubspotUploadMode === \"cli\" || !pak) {\n // CLI fallback\n const result = run(`hs cms fetch \"${themeName}\" \"${themePath}\"`);\n if (!result.success) {\n s.stop(\"Fetch failed\");\n ui.logError(\n `Could not fetch theme \"${themeName}\". Check the name in HubSpot Design Manager.`\n );\n process.exit(1);\n }\n } else {\n // API mode\n try {\n await fetchTheme(pak, themeName, themePath);\n } catch (err) {\n s.stop(\"Fetch failed\");\n ui.logError(\n `Could not fetch theme \"${themeName}\": ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n }\n\n s.stop(`Theme fetched: ${theme.dim(themePath)}`);\n } else {\n themeName = await ui.text({\n message: \"Name for your new theme:\",\n placeholder: \"my-theme\",\n defaultValue: \"my-theme\",\n });\n\n themePath = join(workspaceDir, themeName);\n\n const s = await ui.spinner();\n s.start(\"Creating theme...\");\n\n try {\n createThemeScaffold(themePath, themeName);\n } catch (err) {\n s.stop(\"Creation failed\");\n ui.logError(\n `Could not create theme \"${themeName}\": ${err instanceof Error ? err.message : String(err)}`\n );\n process.exit(1);\n }\n\n s.stop(`Theme created: ${theme.dim(themePath)}`);\n }\n\n // Validate and patch\n await ui.intro(\"Checking theme compatibility\");\n\n const baseHtmlPath = join(themePath, \"templates/layouts/base.html\");\n if (!fileExists(baseHtmlPath)) {\n ui.logError(\n `base.html not found at ${baseHtmlPath}. Your theme may have a different structure.`\n );\n process.exit(1);\n }\n ui.logSuccess(\"base.html found\");\n\n // Check for template_css and template_js support\n let baseHtml = readFile(baseHtmlPath);\n let patched = false;\n\n if (!baseHtml.includes(\"template_css\")) {\n ui.logWarn(\"Missing template_css support in base.html\");\n\n // Find the line with require_css for theme-overrides or the last require_css\n const cssInsertPoint =\n baseHtml.indexOf(\"theme-overrides.css\") !== -1\n ? baseHtml.indexOf(\n \"{{\",\n baseHtml.lastIndexOf(\"\\n\", baseHtml.indexOf(\"theme-overrides.css\"))\n )\n : baseHtml.lastIndexOf(\"require_css\");\n\n if (cssInsertPoint > 0) {\n const insertBefore = baseHtml.lastIndexOf(\"\\n\", cssInsertPoint);\n const block = `\\n {% if template_css %}\\n {{ require_css(get_asset_url(template_css)) }}\\n {% endif %}`;\n baseHtml =\n baseHtml.slice(0, insertBefore) + block + baseHtml.slice(insertBefore);\n patched = true;\n }\n } else {\n ui.logSuccess(\"template_css support\");\n }\n\n if (!baseHtml.includes(\"template_js\")) {\n ui.logWarn(\"Missing template_js support in base.html\");\n\n // Find the line with require_js for main.js or the last require_js\n const jsLine = baseHtml.indexOf(\"require_js\");\n if (jsLine > 0) {\n const lineEnd = baseHtml.indexOf(\"\\n\", jsLine);\n // Find the end of the require_js line (including closing tags)\n const nextLine = baseHtml.indexOf(\"\\n\", lineEnd + 1);\n const block = `\\n {% if template_js %}\\n {{ require_js(get_asset_url(template_js)) }}\\n {% endif %}`;\n const insertAt =\n baseHtml.indexOf(\"}}\", jsLine) + 2 + baseHtml.slice(baseHtml.indexOf(\"}}\", jsLine) + 2).indexOf(\"\\n\") + 1;\n baseHtml =\n baseHtml.slice(0, baseHtml.indexOf(\"\\n\", baseHtml.indexOf(\"}}\", jsLine) + 2)) +\n block +\n baseHtml.slice(baseHtml.indexOf(\"\\n\", baseHtml.indexOf(\"}}\", jsLine) + 2));\n patched = true;\n }\n } else {\n ui.logSuccess(\"template_js support\");\n }\n\n if (patched) {\n const s = await ui.spinner();\n s.start(\"Patching base.html...\");\n writeFile(baseHtmlPath, baseHtml);\n s.stop(\"base.html patched with template_css/template_js support\");\n }\n\n // Check .hsignore\n const hsignorePath = join(themePath, \".hsignore\");\n if (fileExists(hsignorePath)) {\n const hsignore = readFile(hsignorePath);\n if (!hsignore.includes(\"docs/\")) {\n writeFile(hsignorePath, hsignore + \"\\ndocs/\\n\");\n ui.logSuccess(\"Added docs/ to .hsignore\");\n }\n } else {\n writeFile(hsignorePath, \"docs/\\n*.md\\nnode_modules/\\n.git\\n\");\n ui.logSuccess(\"Created .hsignore\");\n }\n\n await ui.outro(\"Theme ready!\");\n\n return { themePath, themeName };\n}\n","/**\n * Theme scaffold generator — replaces `hs cms theme create`.\n * Creates the standard HubSpot theme directory structure locally.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Create a minimal HubSpot theme directory structure.\n * Produces the same layout as `hs cms theme create` but without\n * boilerplate modules/templates (vibespot generates those via AI).\n */\nexport function createThemeScaffold(themePath: string, themeName: string): void {\n // Create directories\n mkdirSync(themePath, { recursive: true });\n mkdirSync(join(themePath, \"templates\"), { recursive: true });\n mkdirSync(join(themePath, \"modules\"), { recursive: true });\n mkdirSync(join(themePath, \"css\"), { recursive: true });\n mkdirSync(join(themePath, \"js\"), { recursive: true });\n mkdirSync(join(themePath, \"images\"), { recursive: true });\n mkdirSync(join(themePath, \"assets\"), { recursive: true });\n\n // theme.json — required by HubSpot\n const themeJson = {\n label: themeName,\n preview_path: \"./templates/home.html\",\n screenshot_path: \"./images/template-previews/home.png\",\n enable_domain_stylesheets: false,\n version: \"1.0.0\",\n author: {\n name: \"vibeSpot\",\n url: \"https://github.com/borismichel/vibespot\",\n },\n };\n writeFileSync(join(themePath, \"theme.json\"), JSON.stringify(themeJson, null, 2) + \"\\n\");\n\n // fields.json — empty theme-level fields\n writeFileSync(join(themePath, \"fields.json\"), \"[]\\n\");\n\n // Landing page template — minimal DnD template for vibespot modules\n const landingTemplate = `<!--\n templateType: page\n isAvailableForNewContent: true\n label: ${themeName} Landing Page\n screenshotPath: ../images/template-previews/home.png\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% block body %}\n{% dnd_area \"main_content\"\n label=\"Main Content\",\n class=\"body-container body-container--${themeName}\"\n%}\n{% end_dnd_area %}\n{% endblock body %}\n`;\n writeFileSync(join(themePath, \"templates\", \"home.html\"), landingTemplate);\n\n // Base layout\n const baseLayout = `<!--\n templateType: none\n isAvailableForNewContent: false\n label: Base Layout\n-->\n<!DOCTYPE html>\n<html lang=\"{{ html_lang }}\" {{ html_lang_dir }}>\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n {{ standard_header_includes }}\n</head>\n<body>\n {% block body %}{% endblock body %}\n {{ standard_footer_includes }}\n</body>\n</html>\n`;\n mkdirSync(join(themePath, \"templates\", \"layouts\"), { recursive: true });\n writeFileSync(join(themePath, \"templates\", \"layouts\", \"base.html\"), baseLayout);\n}\n","/**\n * Theme fetcher — downloads an existing theme from HubSpot\n * via the CMS Source Code API v3. Replaces `hs cms fetch`.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { getMetadata, downloadFile, type FileMetadata } from \"./api.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface FetchThemeOptions {\n onFile?: (path: string) => void;\n concurrency?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Recursive directory listing\n// ---------------------------------------------------------------------------\n\n/** Recursively list all files under a remote path. */\nasync function listFilesRecursive(pak: string, remotePath: string): Promise<string[]> {\n const meta = await getMetadata(pak, remotePath);\n if (!meta) return [];\n\n if (!meta.folder) return [meta.path || remotePath];\n\n const files: string[] = [];\n const rawChildren = meta.children || [];\n\n for (const child of rawChildren) {\n // HubSpot API returns children as plain strings (folder/file names) or as objects\n const childName = typeof child === \"string\" ? child : (child as FileMetadata).name;\n if (!childName) continue;\n const childPath = `${remotePath}/${childName}`;\n\n if (typeof child === \"string\") {\n // String children — need to fetch metadata to determine if folder or file\n files.push(...(await listFilesRecursive(pak, childPath)));\n } else {\n const childMeta = child as FileMetadata;\n if (childMeta.folder) {\n files.push(...(await listFilesRecursive(pak, childMeta.path || childPath)));\n } else {\n files.push(childMeta.path || childPath);\n }\n }\n }\n\n return files;\n}\n\n// ---------------------------------------------------------------------------\n// Parallel download\n// ---------------------------------------------------------------------------\n\nasync function parallelMap<T>(\n items: T[],\n concurrency: number,\n fn: (item: T) => Promise<void>,\n): Promise<void> {\n let index = 0;\n\n async function worker(): Promise<void> {\n while (index < items.length) {\n const i = index++;\n await fn(items[i]);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n}\n\n// ---------------------------------------------------------------------------\n// Main fetch function\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch (download) an entire theme from HubSpot to a local directory.\n */\nexport async function fetchTheme(\n pak: string,\n themeName: string,\n targetPath: string,\n opts: FetchThemeOptions = {},\n): Promise<void> {\n const concurrency = opts.concurrency ?? 5;\n\n // List all files in the remote theme\n const remoteFiles = await listFilesRecursive(pak, themeName);\n\n if (remoteFiles.length === 0) {\n throw new Error(`Theme \"${themeName}\" not found on HubSpot or is empty`);\n }\n\n // Download all files in parallel\n mkdirSync(targetPath, { recursive: true });\n\n await parallelMap(remoteFiles, concurrency, async (remotePath) => {\n // Strip theme name prefix to get relative path\n const relativePath = remotePath.startsWith(themeName + \"/\")\n ? remotePath.slice(themeName.length + 1)\n : remotePath;\n\n const localPath = join(targetPath, relativePath);\n\n // Ensure directory exists\n mkdirSync(dirname(localPath), { recursive: true });\n\n // Download and write\n const content = await downloadFile(pak, remotePath);\n writeFileSync(localPath, content);\n\n opts.onFile?.(relativePath);\n });\n}\n","import { join } from \"node:path\";\nimport { readdirSync, rmSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets } from \"../ai/engine.js\";\nimport type { AIEngineType } from \"../utils/config.js\";\nimport { ClaudeCodeEngine } from \"../ai/claude-code.js\";\nimport { ClaudeAPIEngine } from \"../ai/claude-api.js\";\nimport { GeminiCLIEngine } from \"../ai/gemini-cli.js\";\nimport { CodexCLIEngine } from \"../ai/codex-cli.js\";\nimport { getConversionGuide } from \"../ai/prompts.js\";\nimport { readFile, writeFile, fileExists } from \"../utils/fs.js\";\nimport * as ui from \"../prompts/prompter.js\";\n\nfunction createEngine(type: AIEngineType, model?: string): AIEngine {\n switch (type) {\n case \"claude-code\":\n return new ClaudeCodeEngine(model);\n case \"gemini-cli\":\n return new GeminiCLIEngine();\n case \"codex-cli\":\n return new CodexCLIEngine();\n case \"api\":\n return new ClaudeAPIEngine();\n }\n}\n\nexport async function runConversion(opts: {\n aiEngine: AIEngineType;\n model?: string;\n sourceDir: string;\n themePath: string;\n}): Promise<GeneratedAssets> {\n await ui.intro(\"Converting React to HubSpot Modules\");\n\n await ui.note(\n \"AI will now analyze your React code and create\\nHubSpot-native modules. This takes 2-5 minutes.\",\n \"AI Conversion\"\n );\n\n const engine = createEngine(opts.aiEngine, opts.model);\n\n const conversionGuide = getConversionGuide();\n\n const s = await ui.spinner();\n s.start(\"Starting AI conversion...\");\n\n const startTime = Date.now();\n\n const result = await engine.convert({\n sourceDir: opts.sourceDir,\n themePath: opts.themePath,\n conversionGuide,\n onProgress: (step, detail) => {\n if (step === \"created\") {\n ui.logSuccess(detail);\n } else {\n s.message(detail);\n }\n },\n });\n\n const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);\n s.stop(`AI conversion complete (${elapsed}s)`);\n\n // Validate and auto-fix all known HubSpot issues before upload\n const fixes = validateAndFix(opts.themePath);\n for (const fix of fixes) {\n ui.logSuccess(`Auto-fixed: ${fix}`);\n }\n\n // Show conversion checklist\n const checklist = buildChecklist(opts.themePath, result);\n const lines: string[] = [];\n for (const item of checklist) {\n const icon = item.passed ? \"\\u2705\" : \"\\u274c\";\n const severity = !item.passed ? (item.critical ? \" (CRITICAL)\" : \" (cosmetic)\") : \"\";\n lines.push(`${icon} ${item.label}${severity}`);\n }\n const passed = checklist.filter((c) => c.passed).length;\n lines.push(`\\n${passed}/${checklist.length} checks passed`);\n await ui.note(lines.join(\"\\n\"), \"Conversion Checklist\");\n\n const criticalFailures = checklist.filter((c) => !c.passed && c.critical);\n const cosmeticFailures = checklist.filter((c) => !c.passed && !c.critical);\n\n if (criticalFailures.length > 0) {\n ui.logError(\n `${criticalFailures.length} critical issue(s) — upload will likely fail:\\n` +\n criticalFailures.map((c) => ` - ${c.label}`).join(\"\\n\")\n );\n const proceed = await ui.confirm({\n message: \"Continue with upload anyway?\",\n initialValue: false,\n });\n if (!proceed) {\n throw new Error(\"Conversion aborted due to critical checklist failures.\");\n }\n } else if (cosmeticFailures.length > 0) {\n ui.logWarn(\n `${cosmeticFailures.length} non-critical issue(s) — page will work but may look incomplete:\\n` +\n cosmeticFailures.map((c) => ` - ${c.label}`).join(\"\\n\")\n );\n }\n\n // Offer to clean up log file\n const logPath = join(opts.themePath, \"..\", \"vibespot-conversion.log\");\n if (fileExists(logPath)) {\n const keepLog = await ui.confirm({\n message: \"Keep conversion log file for debugging?\",\n initialValue: false,\n });\n if (!keepLog) {\n rmSync(logPath);\n } else {\n ui.logSuccess(`Log saved: ${logPath}`);\n }\n }\n\n await ui.outro(\"Files ready for upload!\");\n\n return result;\n}\n\n/**\n * Run all validation and auto-fix routines before upload.\n * Returns a list of human-readable fix descriptions.\n */\nexport function validateAndFix(themePath: string): string[] {\n const fixes: string[] = [];\n\n // 1. Template annotations\n validateTemplates(themePath);\n\n // 2. Module meta.json\n validateModuleMeta(themePath);\n\n // 3. Fix fields.json issues in all modules\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n\n const moduleName = entry.replace(\".module\", \"\");\n let content = readFile(fieldsPath);\n let changed = false;\n\n // 3a. \"textarea\" → \"text\"\n if (content.includes('\"textarea\"')) {\n content = content.replace(/\"textarea\"/g, '\"text\"');\n changed = true;\n fixes.push(`${moduleName}: \"textarea\" → \"text\"`);\n }\n\n // 3b. \"name\": \"name\" → \"name\": \"item_name\"\n if (/\"name\":\\s*\"name\"/.test(content)) {\n content = content.replace(/\"name\":\\s*\"name\"/g, '\"name\": \"item_name\"');\n changed = true;\n fixes.push(`${moduleName}: reserved field name \"name\" → \"item_name\"`);\n }\n\n // 3c. Fix \"choice\" fields — choices must be [[\"value\",\"Label\"]] not [\"value\"]\n // 3d. Fix \"link\" fields — default must be { url: { href, type }, open_in_new_tab, no_follow }\n try {\n const fields = JSON.parse(content);\n let jsonFixed = false;\n if (fixChoiceFields(fields)) {\n jsonFixed = true;\n fixes.push(`${moduleName}: fixed choice field format`);\n }\n if (fixLinkFields(fields)) {\n jsonFixed = true;\n fixes.push(`${moduleName}: fixed link field default value`);\n }\n if (jsonFixed) {\n content = JSON.stringify(fields, null, 2) + \"\\n\";\n changed = true;\n }\n } catch {\n fixes.push(`${moduleName}: fields.json has invalid JSON — manual fix needed`);\n }\n\n if (changed) writeFile(fieldsPath, content);\n\n // 3d. Fix now() in module.html\n const htmlPath = join(modulesDir, entry, \"module.html\");\n if (fileExists(htmlPath)) {\n let html = readFile(htmlPath);\n if (html.includes(\"now()\")) {\n html = html.replace(/now\\(\\)/g, \"local_dt\");\n writeFile(htmlPath, html);\n fixes.push(`${moduleName}: now() → local_dt`);\n }\n }\n }\n }\n\n // 4. Remove HubDB templates (requires CMS Hub Pro/Enterprise)\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\")) continue;\n const filePath = join(templatesDir, file);\n const content = readFile(filePath);\n if (content.includes(\"hubdb_table\") || content.includes(\"hubdb_table_rows\")) {\n rmSync(filePath);\n fixes.push(`Removed ${file} (HubDB requires CMS Hub Pro/Enterprise)`);\n }\n }\n }\n\n return fixes;\n}\n\n/** Recursively fix choice fields: convert string[] choices to [value, Label][] */\nfunction fixChoiceFields(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"choice\" && Array.isArray(f.choices)) {\n const needsFix = f.choices.some((c: unknown) => typeof c === \"string\");\n if (needsFix) {\n f.choices = (f.choices as unknown[]).map((c: unknown) => {\n if (typeof c === \"string\") {\n const label = c.charAt(0).toUpperCase() + c.slice(1);\n return [c, label];\n }\n return c;\n });\n fixed = true;\n }\n }\n\n // Recurse into group children\n if (Array.isArray(f.children)) {\n if (fixChoiceFields(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n\n/** Recursively fix link fields: default must be { url: { href, type }, open_in_new_tab, no_follow } */\nfunction fixLinkFields(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"link\") {\n const def = f.default;\n // Fix if default is a string, missing, or doesn't have the required url.href structure\n const needsFix =\n typeof def === \"string\" ||\n def === undefined ||\n def === null ||\n (typeof def === \"object\" && !(def as Record<string, unknown>).url);\n\n if (needsFix) {\n const href = typeof def === \"string\" ? def : \"\";\n f.default = {\n url: { href, type: \"EXTERNAL\" },\n open_in_new_tab: false,\n no_follow: false,\n };\n fixed = true;\n }\n }\n\n // Recurse into group children\n if (Array.isArray(f.children)) {\n if (fixLinkFields(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n\ninterface CheckItem {\n label: string;\n passed: boolean;\n /** If true, failure blocks upload. If false, it's cosmetic / nice-to-have. */\n critical: boolean;\n}\n\nfunction buildChecklist(themePath: string, result: GeneratedAssets): CheckItem[] {\n const items: CheckItem[] = [];\n\n // Modules — critical: upload will fail with zero modules\n const moduleCount = result.modules.length;\n items.push({\n label: `Modules created (${moduleCount})`,\n passed: moduleCount > 0,\n critical: true,\n });\n\n // fields.json — critical: invalid fields cause upload deserialization errors\n let fieldsOk = true;\n for (const m of result.modules) {\n if (m.fieldsJson.includes('\"textarea\"') || /\"name\":\\s*\"name\"/.test(m.fieldsJson)) {\n fieldsOk = false;\n break;\n }\n }\n items.push({\n label: \"fields.json valid (no textarea, no reserved names)\",\n passed: moduleCount > 0 && fieldsOk,\n critical: true,\n });\n\n // module.html — critical: modules won't render without it\n const allHaveHtml = result.modules.every((m) => m.moduleHtml.length > 0);\n items.push({\n label: \"module.html created for each module\",\n passed: moduleCount > 0 && allHaveHtml,\n critical: true,\n });\n\n // module.css — not critical (page works but looks unstyled)\n const missingCss = result.modules.filter((m) => !m.moduleCss).map((m) => m.moduleName);\n const allHaveCss = missingCss.length === 0;\n items.push({\n label: allHaveCss\n ? \"module.css created for each module\"\n : `module.css missing for: ${missingCss.join(\", \")}`,\n passed: moduleCount > 0 && allHaveCss,\n critical: false,\n });\n\n // Style tab — not critical (modules work without style tab)\n const hasStyleTab = result.modules.some((m) => m.fieldsJson.includes('\"STYLE\"'));\n items.push({\n label: \"Style tab fields (color pickers)\",\n passed: hasStyleTab,\n critical: false,\n });\n\n // Shared CSS — not critical (modules have their own CSS)\n items.push({\n label: \"Shared CSS with design system variables\",\n passed: result.sharedCss.length > 50,\n critical: false,\n });\n\n // Shared JS — not critical (page works without animations)\n items.push({\n label: \"Shared JS for scroll animations\",\n passed: result.sharedJs.length > 50,\n critical: false,\n });\n\n // Page template — critical: no template means no page in HubSpot\n items.push({\n label: \"Page template with dnd_area\",\n passed: result.template.length > 0 && result.template.includes(\"dnd_area\"),\n critical: true,\n });\n\n // Template annotations — critical: template won't appear in picker\n const templatesDir = join(themePath, \"templates\");\n let templateAnnotated = false;\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\") || file === \"base.html\" || file.startsWith(\"system\")) continue;\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\") && /templateType\\s*:\\s*page/i.test(content)) {\n templateAnnotated = true;\n break;\n }\n }\n }\n items.push({\n label: \"Template annotations (templateType: page)\",\n passed: templateAnnotated,\n critical: true,\n });\n\n return items;\n}\n\n/**\n * Ensure all templates in templates/ have the required HubSpot annotations.\n * Without `templateType: page` and `isAvailableForNewContent: true`,\n * the template won't appear in HubSpot's template picker.\n */\nexport function validateTemplates(themePath: string): void {\n const templatesDir = join(themePath, \"templates\");\n if (!fileExists(templatesDir)) return;\n\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\") || file === \"base.html\" || file.startsWith(\"system\")) continue;\n\n const filePath = join(templatesDir, file);\n let content = readFile(filePath);\n\n // Skip files that don't look like page templates\n if (!content.includes(\"dnd_area\") && !content.includes(\"extends\")) continue;\n\n const hasTemplateType = /templateType\\s*:\\s*page/i.test(content);\n const hasAvailable = /isAvailableForNewContent\\s*:\\s*true/i.test(content);\n\n if (hasTemplateType && hasAvailable) continue;\n\n // Build the annotation block\n const label = file.replace(\".html\", \"\").replace(/[-_]/g, \" \").replace(/\\b\\w/g, c => c.toUpperCase());\n\n if (content.includes(\"<!--\") && content.indexOf(\"-->\") < 200) {\n // Has an existing comment block at the top — patch it\n const commentEnd = content.indexOf(\"-->\");\n let annotation = content.slice(0, commentEnd);\n\n if (!hasTemplateType) {\n annotation += \"\\n templateType: page\";\n }\n if (!hasAvailable) {\n annotation += \"\\n isAvailableForNewContent: true\";\n }\n if (!/label\\s*:/i.test(annotation)) {\n annotation += `\\n label: ${label}`;\n }\n\n content = annotation + content.slice(commentEnd);\n } else {\n // No annotation block — prepend one\n const block = `<!--\\n templateType: page\\n isAvailableForNewContent: true\\n label: ${label}\\n-->\\n`;\n content = block + content;\n }\n\n writeFile(filePath, content);\n ui.logSuccess(`Template \"${file}\" — annotations verified`);\n }\n\n}\n\n/**\n * Ensure all module meta.json files have the required fields for\n * landing page compatibility.\n */\nexport function validateModuleMeta(themePath: string): void {\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const metaPath = join(modulesDir, entry, \"meta.json\");\n if (!fileExists(metaPath)) continue;\n\n try {\n const meta = JSON.parse(readFile(metaPath));\n let changed = false;\n\n if (!meta.host_template_types || !meta.host_template_types.includes(\"PAGE\")) {\n meta.host_template_types = [\"PAGE\"];\n changed = true;\n }\n if (!meta.is_available_for_new_content) {\n meta.is_available_for_new_content = true;\n changed = true;\n }\n\n if (changed) {\n writeFile(metaPath, JSON.stringify(meta, null, 2) + \"\\n\");\n }\n } catch {\n // Skip malformed meta.json\n }\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { join, basename } from \"node:path\";\nimport { readdirSync, statSync, writeFileSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport { getConversionGuide, getHubspotRules } from \"./prompts.js\";\nimport { readFile, fileExists } from \"../utils/fs.js\";\n\n/** Boilerplate modules from `hs cms theme create` — used to distinguish AI-generated modules. */\nconst BOILERPLATE_MODULES = new Set([\n \"button.module\",\n \"card.module\",\n \"menu.module\",\n \"pricing-card.module\",\n \"social-follow.module\",\n]);\n\n/** Boilerplate templates from `hs cms theme create`. */\nconst BOILERPLATE_TEMPLATES = new Set([\n \"about.html\",\n \"blog-index.html\",\n \"blog-post.html\",\n \"contact.html\",\n \"home.html\",\n \"hubdb.html\",\n \"landing-page.html\",\n \"pricing.html\",\n \"qa-test.html\",\n \"base.html\",\n]);\n\nexport class ClaudeCodeEngine implements AIEngine {\n private model?: string;\n private reported = new Set<string>();\n private moduleCount = 0;\n private expectedModules = 0;\n\n constructor(model?: string) {\n this.model = model;\n }\n\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, onProgress } = opts;\n const guide = opts.conversionGuide || getConversionGuide();\n\n // Reset progress tracking\n this.reported.clear();\n this.moduleCount = 0;\n this.expectedModules = 0;\n\n // Count source components to estimate expected modules\n const sourceComponents = this.countSourceComponents(sourceDir);\n\n // Snapshot existing files so we can detect what Claude actually created\n const existingModules = this.listModules(themePath);\n const existingCss = this.listDir(join(themePath, \"css\"));\n const existingJs = this.listDir(join(themePath, \"js\"));\n const existingTemplates = this.listDir(join(themePath, \"templates\"));\n\n // Build the prompt for Claude Code\n const prompt = this.buildFullPrompt(sourceDir, themePath, guide);\n\n onProgress(\"convert\", `Starting Claude Code (${sourceComponents} source components found)...`);\n\n // Run Claude Code with real-time progress tracking\n let stdout = \"\";\n let stderr = \"\";\n\n // Poll the filesystem every 3s to show progress\n const progressInterval = setInterval(() => {\n this.reportProgress(themePath, existingModules, existingCss, existingJs, existingTemplates, onProgress);\n }, 3000);\n\n try {\n await new Promise<void>((resolve, reject) => {\n // Strip CLAUDECODE env var to allow running from inside a Claude Code session\n const env = { ...process.env };\n delete env.CLAUDECODE;\n\n const args = [\n \"--print\",\n \"--max-turns\", \"50\",\n \"--allowedTools\", \"Read,Glob,Grep,Write,Edit,Bash\",\n ];\n if (this.model) args.push(\"--model\", this.model);\n\n const child = spawn(\"claude\", args, {\n cwd: themePath,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n shell: true,\n });\n\n child.stdout.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) => reject(new Error(`Claude Code failed to start: ${err.message}`)));\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(\n `Claude Code exited with code ${code}.\\n` +\n (stderr ? `Stderr: ${stderr.slice(0, 500)}\\n` : \"\") +\n (stdout ? `Output: ${stdout.slice(0, 500)}` : \"No output\")\n ));\n } else {\n resolve();\n }\n });\n\n // Handle stdin errors (EPIPE if claude exits before prompt is fully written)\n child.stdin.on(\"error\", () => {});\n\n // Send prompt via stdin and close\n child.stdin.write(prompt);\n child.stdin.end();\n\n // 30 min timeout\n setTimeout(() => {\n child.kill();\n reject(new Error(\"Claude Code timed out after 30 minutes\"));\n }, 1_800_000);\n });\n } finally {\n clearInterval(progressInterval);\n }\n\n // Write full log to workspace for debugging\n const logPath = join(themePath, \"..\", \"vibespot-conversion.log\");\n try {\n const timestamp = new Date().toISOString();\n const logContent = [\n `=== vibeSpot Conversion Log ===`,\n `Timestamp: ${timestamp}`,\n `Source: ${sourceDir}`,\n `Theme: ${themePath}`,\n `Model: ${this.model || \"default\"}`,\n ``,\n `=== PROMPT SENT ===`,\n prompt.slice(0, 500) + \"\\n... (truncated, full guide follows)\",\n ``,\n `=== CLAUDE CODE STDOUT ===`,\n stdout || \"(empty)\",\n ``,\n `=== CLAUDE CODE STDERR ===`,\n stderr || \"(empty)\",\n ``,\n ].join(\"\\n\");\n writeFileSync(logPath, logContent, \"utf-8\");\n onProgress(\"status\", `Log written to ${basename(logPath)}`);\n } catch {\n // Non-critical — don't fail if log can't be written\n }\n\n onProgress(\"scan\", \"Scanning generated files...\");\n\n // Scan the theme directory for what Claude Code created\n const result = this.scanGeneratedFiles(themePath);\n\n // Validate that new files were actually created\n const newModules = result.modules.filter(\n (m) => !existingModules.has(m.moduleName + \".module\")\n );\n\n if (newModules.length === 0) {\n const outputPreview = stdout.slice(0, 1500) || \"(no output)\";\n const stderrPreview = stderr.slice(0, 500);\n throw new Error(\n \"Claude Code did not create any new module files.\\n\\n\" +\n \"This usually means the model described the conversion instead of using Write tool to create files.\\n\\n\" +\n \"Possible causes:\\n\" +\n \" - Model didn't use Write tool (just printed text)\\n\" +\n \" - Claude Code hit a rate limit or API error\\n\" +\n \" - The source directory was not accessible\\n\\n\" +\n `Source: ${opts.sourceDir}\\n` +\n `Theme: ${themePath}\\n` +\n (stderrPreview ? `\\nStderr:\\n${stderrPreview}\\n` : \"\") +\n `\\nClaude output:\\n${outputPreview}`\n );\n }\n\n return result;\n }\n\n /** Poll filesystem and emit \"created\" events for newly detected files. */\n private reportProgress(\n themePath: string,\n existingModules: Set<string>,\n existingCss: Set<string>,\n existingJs: Set<string>,\n existingTemplates: Set<string>,\n onProgress: (step: string, detail: string) => void,\n ): void {\n let newItems = 0;\n\n // Check for new CSS files\n const currentCss = this.listDir(join(themePath, \"css\"));\n for (const f of currentCss) {\n if (existingCss.has(f) || !f.endsWith(\".css\")) continue;\n const key = `css:${f}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n onProgress(\"created\", `Shared CSS (${f})`);\n newItems++;\n }\n }\n\n // Check for new JS files\n const currentJs = this.listDir(join(themePath, \"js\"));\n for (const f of currentJs) {\n if (existingJs.has(f) || !f.endsWith(\".js\")) continue;\n const key = `js:${f}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n onProgress(\"created\", `Shared JS (${f})`);\n newItems++;\n }\n }\n\n // Try to detect expected module count from template file (once it exists)\n if (this.expectedModules === 0) {\n this.expectedModules = this.detectExpectedModules(themePath, existingTemplates);\n }\n\n // Check for new modules\n const currentModules = this.listModules(themePath);\n for (const mod of currentModules) {\n if (existingModules.has(mod)) continue;\n const key = `module:${mod}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n this.moduleCount++;\n const counter = this.expectedModules > 0\n ? `[${this.moduleCount}/${this.expectedModules}]`\n : `[${this.moduleCount}]`;\n onProgress(\"created\", `Module ${counter}: ${mod.replace(\".module\", \"\")}`);\n newItems++;\n }\n }\n\n // Check for new templates\n const currentTemplates = this.listDir(join(themePath, \"templates\"));\n for (const f of currentTemplates) {\n if (existingTemplates.has(f) || !f.endsWith(\".html\")) continue;\n const key = `template:${f}`;\n if (!this.reported.has(key)) {\n this.reported.add(key);\n onProgress(\"created\", `Page template (${f})`);\n newItems++;\n }\n }\n\n // Update spinner status text (only if no new items were just logged)\n if (newItems === 0) {\n if (this.moduleCount > 0) {\n const of = this.expectedModules > 0 ? `/${this.expectedModules}` : \"\";\n onProgress(\"status\", `${this.moduleCount}${of} modules created, conversion continuing...`);\n } else if (this.reported.size > 0) {\n onProgress(\"status\", \"Shared assets created, building modules...\");\n } else {\n onProgress(\"status\", \"Claude Code is analyzing source files...\");\n }\n }\n }\n\n private buildFullPrompt(\n sourceDir: string,\n themePath: string,\n guide: string\n ): string {\n return `You are converting a React landing page to native HubSpot CMS modules.\n\nSOURCE DIRECTORY: ${sourceDir}\nTHEME DIRECTORY: ${themePath}\n\nIMPORTANT — YOU MUST CREATE REAL FILES:\nYou have access to Write, Edit, Read, Glob, Grep, and Bash tools. You MUST use the Write tool to create each file. Do NOT just describe or list what files should be created — actually call the Write tool for every single file. If you do not call Write, no files will be created and the conversion will fail.\n\nSTEP-BY-STEP PROCESS:\n1. Use Glob to find all .tsx/.jsx files in ${sourceDir}/src/\n2. Use Read to read each component file and understand the page structure\n3. Use Write to create a shared CSS file at ${themePath}/css/<name>-theme.css\n - Include CSS custom properties, design system variables, utility classes\n - Add theme-override countermeasures (.body-wrapper:has(), scoped !important overrides)\n4. Use Write to create a shared JS file at ${themePath}/js/<name>-animations.js\n - Convert React hooks to vanilla JS (IntersectionObserver for scroll animations)\n - IIFE wrapper, DOMContentLoaded setup\n5. For EACH visual section of the page, use Write to create ALL FOUR files:\n a. ${themePath}/modules/<name>.module/fields.json\n - Editable fields for the section content\n - NEVER use \"textarea\" type (use \"text\" instead)\n - NEVER use \"name\" as a field name (use \"item_name\" instead)\n - Add a \"styles\" group with \"tab\": \"STYLE\" containing color pickers\n b. ${themePath}/modules/<name>.module/meta.json\n - Must include: host_template_types: [\"PAGE\"], is_available_for_new_content: true\n c. ${themePath}/modules/<name>.module/module.html\n - HubL template that renders the section (convert JSX to HubL)\n d. ${themePath}/modules/<name>.module/module.css\n - REQUIRED — complete vanilla CSS for this section\n - Must include: layout, spacing, colors, typography, backgrounds, gradients, shadows, borders, hover effects, responsive breakpoints\n - Convert ALL Tailwind classes to BEM-style CSS. Do NOT skip this file.\n6. Use Write to create a page template at ${themePath}/templates/lp-<name>.html\n - Annotation: templateType: page, isAvailableForNewContent: true\n - Extends \"./layouts/base.html\"\n - Sets template_css and template_js variables\n - Wraps modules in dnd_area with dnd_section containers\n7. Read ${themePath}/templates/layouts/base.html and ensure it supports template_css and template_js variables\n\nCSS QUALITY: The converted page must visually match the original React page. Every module.css must be self-contained with complete styling for that section.\n\nDo NOT run hs upload — I will handle that separately.\n\nHUBSPOT CMS RULES:\n${getHubspotRules()}\n\nCONVERSION GUIDE:\n${guide}`;\n }\n\n private scanGeneratedFiles(themePath: string): GeneratedAssets {\n const result: GeneratedAssets = {\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n modules: [],\n };\n\n // Find shared CSS (any non-boilerplate CSS in css/)\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (\n file.endsWith(\".css\") &&\n file !== \"theme-overrides.css\" &&\n file !== \"main.css\" &&\n file !== \"style.css\"\n ) {\n result.sharedCss = readFile(join(cssDir, file));\n break;\n }\n }\n }\n\n // Find shared JS (any non-boilerplate JS in js/)\n const jsDir = join(themePath, \"js\");\n if (fileExists(jsDir)) {\n for (const file of readdirSync(jsDir)) {\n if (\n file.endsWith(\".js\") &&\n file !== \"main.js\"\n ) {\n result.sharedJs = readFile(join(jsDir, file));\n break;\n }\n }\n }\n\n // Find new template (prefer lp-* or non-boilerplate templates)\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n // First pass: look for lp-* templates (AI-generated naming convention)\n for (const file of readdirSync(templatesDir)) {\n if (file.startsWith(\"lp-\") && file.endsWith(\".html\")) {\n result.template = readFile(join(templatesDir, file));\n break;\n }\n }\n // Second pass: any non-boilerplate template with dnd_area\n if (!result.template) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !BOILERPLATE_TEMPLATES.has(file) &&\n !file.startsWith(\"system\")\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n // Third pass: fall back to any template with dnd_area\n if (!result.template) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !file.startsWith(\"system\") &&\n file !== \"base.html\"\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n }\n\n // Scan modules/\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const modDir = join(modulesDir, entry);\n if (!statSync(modDir).isDirectory()) continue;\n\n const moduleFiles: ModuleFiles = {\n moduleName: entry.replace(\".module\", \"\"),\n fieldsJson: \"\",\n metaJson: \"\",\n moduleHtml: \"\",\n moduleCss: \"\",\n };\n\n const fj = join(modDir, \"fields.json\");\n if (fileExists(fj)) moduleFiles.fieldsJson = readFile(fj);\n\n const mj = join(modDir, \"meta.json\");\n if (fileExists(mj)) moduleFiles.metaJson = readFile(mj);\n\n const mh = join(modDir, \"module.html\");\n if (fileExists(mh)) moduleFiles.moduleHtml = readFile(mh);\n\n const mc = join(modDir, \"module.css\");\n if (fileExists(mc)) moduleFiles.moduleCss = readFile(mc);\n\n const mjs = join(modDir, \"module.js\");\n if (fileExists(mjs)) moduleFiles.moduleJs = readFile(mjs);\n\n // Only count modules that have at least fields.json and module.html\n if (moduleFiles.fieldsJson && moduleFiles.moduleHtml) {\n result.modules.push(moduleFiles);\n }\n }\n }\n\n return result;\n }\n\n /** List module directories in modules/ */\n private listModules(themePath: string): Set<string> {\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return new Set();\n return new Set(\n readdirSync(modulesDir).filter((e) => e.endsWith(\".module\"))\n );\n }\n\n /** List files in a directory */\n private listDir(dir: string): Set<string> {\n if (!fileExists(dir)) return new Set();\n return new Set(readdirSync(dir));\n }\n\n /** Detect expected module count from template file (counts dnd_module references) */\n private detectExpectedModules(themePath: string, existingTemplates: Set<string>): number {\n const templatesDir = join(themePath, \"templates\");\n if (!fileExists(templatesDir)) return 0;\n\n for (const file of readdirSync(templatesDir)) {\n if (existingTemplates.has(file)) continue;\n if (!file.endsWith(\".html\") || file === \"base.html\" || file.startsWith(\"system\")) continue;\n\n try {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n const matches = content.match(/dnd_module/g);\n return matches ? matches.length : 0;\n }\n } catch {\n // Skip unreadable files\n }\n }\n return 0;\n }\n\n /** Count .tsx/.jsx component files in the source directory */\n private countSourceComponents(sourceDir: string): number {\n const srcDir = join(sourceDir, \"src\");\n if (!fileExists(srcDir)) return 0;\n return this.countComponentsRecursive(srcDir);\n }\n\n private countComponentsRecursive(dir: string): number {\n let count = 0;\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry);\n try {\n const stat = statSync(fullPath);\n if (stat.isDirectory() && entry !== \"node_modules\" && entry !== \".git\") {\n count += this.countComponentsRecursive(fullPath);\n } else if (/\\.(tsx|jsx)$/.test(entry) && !entry.includes(\".test.\") && !entry.includes(\".spec.\")) {\n count++;\n }\n } catch {\n // Skip unreadable entries\n }\n }\n return count;\n }\n}\n","import { readFile, resolveAsset } from \"../utils/fs.js\";\n\n// In-memory cache for guide files (~90KB total, read once)\nconst guideCache = new Map<string, string>();\n\nfunction cachedAsset(name: string): string {\n let val = guideCache.get(name);\n if (val !== undefined) return val;\n try { val = readFile(resolveAsset(name)); } catch { val = \"\"; }\n guideCache.set(name, val);\n return val;\n}\n\nexport function getConversionGuide(): string {\n return cachedAsset(\"conversion-guide.md\") || \"Conversion guide not found. Using built-in rules.\";\n}\n\nexport function getDesignGuide(): string {\n return cachedAsset(\"design-guide.md\");\n}\n\nexport function getContentGuide(): string {\n return cachedAsset(\"content-guide.md\");\n}\n\nexport function getHubspotRules(): string {\n return cachedAsset(\"hubspot-rules.md\");\n}\n\nexport function getHumanifyGuide(): string {\n return cachedAsset(\"humanify-guide.md\");\n}\n\n/**\n * Extract page-type-specific section from page-types.md.\n * Returns only the relevant section for the given page type.\n */\nexport function getPageTypeGuide(pageType: string): string {\n const fullGuide = cachedAsset(\"page-types.md\");\n if (!fullGuide) return \"\";\n\n // Map page type to section header\n const sectionHeaders: Record<string, string> = {\n landing_page: \"## Landing Page\",\n blog_post: \"## Blog Post\",\n website_page: \"## Website Page\",\n module_only: \"## Module Only\",\n };\n\n const header = sectionHeaders[pageType];\n if (!header) return \"\";\n\n const startIdx = fullGuide.indexOf(header);\n if (startIdx < 0) return \"\";\n\n // Find the next section (## at start of line) after this one\n const afterHeader = fullGuide.indexOf(\"\\n## \", startIdx + header.length);\n const section = afterHeader >= 0\n ? fullGuide.slice(startIdx, afterHeader).trim()\n : fullGuide.slice(startIdx).trim();\n\n return section;\n}\n\nexport function buildSystemPrompt(conversionGuide: string): string {\n return `You are a HubSpot CMS expert converting React/Tailwind pages to native HubSpot modules.\n\n## Rules\nFollow the conversion guide below EXACTLY. Key rules:\n- Use \"type\": \"text\" (NEVER \"textarea\")\n- NEVER use \"name\": \"name\" (it's reserved) — use alternatives like \"item_name\"\n- Wrap style fields in a \"styles\" group with \"tab\": \"STYLE\" on the group\n- All CSS classes must use a unique prefix to avoid theme conflicts\n- Every dnd_section needs padding={\"top\":\"0\",\"bottom\":\"0\",\"left\":\"0\",\"right\":\"0\"}, full_width=true\n- Use template_css and template_js variables (resolved in base.html, not child templates)\n- Add .body-wrapper:has(.my-page) CSS fix + JS fallback for body background\n- Add scoped overrides with !important for headings, paragraphs, links to defeat theme-overrides.css\n- Use IntersectionObserver for scroll animations (add .visible class)\n- Convert Tailwind utilities to vanilla CSS with BEM naming\n- Convert React hooks to vanilla JS (no React, no npm packages)\n\n## HubSpot CMS Rules\n${getHubspotRules()}\n\n## Conversion Guide\n${conversionGuide}`;\n}\n\nexport function buildAnalyzePrompt(componentList: string): string {\n return `Analyze these React components and create a module map.\n\nFor each component, return a JSON object with:\n- name: HubSpot module name (e.g., \"My Hero\")\n- description: Brief description of the section\n- hasRepeaters: true if it contains .map() or array iteration\n- hasInteractivity: true if it has JS-driven behavior (carousel, accordion, etc.)\n\nComponents:\n${componentList}\n\nReturn ONLY valid JSON array, no markdown fences.`;\n}\n\nexport function buildModulePrompt(\n componentSource: string,\n moduleName: string,\n cssVars: string\n): string {\n return `Convert this React component to a HubSpot module named \"${moduleName}\".\n\nReturn a JSON object with these keys:\n- fieldsJson: complete fields.json content (as JSON string)\n- metaJson: complete meta.json content (as JSON string)\n- moduleHtml: complete module.html content (HubL template)\n- moduleCss: complete module.css content (vanilla CSS)\n- moduleJs: module.js content if interactive behavior needed, or null\n\nDesign system CSS variables available:\n${cssVars}\n\nReact component source:\n${componentSource}\n\nReturn ONLY valid JSON, no markdown fences.`;\n}\n\nexport function buildCssPrompt(\n indexCss: string,\n tailwindConfig: string,\n pagePrefix: string\n): string {\n return `Create a shared CSS file for a HubSpot CMS landing page.\n\nExtract the design system from the source CSS and Tailwind config below.\nUse the class prefix \".${pagePrefix}-\" for all custom classes.\n\nRequirements:\n- CSS custom properties for all colors, spacing\n- Page wrapper styles (.${pagePrefix}-page) with !important font/color\n- .body-wrapper:has(.${pagePrefix}-page) background fix\n- .body-wrapper.${pagePrefix}-page-active JS fallback\n- Scoped overrides: .${pagePrefix}-page h1-h6, p, a with !important\n- .dnd-section padding: 0 !important and .row-fluid max-width: 100%\n- Form overrides for dark themes\n- Utility classes (container, section, grid, glass)\n- Scroll animation classes (.${pagePrefix}-scroll-animate / .visible)\n- Mobile breakpoint at 767px\n- Responsive grid fallbacks\n\nSource CSS:\n${indexCss}\n\nTailwind config:\n${tailwindConfig}\n\nReturn ONLY the CSS content, no markdown fences.`;\n}\n\nexport function buildJsPrompt(\n hooksSource: string,\n interactiveComponents: string,\n pagePrefix: string\n): string {\n return `Create a shared vanilla JS file for a HubSpot CMS landing page.\n\nConvert the React hooks and interactive components below to plain JavaScript.\nUse the class prefix \"${pagePrefix}-\" to match the CSS.\n\nRequirements:\n- IIFE wrapper with \"use strict\"\n- initBodyWrapper: add \"${pagePrefix}-page-active\" class to .body-wrapper\n- initScrollAnimations: IntersectionObserver for .${pagePrefix}-scroll-animate → .visible\n- Convert any carousels, accordions, typing animations to vanilla JS\n- DOMContentLoaded / readyState check\n\nReact hooks source:\n${hooksSource}\n\nInteractive component sources:\n${interactiveComponents}\n\nReturn ONLY the JavaScript content, no markdown fences.`;\n}\n\nexport function buildTemplatePrompt(\n moduleNames: string[],\n themeName: string,\n pagePrefix: string\n): string {\n return `Create a HubSpot page template that assembles these modules:\n\n${moduleNames.map((n, i) => `${i + 1}. ${n}.module`).join(\"\\n\")}\n\nTemplate requirements:\n- templateType: page, isAvailableForNewContent: true\n- extends \"./layouts/base.html\"\n- set template_css = \"../../css/${pagePrefix}-theme.css\"\n- set template_js = \"../../js/${pagePrefix}-animations.js\"\n- Empty header and footer blocks (modules handle them)\n- Wrap content in <div class=\"${pagePrefix}-page\">\n- Each module in its own dnd_section with padding zeroed and full_width=true\n- dnd_area label: \"${themeName} Landing Page\"\n\nReturn ONLY the template HTML content, no markdown fences.`;\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport { join, basename } from \"node:path\";\nimport { readdirSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport {\n buildSystemPrompt,\n buildCssPrompt,\n buildJsPrompt,\n buildModulePrompt,\n buildTemplatePrompt,\n} from \"./prompts.js\";\nimport { readFile, fileExists, writeFile, ensureDir } from \"../utils/fs.js\";\n\nexport class ClaudeAPIEngine implements AIEngine {\n private client: Anthropic;\n private model = \"claude-sonnet-4-6\";\n\n constructor(apiKey?: string) {\n this.client = new Anthropic({\n apiKey: apiKey || process.env.ANTHROPIC_API_KEY,\n });\n }\n\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, conversionGuide, onProgress } = opts;\n const systemPrompt = buildSystemPrompt(conversionGuide);\n\n // Determine a page prefix from the source dir name\n const dirName = basename(sourceDir) || \"page\";\n const pagePrefix = dirName\n .toLowerCase()\n .replace(/[^a-z0-9]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 15);\n\n // Step 1: Generate shared CSS\n onProgress(\"css\", \"Analyzing design system...\");\n const indexCss = this.findAndReadCSS(sourceDir);\n const tailwindConfig = this.findAndReadTailwind(sourceDir);\n\n const cssContent = await this.complete(\n systemPrompt,\n buildCssPrompt(indexCss, tailwindConfig, pagePrefix)\n );\n const cssPath = join(themePath, \"css\", `${pagePrefix}-theme.css`);\n writeFile(cssPath, cssContent);\n onProgress(\"css-done\", `Created css/${pagePrefix}-theme.css`);\n\n // Step 2: Generate shared JS\n onProgress(\"js\", \"Creating shared JavaScript...\");\n const hooksSource = this.findAndReadHooks(sourceDir);\n const interactiveSource = this.findInteractiveComponents(sourceDir);\n\n const jsContent = await this.complete(\n systemPrompt,\n buildJsPrompt(hooksSource, interactiveSource, pagePrefix)\n );\n const jsPath = join(themePath, \"js\", `${pagePrefix}-animations.js`);\n writeFile(jsPath, jsContent);\n onProgress(\"js-done\", `Created js/${pagePrefix}-animations.js`);\n\n // Step 3: Generate modules\n onProgress(\"modules\", \"Building modules...\");\n const components = this.findComponents(sourceDir);\n const modules: ModuleFiles[] = [];\n\n for (let i = 0; i < components.length; i++) {\n const comp = components[i];\n const moduleName = comp.name\n .replace(/Section$/, \"\")\n .replace(/([A-Z])/g, \" $1\")\n .trim();\n\n onProgress(\n \"module\",\n `Building ${moduleName}.module (${i + 1}/${components.length})...`\n );\n\n const source = readFile(comp.path);\n const response = await this.complete(\n systemPrompt,\n buildModulePrompt(source, moduleName, `See css/${pagePrefix}-theme.css`)\n );\n\n try {\n const parsed = JSON.parse(response);\n const mod: ModuleFiles = {\n moduleName,\n fieldsJson: typeof parsed.fieldsJson === \"string\"\n ? parsed.fieldsJson\n : JSON.stringify(parsed.fieldsJson, null, 2),\n metaJson: typeof parsed.metaJson === \"string\"\n ? parsed.metaJson\n : JSON.stringify(parsed.metaJson, null, 2),\n moduleHtml: parsed.moduleHtml || \"\",\n moduleCss: parsed.moduleCss || \"\",\n moduleJs: parsed.moduleJs || undefined,\n };\n\n // Write module files\n const modDir = join(themePath, \"modules\", `${moduleName}.module`);\n ensureDir(modDir);\n writeFile(join(modDir, \"fields.json\"), mod.fieldsJson);\n writeFile(join(modDir, \"meta.json\"), mod.metaJson);\n writeFile(join(modDir, \"module.html\"), mod.moduleHtml);\n writeFile(join(modDir, \"module.css\"), mod.moduleCss);\n if (mod.moduleJs) writeFile(join(modDir, \"module.js\"), mod.moduleJs);\n\n modules.push(mod);\n onProgress(\"module-done\", `${moduleName}.module (${this.countFiles(mod)} files)`);\n } catch {\n onProgress(\"module-error\", `Failed to parse ${moduleName} — skipping`);\n }\n }\n\n // Step 4: Generate template\n onProgress(\"template\", \"Creating page template...\");\n const moduleNames = modules.map((m) => m.moduleName);\n const templateContent = await this.complete(\n systemPrompt,\n buildTemplatePrompt(moduleNames, dirName, pagePrefix)\n );\n\n const templatePath = join(\n themePath,\n \"templates\",\n `lp-${pagePrefix}.html`\n );\n writeFile(templatePath, templateContent);\n onProgress(\"template-done\", `Created templates/lp-${pagePrefix}.html`);\n\n return {\n sharedCss: cssContent,\n sharedJs: jsContent,\n template: templateContent,\n modules,\n };\n }\n\n private async complete(system: string, user: string): Promise<string> {\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: 8192,\n system,\n messages: [{ role: \"user\", content: user }],\n });\n\n const textBlock = response.content.find((b) => b.type === \"text\");\n return textBlock?.text || \"\";\n }\n\n private findAndReadCSS(dir: string): string {\n const paths = [\n join(dir, \"src/index.css\"),\n join(dir, \"src/globals.css\"),\n join(dir, \"src/app/globals.css\"),\n join(dir, \"app/globals.css\"),\n ];\n for (const p of paths) {\n if (fileExists(p)) return readFile(p);\n }\n return \"\";\n }\n\n private findAndReadTailwind(dir: string): string {\n const paths = [\n join(dir, \"tailwind.config.ts\"),\n join(dir, \"tailwind.config.js\"),\n join(dir, \"tailwind.config.mjs\"),\n ];\n for (const p of paths) {\n if (fileExists(p)) return readFile(p);\n }\n return \"\";\n }\n\n private findAndReadHooks(dir: string): string {\n const hooksDir = join(dir, \"src/hooks\");\n if (!fileExists(hooksDir)) return \"\";\n try {\n return readdirSync(hooksDir)\n .filter((f) => f.endsWith(\".ts\") || f.endsWith(\".tsx\"))\n .map((f) => `// ${f}\\n${readFile(join(hooksDir, f))}`)\n .join(\"\\n\\n\");\n } catch {\n return \"\";\n }\n }\n\n private findInteractiveComponents(dir: string): string {\n const components = this.findComponents(dir);\n const interactive: string[] = [];\n\n for (const comp of components) {\n const content = readFile(comp.path);\n if (\n /carousel|accordion|typing|parallax|embla|swiper|collapsible/i.test(\n content\n )\n ) {\n interactive.push(`// ${comp.name}\\n${content}`);\n }\n }\n\n return interactive.join(\"\\n\\n\");\n }\n\n private findComponents(dir: string): { name: string; path: string }[] {\n const searchDirs = [\n join(dir, \"src/components/landing\"),\n join(dir, \"src/components/sections\"),\n join(dir, \"src/components\"),\n ];\n\n for (const searchDir of searchDirs) {\n if (!fileExists(searchDir)) continue;\n try {\n return readdirSync(searchDir)\n .filter(\n (f) =>\n (f.endsWith(\".tsx\") || f.endsWith(\".jsx\")) &&\n !f.startsWith(\"ui\") &&\n f !== \"index.tsx\" &&\n f !== \"index.jsx\"\n )\n .map((f) => ({\n name: f.replace(/\\.(tsx|jsx)$/, \"\"),\n path: join(searchDir, f),\n }));\n } catch {\n continue;\n }\n }\n\n return [];\n }\n\n private countFiles(mod: ModuleFiles): number {\n let count = 3; // fields.json, meta.json, module.html always present\n if (mod.moduleCss) count++;\n if (mod.moduleJs) count++;\n return count;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport { getConversionGuide } from \"./prompts.js\";\nimport { readFile, fileExists } from \"../utils/fs.js\";\n\nexport class GeminiCLIEngine implements AIEngine {\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, onProgress } = opts;\n const guide = opts.conversionGuide || getConversionGuide();\n\n const prompt = this.buildFullPrompt(sourceDir, themePath, guide);\n\n onProgress(\"convert\", \"Running Gemini CLI (this may take a few minutes)...\");\n\n // Use async spawn so the event loop stays free for spinner animation\n await new Promise<void>((resolve, reject) => {\n const child = spawn(\"gemini\", [\"-p\", prompt], {\n cwd: themePath,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n shell: true,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) => reject(new Error(`Gemini CLI failed: ${err.message}`)));\n child.on(\"close\", (code) => {\n if (code !== 0 && stderr && !stdout) {\n reject(new Error(`Gemini CLI failed: ${stderr}`));\n } else {\n resolve();\n }\n });\n\n setTimeout(() => {\n child.kill();\n reject(new Error(\"Gemini CLI timed out after 10 minutes\"));\n }, 600_000);\n });\n\n onProgress(\"scan\", \"Scanning generated files...\");\n\n return this.scanGeneratedFiles(themePath);\n }\n\n private buildFullPrompt(\n sourceDir: string,\n themePath: string,\n guide: string\n ): string {\n return `Read the conversion guide below, then convert the React landing page at ${sourceDir} into native HubSpot CMS modules for the theme at ${themePath}.\n\nINSTRUCTIONS:\n1. Analyze all .tsx/.jsx components in the React source\n2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures\n3. Create a shared JS file in js/ for scroll animations and interactive features\n4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css\n5. Add a styles group with \"tab\": \"STYLE\" and color pickers to each module\n6. Create a page template in templates/ that assembles all modules\n7. Make sure base.html supports template_css and template_js variables\n\nCONVERSION GUIDE:\n${guide}\n\nDo NOT run hs upload — I will handle that separately.\nCreate all files directly in the theme directory.`;\n }\n\n private scanGeneratedFiles(themePath: string): GeneratedAssets {\n const result: GeneratedAssets = {\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n modules: [],\n };\n\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (\n (file.includes(\"theme\") || file.includes(\"page\")) &&\n file.endsWith(\".css\") &&\n file !== \"theme-overrides.css\" &&\n file !== \"main.css\" &&\n file !== \"style.css\"\n ) {\n result.sharedCss = readFile(join(cssDir, file));\n break;\n }\n }\n }\n\n const jsDir = join(themePath, \"js\");\n if (fileExists(jsDir)) {\n for (const file of readdirSync(jsDir)) {\n if (\n (file.includes(\"animation\") || file.includes(\"page\")) &&\n file.endsWith(\".js\") &&\n file !== \"main.js\"\n ) {\n result.sharedJs = readFile(join(jsDir, file));\n break;\n }\n }\n }\n\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !file.startsWith(\"system\") &&\n file !== \"base.html\"\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const modDir = join(modulesDir, entry);\n if (!statSync(modDir).isDirectory()) continue;\n\n const moduleFiles: ModuleFiles = {\n moduleName: entry.replace(\".module\", \"\"),\n fieldsJson: \"\",\n metaJson: \"\",\n moduleHtml: \"\",\n moduleCss: \"\",\n };\n\n const fj = join(modDir, \"fields.json\");\n if (fileExists(fj)) moduleFiles.fieldsJson = readFile(fj);\n\n const mj = join(modDir, \"meta.json\");\n if (fileExists(mj)) moduleFiles.metaJson = readFile(mj);\n\n const mh = join(modDir, \"module.html\");\n if (fileExists(mh)) moduleFiles.moduleHtml = readFile(mh);\n\n const mc = join(modDir, \"module.css\");\n if (fileExists(mc)) moduleFiles.moduleCss = readFile(mc);\n\n const mjs = join(modDir, \"module.js\");\n if (fileExists(mjs)) moduleFiles.moduleJs = readFile(mjs);\n\n if (moduleFiles.fieldsJson && moduleFiles.moduleHtml) {\n result.modules.push(moduleFiles);\n }\n }\n }\n\n return result;\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport type { AIEngine, GeneratedAssets, ModuleFiles } from \"./engine.js\";\nimport { getConversionGuide } from \"./prompts.js\";\nimport { readFile, fileExists } from \"../utils/fs.js\";\n\nexport class CodexCLIEngine implements AIEngine {\n async convert(opts: {\n sourceDir: string;\n themePath: string;\n conversionGuide: string;\n onProgress: (step: string, detail: string) => void;\n }): Promise<GeneratedAssets> {\n const { sourceDir, themePath, onProgress } = opts;\n const guide = opts.conversionGuide || getConversionGuide();\n\n const prompt = this.buildFullPrompt(sourceDir, themePath, guide);\n\n onProgress(\"convert\", \"Running OpenAI Codex (this may take a few minutes)...\");\n\n // Use async spawn so the event loop stays free for spinner animation\n await new Promise<void>((resolve, reject) => {\n const child = spawn(\"codex\", [\"exec\", \"--full-auto\", prompt], {\n cwd: themePath,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n shell: true,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n child.stdout.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) => reject(new Error(`Codex CLI failed: ${err.message}`)));\n child.on(\"close\", (code) => {\n if (code !== 0 && stderr && !stdout) {\n reject(new Error(`Codex CLI failed: ${stderr}`));\n } else {\n resolve();\n }\n });\n\n setTimeout(() => {\n child.kill();\n reject(new Error(\"Codex CLI timed out after 10 minutes\"));\n }, 600_000);\n });\n\n onProgress(\"scan\", \"Scanning generated files...\");\n\n return this.scanGeneratedFiles(themePath);\n }\n\n private buildFullPrompt(\n sourceDir: string,\n themePath: string,\n guide: string\n ): string {\n return `Read the conversion guide below, then convert the React landing page at ${sourceDir} into native HubSpot CMS modules for the theme at ${themePath}.\n\nINSTRUCTIONS:\n1. Analyze all .tsx/.jsx components in the React source\n2. Create a shared CSS file in css/ with design system variables, utilities, and theme-override countermeasures\n3. Create a shared JS file in js/ for scroll animations and interactive features\n4. For each visual section, create a HubSpot module in modules/ with fields.json, meta.json, module.html, module.css\n5. Add a styles group with \"tab\": \"STYLE\" and color pickers to each module\n6. Create a page template in templates/ that assembles all modules\n7. Make sure base.html supports template_css and template_js variables\n\nCONVERSION GUIDE:\n${guide}\n\nDo NOT run hs upload — I will handle that separately.\nCreate all files directly in the theme directory.`;\n }\n\n private scanGeneratedFiles(themePath: string): GeneratedAssets {\n const result: GeneratedAssets = {\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n modules: [],\n };\n\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (\n (file.includes(\"theme\") || file.includes(\"page\")) &&\n file.endsWith(\".css\") &&\n file !== \"theme-overrides.css\" &&\n file !== \"main.css\" &&\n file !== \"style.css\"\n ) {\n result.sharedCss = readFile(join(cssDir, file));\n break;\n }\n }\n }\n\n const jsDir = join(themePath, \"js\");\n if (fileExists(jsDir)) {\n for (const file of readdirSync(jsDir)) {\n if (\n (file.includes(\"animation\") || file.includes(\"page\")) &&\n file.endsWith(\".js\") &&\n file !== \"main.js\"\n ) {\n result.sharedJs = readFile(join(jsDir, file));\n break;\n }\n }\n }\n\n const templatesDir = join(themePath, \"templates\");\n if (fileExists(templatesDir)) {\n for (const file of readdirSync(templatesDir)) {\n if (\n file.endsWith(\".html\") &&\n !file.startsWith(\"system\") &&\n file !== \"base.html\"\n ) {\n const content = readFile(join(templatesDir, file));\n if (content.includes(\"dnd_area\")) {\n result.template = content;\n break;\n }\n }\n }\n }\n\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const modDir = join(modulesDir, entry);\n if (!statSync(modDir).isDirectory()) continue;\n\n const moduleFiles: ModuleFiles = {\n moduleName: entry.replace(\".module\", \"\"),\n fieldsJson: \"\",\n metaJson: \"\",\n moduleHtml: \"\",\n moduleCss: \"\",\n };\n\n const fj = join(modDir, \"fields.json\");\n if (fileExists(fj)) moduleFiles.fieldsJson = readFile(fj);\n\n const mj = join(modDir, \"meta.json\");\n if (fileExists(mj)) moduleFiles.metaJson = readFile(mj);\n\n const mh = join(modDir, \"module.html\");\n if (fileExists(mh)) moduleFiles.moduleHtml = readFile(mh);\n\n const mc = join(modDir, \"module.css\");\n if (fileExists(mc)) moduleFiles.moduleCss = readFile(mc);\n\n const mjs = join(modDir, \"module.js\");\n if (fileExists(mjs)) moduleFiles.moduleJs = readFile(mjs);\n\n if (moduleFiles.fieldsJson && moduleFiles.moduleHtml) {\n result.modules.push(moduleFiles);\n }\n }\n }\n\n return result;\n }\n}\n","import { join, basename } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\nimport {\n parseUploadErrors,\n parseApiErrors,\n autoFixError,\n type UploadError,\n} from \"../server/auto-fix.js\";\nimport { loadConfig, getHubSpotPak } from \"../utils/config.js\";\nimport { uploadTheme, deleteFile } from \"../hubspot/uploader.js\";\n\n/** Count \"Uploaded file\" lines in hs cms upload output */\nfunction countUploadedFiles(output: string): number {\n return (output.match(/^Uploaded file /gm) || []).length;\n}\n\nexport async function runUpload(themePath: string): Promise<boolean> {\n await ui.intro(\"Uploading to HubSpot\");\n\n const themeName = basename(themePath) || themePath;\n const config = loadConfig();\n const pak = getHubSpotPak();\n const useApi = config.hubspotUploadMode !== \"cli\" && !!pak;\n const s = await ui.spinner();\n\n const MAX_RETRIES = 3;\n\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n s.start(\n attempt === 1\n ? \"Uploading theme...\"\n : `Retrying upload (attempt ${attempt}/${MAX_RETRIES})...`\n );\n\n let errors: UploadError[] = [];\n let uploadedCount = 0;\n let success = false;\n\n if (useApi) {\n // API mode — parallel upload\n const result = await uploadTheme(pak!, themePath, themeName, {\n onFileComplete: () => { uploadedCount++; },\n });\n success = result.success;\n if (!success) {\n errors = parseApiErrors(result.errors);\n } else {\n uploadedCount = result.uploaded;\n }\n } else {\n // CLI mode\n const result = run(`hs cms upload \"${themePath}\" \"${themeName}\"`, {\n cwd: join(themePath, \"..\"),\n });\n const fullOutput = [result.stdout, result.stderr].filter(Boolean).join(\"\\n\");\n uploadedCount = countUploadedFiles(fullOutput);\n success = result.success;\n if (!success) {\n errors = parseUploadErrors(fullOutput);\n }\n }\n\n if (success) {\n s.stop(`All files uploaded! (${uploadedCount} files)`);\n await ui.outro(\"Upload complete!\");\n return true;\n }\n\n if (uploadedCount > 0) {\n s.stop(`${uploadedCount} files uploaded, but some errors occurred`);\n } else {\n s.stop(\"Upload failed\");\n }\n\n if (errors.length === 0) {\n ui.logError(\"Upload failed with unknown error.\");\n\n if (uploadedCount > 0) {\n ui.logWarn(\n \"Most files uploaded successfully. The theme may already be usable in HubSpot.\\n\" +\n \"You can check your HubSpot Design Manager to verify.\"\n );\n const proceed = await ui.confirm({\n message: \"Continue anyway (theme is likely uploaded)?\",\n initialValue: true,\n });\n if (proceed) return true;\n }\n\n if (attempt < MAX_RETRIES) {\n const retry = await ui.confirm({ message: \"Try uploading again?\" });\n if (!retry) break;\n continue;\n }\n break;\n }\n\n // Try to auto-fix known errors\n let anyFixed = false;\n for (const error of errors) {\n if (error.fixable) {\n const fixed = autoFixError(themePath, error);\n if (fixed) {\n ui.logSuccess(`Auto-fixed: ${error.message}`);\n anyFixed = true;\n } else {\n ui.logWarn(`Could not auto-fix: ${error.message}`);\n }\n } else {\n ui.logError(error.message);\n }\n }\n\n if (anyFixed && attempt < MAX_RETRIES) continue;\n\n if (uploadedCount > 0) {\n ui.logWarn(\n `${uploadedCount} files uploaded successfully despite errors.\\n` +\n \"The theme may work — check HubSpot Design Manager.\"\n );\n const proceed = await ui.confirm({\n message: \"Continue anyway?\",\n initialValue: true,\n });\n if (proceed) return true;\n }\n\n if (!anyFixed) {\n s.start(\"Cleaning up stuck modules...\");\n if (useApi) {\n try { await deleteFile(pak!, `${themeName}/modules`); } catch { /* ignore */ }\n } else {\n run(`hs cms delete \"${themeName}/modules\"`, { cwd: join(themePath, \"..\") });\n }\n s.stop(\"Cleaned up modules, retrying...\");\n }\n }\n\n ui.logError(\"Upload failed after multiple attempts.\");\n return false;\n}\n","/**\n * Auto-fix utilities for common HubSpot upload errors.\n * Shared between CLI wizard (uploader.ts) and web server (server.ts).\n */\n\nimport { join } from \"node:path\";\nimport { readdirSync, rmSync } from \"node:fs\";\nimport { readFile, writeFile, fileExists } from \"../utils/fs.js\";\n\nexport interface UploadError {\n file: string;\n message: string;\n fixable: boolean;\n}\n\n/** Parse API upload errors into the standard UploadError interface. */\nexport function parseApiErrors(apiErrors: { file: string; status: number; message: string; category?: string; detail?: string }[]): UploadError[] {\n const errors: UploadError[] = [];\n\n for (const err of apiErrors) {\n const msg = `${err.message}${err.detail ? ` — ${err.detail}` : \"\"}`;\n let fixable = false;\n\n // Detect fixable error patterns from API response messages\n if (/textarea|unknown.*field.*type/i.test(msg)) fixable = true;\n if (/reserved.*name|missing field name|field null/i.test(msg)) fixable = true;\n if (/could not resolve.*now/i.test(msg)) fixable = true;\n if (/hubdb|do not have access/i.test(msg)) fixable = true;\n if (/invalid default value|link.*invalid|deserializ/i.test(msg)) fixable = true;\n if (/color.*invalid/i.test(msg)) fixable = true;\n\n errors.push({\n file: err.file || \"unknown\",\n message: msg,\n fixable,\n });\n }\n\n return errors;\n}\n\nexport function parseUploadErrors(output: string): UploadError[] {\n const errors: UploadError[] = [];\n\n if (/textarea.*not.*valid|unknown.*field.*type/i.test(output)) {\n const fileMatch = output.match(/(?:in|file:?)\\s+(\\S+fields\\.json)/i);\n errors.push({\n file: fileMatch?.[1] || \"fields.json\",\n message: '\"textarea\" is not a valid field type',\n fixable: true,\n });\n }\n\n if (/missing field name|field null/i.test(output)) {\n const fileMatch = output.match(/(?:in|file:?)\\s+(\\S+fields\\.json)/i);\n errors.push({\n file: fileMatch?.[1] || \"fields.json\",\n message: '\"name\" is a reserved field name',\n fixable: true,\n });\n }\n\n if (/could not resolve.*now/i.test(output)) {\n errors.push({\n file: \"module.html\",\n message: \"now() is not a valid HubL function\",\n fixable: true,\n });\n }\n\n if (/hubdb|do not have access to hubdb/i.test(output)) {\n errors.push({\n file: \"templates\",\n message: \"HubDB requires CMS Hub Pro/Enterprise\",\n fixable: true,\n });\n }\n\n if (/invalid default value|link.*field.*invalid/i.test(output)) {\n const fieldMatch = output.match(/field.*?(\\w+)\\s+has an invalid/i);\n errors.push({\n file: fieldMatch?.[1] || \"fields.json\",\n message: `Link field has invalid default value`,\n fixable: true,\n });\n }\n\n if (/failed to deserialize/i.test(output)) {\n const fileMatch = output.match(/file '([^']+)'/i);\n errors.push({\n file: fileMatch?.[1] || \"fields.json\",\n message: \"fields.json deserialization error\",\n fixable: true,\n });\n }\n\n if (/format for the color value is invalid/i.test(output)) {\n errors.push({\n file: \"fields.json\",\n message: \"Color field has invalid format (rgba/rgb/named — must be hex)\",\n fixable: true,\n });\n }\n\n return errors;\n}\n\nexport function applyAutoFixes(themePath: string): string[] {\n const fixes: string[] = [];\n if (fixTextareaFields(themePath)) fixes.push('textarea → text');\n if (fixReservedNames(themePath)) fixes.push('name → item_name');\n if (fixNowFunction(themePath)) fixes.push('now() → local_dt');\n if (fixHubDbTemplates(themePath)) fixes.push('Removed HubDB templates');\n if (fixLinkFieldDefaults(themePath)) fixes.push('Fixed link field defaults');\n if (fixColorFieldDefaults(themePath)) fixes.push('Fixed rgba/invalid color values → hex');\n if (fixCdnImports(themePath)) fixes.push('Stripped CDN @import statements');\n return fixes;\n}\n\nexport function autoFixError(themePath: string, error: UploadError): boolean {\n if (error.message.includes(\"textarea\")) return fixTextareaFields(themePath);\n if (error.message.includes(\"reserved field name\")) return fixReservedNames(themePath);\n if (error.message.includes(\"now()\")) return fixNowFunction(themePath);\n if (error.message.includes(\"HubDB\")) return fixHubDbTemplates(themePath);\n if (error.message.includes(\"invalid default value\") || error.message.includes(\"deserialization\"))\n return fixLinkFieldDefaults(themePath);\n if (error.message.includes(\"invalid format\") && error.message.includes(\"color\"))\n return fixColorFieldDefaults(themePath);\n return false;\n}\n\nexport function fixTextareaFields(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n let content = readFile(fieldsPath);\n if (content.includes('\"textarea\"')) {\n content = content.replace(/\"textarea\"/g, '\"text\"');\n writeFile(fieldsPath, content);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixReservedNames(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n let content = readFile(fieldsPath);\n if (/\"name\":\\s*\"name\"/g.test(content)) {\n content = content.replace(/\"name\":\\s*\"name\"/g, '\"name\": \"item_name\"');\n writeFile(fieldsPath, content);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixNowFunction(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const htmlPath = join(modulesDir, entry, \"module.html\");\n if (!fileExists(htmlPath)) continue;\n let content = readFile(htmlPath);\n if (content.includes(\"now()\")) {\n content = content.replace(/now\\(\\)/g, \"local_dt\");\n writeFile(htmlPath, content);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixHubDbTemplates(themePath: string): boolean {\n let fixed = false;\n const templatesDir = join(themePath, \"templates\");\n if (!fileExists(templatesDir)) return false;\n\n for (const file of readdirSync(templatesDir)) {\n if (!file.endsWith(\".html\")) continue;\n const filePath = join(templatesDir, file);\n const content = readFile(filePath);\n if (content.includes(\"hubdb_table\") || content.includes(\"hubdb_table_rows\")) {\n rmSync(filePath);\n fixed = true;\n }\n }\n return fixed;\n}\n\nexport function fixLinkFieldDefaults(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n try {\n const fields = JSON.parse(readFile(fieldsPath));\n if (fixLinkFieldsRecursive(fields)) {\n writeFile(fieldsPath, JSON.stringify(fields, null, 2) + \"\\n\");\n fixed = true;\n }\n } catch {\n // Skip malformed JSON\n }\n }\n return fixed;\n}\n\n/**\n * Strip external CDN @import statements from all CSS files.\n * Google Fonts and other CDN imports can fail in HubSpot's editor\n * and cause content to appear invisible.\n */\nexport function fixCdnImports(themePath: string): boolean {\n let fixed = false;\n\n // Check shared CSS files\n const cssDir = join(themePath, \"css\");\n if (fileExists(cssDir)) {\n for (const file of readdirSync(cssDir)) {\n if (!file.endsWith(\".css\")) continue;\n const filePath = join(cssDir, file);\n let content = readFile(filePath);\n const cleaned = content.replace(/@import\\s+url\\(['\"]?https?:\\/\\/[^)]+['\"]?\\)\\s*;?/gi, \"\");\n if (cleaned !== content) {\n writeFile(filePath, cleaned);\n fixed = true;\n }\n }\n }\n\n // Check module CSS files\n const modulesDir = join(themePath, \"modules\");\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const cssPath = join(modulesDir, entry, \"module.css\");\n if (!fileExists(cssPath)) continue;\n let content = readFile(cssPath);\n const cleaned = content.replace(/@import\\s+url\\(['\"]?https?:\\/\\/[^)]+['\"]?\\)\\s*;?/gi, \"\");\n if (cleaned !== content) {\n writeFile(cssPath, cleaned);\n fixed = true;\n }\n }\n }\n\n // Check module HTML for <link> tags to external CDNs\n if (fileExists(modulesDir)) {\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const htmlPath = join(modulesDir, entry, \"module.html\");\n if (!fileExists(htmlPath)) continue;\n let content = readFile(htmlPath);\n const cleaned = content.replace(/<link[^>]+href=['\"]https?:\\/\\/[^'\"]+['\"][^>]*>/gi, \"\");\n if (cleaned !== content) {\n writeFile(htmlPath, cleaned);\n fixed = true;\n }\n }\n }\n\n return fixed;\n}\n\n/**\n * Fix color fields that use rgba(), rgb(), named colors, or 3-digit hex.\n * HubSpot requires: { \"color\": \"#rrggbb\", \"opacity\": 100 }\n */\nexport function fixColorFieldDefaults(themePath: string): boolean {\n let fixed = false;\n const modulesDir = join(themePath, \"modules\");\n if (!fileExists(modulesDir)) return false;\n\n for (const entry of readdirSync(modulesDir)) {\n if (!entry.endsWith(\".module\")) continue;\n const fieldsPath = join(modulesDir, entry, \"fields.json\");\n if (!fileExists(fieldsPath)) continue;\n try {\n const fields = JSON.parse(readFile(fieldsPath));\n if (fixColorFieldsRecursive(fields)) {\n writeFile(fieldsPath, JSON.stringify(fields, null, 2) + \"\\n\");\n fixed = true;\n }\n } catch {\n // Skip malformed JSON\n }\n }\n return fixed;\n}\n\nfunction fixColorFieldsRecursive(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"color\" && f.default && typeof f.default === \"object\") {\n const def = f.default as Record<string, unknown>;\n const colorVal = def.color;\n if (typeof colorVal === \"string\" && !isValidHexColor(colorVal)) {\n const converted = convertToHex(colorVal);\n if (converted) {\n def.color = converted.hex;\n // If the rgba had opacity, use that instead of the existing opacity\n if (converted.opacity !== undefined) {\n def.opacity = converted.opacity;\n }\n fixed = true;\n }\n }\n }\n\n if (Array.isArray(f.children)) {\n if (fixColorFieldsRecursive(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n\nfunction isValidHexColor(color: string): boolean {\n return /^#[0-9a-fA-F]{6}$/.test(color);\n}\n\nfunction convertToHex(color: string): { hex: string; opacity?: number } | null {\n // 3-digit hex → 6-digit\n const hex3 = color.match(/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/);\n if (hex3) {\n return { hex: `#${hex3[1]}${hex3[1]}${hex3[2]}${hex3[2]}${hex3[3]}${hex3[3]}` };\n }\n\n // rgba(r, g, b, a)\n const rgba = color.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*([\\d.]+))?\\s*\\)/i);\n if (rgba) {\n const r = Math.min(255, parseInt(rgba[1]));\n const g = Math.min(255, parseInt(rgba[2]));\n const b = Math.min(255, parseInt(rgba[3]));\n const hex = `#${r.toString(16).padStart(2, \"0\")}${g.toString(16).padStart(2, \"0\")}${b.toString(16).padStart(2, \"0\")}`;\n const opacity = rgba[4] !== undefined ? Math.round(parseFloat(rgba[4]) * 100) : undefined;\n return { hex, opacity };\n }\n\n // Named colors (common ones)\n const named: Record<string, string> = {\n white: \"#ffffff\", black: \"#000000\", red: \"#ff0000\", green: \"#008000\",\n blue: \"#0000ff\", yellow: \"#ffff00\", orange: \"#ffa500\", purple: \"#800080\",\n gray: \"#808080\", grey: \"#808080\", transparent: \"#000000\",\n };\n const lower = color.toLowerCase().trim();\n if (named[lower]) {\n return { hex: named[lower], opacity: lower === \"transparent\" ? 0 : undefined };\n }\n\n return null;\n}\n\nfunction fixLinkFieldsRecursive(fields: unknown[]): boolean {\n let fixed = false;\n for (const field of fields) {\n if (typeof field !== \"object\" || field === null) continue;\n const f = field as Record<string, unknown>;\n\n if (f.type === \"link\") {\n const def = f.default;\n const needsFix =\n typeof def === \"string\" ||\n def === undefined ||\n def === null ||\n (typeof def === \"object\" && !(def as Record<string, unknown>).url);\n\n if (needsFix) {\n const href = typeof def === \"string\" ? def : \"\";\n f.default = {\n url: { href, type: \"EXTERNAL\" },\n open_in_new_tab: false,\n no_follow: false,\n };\n fixed = true;\n }\n }\n\n if (Array.isArray(f.children)) {\n if (fixLinkFieldsRecursive(f.children as unknown[])) fixed = true;\n }\n }\n return fixed;\n}\n","/**\n * Parallel theme uploader — walks a theme directory and uploads all files\n * to HubSpot via the CMS Source Code API v3.\n */\n\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport { uploadFile, type HubSpotApiError, type UploadResult } from \"./api.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UploadFileError {\n file: string;\n status: number;\n message: string;\n category?: string;\n detail?: string;\n}\n\nexport interface UploadThemeResult {\n success: boolean;\n uploaded: number;\n failed: number;\n total: number;\n errors: UploadFileError[];\n}\n\nexport interface UploadThemeOptions {\n concurrency?: number;\n onFileStart?: (path: string) => void;\n onFileComplete?: (path: string) => void;\n onFileError?: (path: string, error: UploadFileError) => void;\n onProgress?: (completed: number, total: number) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Excluded directories\n// ---------------------------------------------------------------------------\n\nconst EXCLUDED_DIRS = new Set([\".git\", \"node_modules\", \".vibespot\", \".DS_Store\"]);\n\n// ---------------------------------------------------------------------------\n// File discovery\n// ---------------------------------------------------------------------------\n\n/** Recursively walk a directory and return all file paths. */\nfunction walkDir(dir: string): string[] {\n const files: string[] = [];\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (EXCLUDED_DIRS.has(entry.name)) continue;\n if (entry.name.startsWith(\".\") && entry.name !== \".gitkeep\") continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isDirectory()) {\n files.push(...walkDir(fullPath));\n } else if (entry.isFile()) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\n// ---------------------------------------------------------------------------\n// Parallel upload\n// ---------------------------------------------------------------------------\n\n/** Run async tasks with bounded concurrency. */\nasync function parallelMap<T>(\n items: T[],\n concurrency: number,\n fn: (item: T) => Promise<void>,\n): Promise<void> {\n let index = 0;\n\n async function worker(): Promise<void> {\n while (index < items.length) {\n const i = index++;\n await fn(items[i]);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n}\n\n// ---------------------------------------------------------------------------\n// Main upload function\n// ---------------------------------------------------------------------------\n\n/**\n * Upload an entire theme directory to HubSpot.\n * Files are uploaded in parallel with configurable concurrency.\n */\nexport async function uploadTheme(\n pak: string,\n themePath: string,\n themeName: string,\n opts: UploadThemeOptions = {},\n): Promise<UploadThemeResult> {\n const concurrency = opts.concurrency ?? 5;\n\n // Discover all files\n const localFiles = walkDir(themePath);\n const total = localFiles.length;\n let uploaded = 0;\n let failed = 0;\n const errors: UploadFileError[] = [];\n\n await parallelMap(localFiles, concurrency, async (localPath) => {\n // Map local path to remote path: themeName/relative/path\n const rel = relative(themePath, localPath).replace(/\\\\/g, \"/\");\n const remotePath = `${themeName}/${rel}`;\n\n opts.onFileStart?.(rel);\n\n const result = await uploadFile(pak, remotePath, localPath);\n\n if (result.success) {\n uploaded++;\n opts.onFileComplete?.(rel);\n } else {\n failed++;\n const err: UploadFileError = {\n file: rel,\n status: result.error?.status || 0,\n message: result.error?.message || \"Unknown error\",\n category: result.error?.category,\n detail: result.error?.detail,\n };\n errors.push(err);\n opts.onFileError?.(rel, err);\n }\n\n opts.onProgress?.(uploaded + failed, total);\n });\n\n return {\n success: failed === 0,\n uploaded,\n failed,\n total,\n errors,\n };\n}\n\n/**\n * Delete a remote path (used for cleaning up stuck modules).\n */\nexport { deleteFile } from \"./api.js\";\n","import { execSync } from \"node:child_process\";\nimport { rmSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\nimport { detectDataCenter } from \"../utils/detect.js\";\nimport { fileExists } from \"../utils/fs.js\";\n\nexport async function showNextSteps(opts: {\n portalId: string;\n sourceDir: string;\n themePath: string;\n wasCloned: boolean;\n}): Promise<void> {\n const { portalId, sourceDir, themePath, wasCloned } = opts;\n await ui.intro(\"You're all set!\");\n\n const dataCenter = detectDataCenter(portalId);\n const host =\n dataCenter === \"eu1\" ? \"app-eu1.hubspot.com\" : \"app.hubspot.com\";\n\n await ui.note(\n `Your React page has been converted and uploaded to HubSpot.\\n` +\n `The theme and modules are now in your account, but you still\\n` +\n `need to ${theme.bold(\"create a new landing page\")} that uses them.\\n\\n` +\n `Next steps:\\n\\n` +\n ` ${theme.bold(\"1.\")} Go to HubSpot ${theme.muted(\"→\")} Content ${theme.muted(\"→\")} Landing Pages ${theme.muted(\"→\")} Create\\n` +\n ` ${theme.bold(\"2.\")} Choose your uploaded theme from the theme picker\\n` +\n ` ${theme.bold(\"3.\")} Select the landing page template that was just created\\n` +\n ` ${theme.bold(\"4.\")} Your converted modules will appear — drag them onto the page\\n` +\n ` ${theme.bold(\"5.\")} Click each section to edit text, images, and colors\\n` +\n ` ${theme.bold(\"6.\")} Upload images via File Manager ${theme.muted(\"(Settings → Files)\")}\\n` +\n ` ${theme.bold(\"7.\")} Preview and publish!`,\n \"What's next\"\n );\n\n const openBrowser = await ui.confirm({\n message: \"Open HubSpot Landing Pages in your browser?\",\n });\n\n if (openBrowser) {\n const url = portalId\n ? `https://${host}/page-ui/${portalId}/management/pages/landing`\n : `https://${host}`;\n\n try {\n // Cross-platform browser open\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(`open \"${url}\"`);\n } else if (platform === \"win32\") {\n execSync(`cmd /c start \"${url}\"`);\n } else {\n execSync(`xdg-open \"${url}\"`);\n }\n ui.logSuccess(\"Opening HubSpot Landing Pages...\");\n } catch {\n ui.log(`Open this URL in your browser: ${theme.info(url)}`);\n }\n }\n\n // Offer to clean up local directories\n const dirsToClean: { path: string; label: string }[] = [];\n if (wasCloned && fileExists(sourceDir)) {\n dirsToClean.push({ path: sourceDir, label: `Cloned source (${basename(sourceDir)})` });\n }\n if (fileExists(themePath)) {\n dirsToClean.push({ path: themePath, label: `Theme directory (${basename(themePath)})` });\n }\n\n if (dirsToClean.length > 0) {\n const cleanup = await ui.confirm({\n message: \"Clean up local working directories?\",\n });\n\n if (cleanup) {\n for (const dir of dirsToClean) {\n try {\n rmSync(dir.path, { recursive: true, force: true });\n ui.logSuccess(`Removed ${dir.label}`);\n } catch {\n ui.logWarn(`Could not remove ${dir.label} — delete manually if needed.`);\n }\n }\n }\n }\n\n await ui.outro(`Thanks for using hub${theme.vibes(\"Vibes\")}! ${theme.vibes(\"~\")}`);\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { runPreflight } from \"../wizard/preflight.js\";\nimport { setupSource } from \"../wizard/source.js\";\nimport { setupTheme } from \"../wizard/theme-setup.js\";\nimport { runConversion } from \"../wizard/conversion.js\";\nimport { runUpload } from \"../wizard/uploader.js\";\nimport { showNextSteps } from \"../wizard/next-steps.js\";\nimport { saveConfig } from \"../utils/config.js\";\n\nexport async function wizardCommand(): Promise<void> {\n printBanner();\n\n // Step 1: Preflight checks\n const preflight = await runPreflight();\n\n // Step 2: Source setup\n const source = await setupSource();\n saveConfig({ lastSourcePath: source.sourceDir });\n\n // Step 3: Theme setup\n const themeInfo = await setupTheme();\n saveConfig({ lastThemePath: themeInfo.themePath });\n\n // Step 4: AI conversion\n await runConversion({\n aiEngine: preflight.aiEngine,\n model: preflight.model,\n sourceDir: source.sourceDir,\n themePath: themeInfo.themePath,\n });\n\n // Step 5: Upload\n await runUpload(themeInfo.themePath);\n\n // Step 6: Next steps + optional cleanup\n await showNextSteps({\n portalId: preflight.portalId,\n sourceDir: source.sourceDir,\n themePath: themeInfo.themePath,\n wasCloned: source.wasCloned,\n });\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { runPreflight } from \"../wizard/preflight.js\";\n\nexport async function initCommand(): Promise<void> {\n printBanner();\n await runPreflight();\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { setupSource } from \"../wizard/source.js\";\nimport { setupTheme } from \"../wizard/theme-setup.js\";\nimport { runConversion } from \"../wizard/conversion.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\n\nexport async function convertCommand(): Promise<void> {\n printBanner();\n\n const config = loadConfig();\n\n if (!config.aiEngine) {\n ui.logError(\n \"AI engine not configured. Run `vibespot init` first or use the full wizard with `vibespot`.\"\n );\n process.exit(1);\n }\n\n const source = await setupSource();\n const themeInfo = await setupTheme();\n\n await runConversion({\n aiEngine: config.aiEngine,\n sourceDir: source.sourceDir,\n themePath: themeInfo.themePath,\n });\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport { runUpload } from \"../wizard/uploader.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\n\nexport async function uploadCommand(): Promise<void> {\n printBanner();\n\n const config = loadConfig();\n\n if (!config.lastThemePath) {\n const path = await ui.text({\n message: \"Path to your HubSpot theme directory:\",\n placeholder: \"./my-theme\",\n validate: (v) => (v.trim() ? undefined : \"Path is required\"),\n });\n await runUpload(path);\n } else {\n const useLast = await ui.confirm({\n message: `Upload from ${config.lastThemePath}?`,\n });\n\n if (useLast) {\n await runUpload(config.lastThemePath);\n } else {\n const path = await ui.text({\n message: \"Path to your HubSpot theme directory:\",\n placeholder: \"./my-theme\",\n });\n await runUpload(path);\n }\n }\n}\n","import { printBanner } from \"../cli/banner.js\";\nimport {\n detectNode,\n detectGit,\n detectHubSpotCLI,\n detectClaudeCode,\n detectGeminiCLI,\n detectCodexCLI,\n detectHubSpotAuth,\n nodeVersionOk,\n hsCliVersionOk,\n} from \"../utils/detect.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport * as ui from \"../prompts/prompter.js\";\nimport { theme } from \"../cli/theme.js\";\n\nexport async function doctorCommand(): Promise<void> {\n printBanner();\n await ui.intro(\"Environment Diagnostics\");\n\n let issues = 0;\n\n // Node.js\n const node = detectNode();\n if (!node.found) {\n ui.logError(\"Node.js — not installed\");\n ui.log(\" Install from https://nodejs.org\");\n issues++;\n } else if (!nodeVersionOk(node.version)) {\n ui.logWarn(`Node.js v${node.version} — too old (need 18+)`);\n ui.log(\" Update at https://nodejs.org\");\n issues++;\n } else {\n ui.logSuccess(`Node.js v${node.version}`);\n }\n\n // Git\n const git = detectGit();\n if (!git.found) {\n ui.logError(\"Git — not installed\");\n ui.log(\" Install from https://git-scm.com\");\n issues++;\n } else {\n ui.logSuccess(`Git ${git.version}`);\n }\n\n // HubSpot CLI (only needed for deployment)\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n ui.logWarn(\"HubSpot CLI — not installed (only needed for deployment)\");\n ui.log(\" Install: npm install -g @hubspot/cli\");\n } else if (!hsCliVersionOk(hs.version)) {\n ui.logWarn(`HubSpot CLI v${hs.version} — too old (need v8+)`);\n ui.log(\" Update: npm install -g @hubspot/cli@latest\");\n issues++;\n } else {\n ui.logSuccess(`HubSpot CLI v${hs.version}`);\n\n // HubSpot auth\n const auth = detectHubSpotAuth();\n if (!auth.authenticated) {\n ui.logWarn(\"HubSpot — not authenticated\");\n ui.log(\" Run: hs init\");\n } else {\n ui.logSuccess(\n `HubSpot portal${auth.portalName ? `: ${auth.portalName}` : \"\"} (ID: ${auth.portalId})`\n );\n }\n }\n\n // AI engines\n const claude = detectClaudeCode();\n if (claude.found) {\n ui.logSuccess(`Claude Code ${claude.version} at ${claude.path}`);\n } else {\n ui.log(theme.muted(\"Claude Code — not installed\"));\n }\n\n const gemini = detectGeminiCLI();\n if (gemini.found) {\n ui.logSuccess(`Gemini CLI ${gemini.version} at ${gemini.path}`);\n } else {\n ui.log(theme.muted(\"Gemini CLI — not installed\"));\n }\n\n const codex = detectCodexCLI();\n if (codex.found) {\n ui.logSuccess(`OpenAI Codex ${codex.version} at ${codex.path}`);\n } else {\n ui.log(theme.muted(\"OpenAI Codex — not installed\"));\n }\n\n // API keys\n const config = loadConfig();\n\n const anthropicKey = !!(config.anthropicApiKey || process.env.ANTHROPIC_API_KEY);\n const openaiKey = !!(config.openaiApiKey || process.env.OPENAI_API_KEY);\n const geminiKey = !!(config.geminiApiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY);\n\n if (anthropicKey) ui.logSuccess(\"Anthropic API key configured\");\n else ui.log(theme.muted(\"Anthropic API key — not set\"));\n\n if (openaiKey) ui.logSuccess(\"OpenAI API key configured\");\n else ui.log(theme.muted(\"OpenAI API key — not set\"));\n\n if (geminiKey) ui.logSuccess(\"Google AI API key configured\");\n else ui.log(theme.muted(\"Google AI API key — not set\"));\n const engineLabels: Record<string, string> = {\n \"claude-code\": \"Claude Code\",\n \"api\": \"Anthropic API\",\n \"anthropic-api\": \"Anthropic API\",\n \"openai-api\": \"OpenAI API\",\n \"gemini-api\": \"Gemini API\",\n \"gemini-cli\": \"Gemini CLI\",\n \"codex-cli\": \"OpenAI Codex\",\n };\n if (config.aiEngine) {\n ui.logSuccess(`AI engine: ${engineLabels[config.aiEngine] || config.aiEngine}`);\n }\n if (config.lastThemePath) {\n ui.log(theme.muted(`Last theme: ${config.lastThemePath}`));\n }\n\n // No AI option available\n if (!claude.found && !gemini.found && !codex.found && !anthropicKey && !openaiKey && !geminiKey) {\n ui.logWarn(\"No AI engine available\");\n ui.log(\" Fastest: Set an API key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY)\");\n ui.log(\" Or install: Claude Code — https://claude.ai/code\");\n ui.log(\" Gemini CLI — https://github.com/google-gemini/gemini-cli\");\n ui.log(\" Codex CLI — https://github.com/openai/codex\");\n issues++;\n }\n\n console.log();\n if (issues === 0) {\n await ui.outro(\"Everything looks good!\");\n } else {\n await ui.outro(\n theme.warn(`${issues} issue${issues > 1 ? \"s\" : \"\"} found — see above`)\n );\n }\n}\n","/**\n * `vibespot vibe` — Vibe coding mode.\n * Immediately starts a local server and opens the browser.\n * All setup happens in the web UI — zero CLI prompts.\n */\n\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport { startServer } from \"../server/server.js\";\nimport { saveSession } from \"../server/session.js\";\n\nconst DEFAULT_PORT = 4200;\n\nexport async function vibeCommand(): Promise<void> {\n const accent = chalk.hex(\"#e8613a\");\n const dim = chalk.dim;\n\n console.log(\"\");\n console.log(accent(\" v vibeSpot\"));\n console.log(dim(\" Starting...\\n\"));\n\n const uiDir = resolveUiDir();\n if (!uiDir) {\n console.error(chalk.red(\" Could not find UI assets. Is the package installed correctly?\"));\n process.exit(1);\n }\n\n try {\n const { port, close } = await startServer({ port: DEFAULT_PORT, uiDir });\n const url = `http://localhost:${port}`;\n\n console.log(accent(` v ${url}`));\n console.log(dim(\" Press Ctrl+C to stop\\n\"));\n\n // Auto-open browser\n try {\n if (process.platform === \"darwin\") {\n execSync(`open \"${url}\"`, { stdio: \"ignore\" });\n } else if (process.platform === \"win32\") {\n execSync(`cmd /c start \"\" \"${url}\"`, { stdio: \"ignore\" });\n } else {\n execSync(`xdg-open \"${url}\"`, { stdio: \"ignore\" });\n }\n } catch {\n // Browser open failed — user can open manually\n }\n\n // Keep running until Ctrl+C\n await new Promise<void>((resolve) => {\n process.on(\"SIGINT\", () => {\n console.log(dim(\"\\n Saving session...\"));\n saveSession();\n close();\n console.log(dim(\" Goodbye!\\n\"));\n resolve();\n });\n });\n } catch (err) {\n console.error(chalk.red(` Failed to start: ${err instanceof Error ? err.message : String(err)}`));\n process.exit(1);\n }\n}\n\nfunction resolveUiDir(): string | null {\n const candidates = [\n join(import.meta.dirname, \"../../ui\"),\n join(import.meta.dirname, \"../ui\"),\n join(process.cwd(), \"ui\"),\n ];\n\n for (const dir of candidates) {\n if (existsSync(join(dir, \"index.html\"))) return dir;\n }\n\n return null;\n}\n","/**\n * Local development server for vibeSpot vibe coding mode.\n * Serves the UI, handles WebSocket connections, and manages AI interactions.\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from \"node:http\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { join, extname } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport {\n getSession,\n addMessage,\n getOrderedModules,\n writeModulesToDisk,\n saveSession,\n getActiveTemplate,\n} from \"./session.js\";\nimport { commitThemeState, commitTemplateState, isGitAvailable } from \"./project-git.js\";\nimport { buildPreviewHtml, buildModulePreviewHtml } from \"./preview.js\";\nimport { handleGenerateStream, setParseWarningCallback } from \"./ai-handler.js\";\nimport { loadConfig, getHubSpotPak, getActiveHubSpotAccount } from \"../utils/config.js\";\nimport { detectHubSpotAuth, detectDataCenter, detectHubSpotAuthFromConfig } from \"../utils/detect.js\";\nimport { applyAutoFixes, parseUploadErrors, parseApiErrors } from \"./auto-fix.js\";\nimport { startStreamingJob, getJob, addJobListener, removeJobListener } from \"./process-manager.js\";\nimport { uploadTheme, type UploadFileError } from \"../hubspot/uploader.js\";\nimport { jsonResponse } from \"./route-helpers.js\";\n\n// Route modules\nimport {\n handleSetupInfoRoute,\n handleSetupCreateRoute,\n handleSetupFetchRoute,\n handleSetupOpenRoute,\n handleSetupResumeRoute,\n handleSetupApiKeyRoute,\n handleSetupRemoteThemesRoute,\n} from \"./routes/setup.js\";\nimport {\n handleSettingsStatusRoute,\n handleSettingsEngineRoute,\n handleSettingsApiKeyRoute,\n handleSettingsInstallRoute,\n handleSettingsHsAuthRoute,\n handleSettingsGhAuthRoute,\n handleSettingsHsSwitchRoute,\n handleSettingsGhLogoutRoute,\n handleSettingsCLIAuthRoute,\n handleSettingsHsModeRoute,\n handleSettingsCliToggleRoute,\n handleSettingsJobRoute,\n} from \"./routes/settings.js\";\nimport {\n handleThemesRoute,\n handleThemeSwitchRoute,\n handleDeleteLocalThemeRoute,\n handleRenameThemeRoute,\n} from \"./routes/themes.js\";\nimport {\n handleDashboardRoute,\n handleDownloadZipRoute,\n handleTemplatesRoute,\n handleTemplateActivateRoute,\n handleTemplateRenameRoute,\n handleModuleLibraryRoute,\n handleAddModuleToTemplateRoute,\n handleBrandAssetsRoute,\n} from \"./routes/templates.js\";\nimport {\n handleSessionRoute,\n handleModulesRoute,\n handleReorderRoute,\n handleUploadRoute,\n handleFieldRoute,\n handleImportRoute,\n handleHistoryRoute,\n handleRollbackRoute,\n} from \"./routes/modules.js\";\nimport { handleFileUploadRoute } from \"./routes/upload-files.js\";\n\n// ---------------------------------------------------------------------------\n// MIME types for static serving\n// ---------------------------------------------------------------------------\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html\",\n \".css\": \"text/css\",\n \".js\": \"application/javascript\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".webp\": \"image/webp\",\n \".gif\": \"image/gif\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport interface ServerOptions {\n port: number;\n uiDir: string;\n}\n\nexport function startServer(opts: ServerOptions): Promise<{ port: number; close: () => void }> {\n const { port, uiDir } = opts;\n\n const server = createServer((req, res) => handleRequest(req, res, uiDir));\n\n // WebSocket server — upgrade on the same HTTP server\n const wss = new WebSocketServer({ server });\n wss.on(\"connection\", (ws) => handleWsConnection(ws));\n\n return new Promise((resolve, reject) => {\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Try next port\n server.listen(port + 1, () => {\n resolve({\n port: port + 1,\n close: () => { server.close(); wss.close(); },\n });\n });\n } else {\n reject(err);\n }\n });\n\n server.listen(port, () => {\n resolve({\n port,\n close: () => { server.close(); wss.close(); },\n });\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// HTTP request handler\n// ---------------------------------------------------------------------------\n\nfunction handleRequest(req: IncomingMessage, res: ServerResponse, uiDir: string): void {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n const method = req.method || \"GET\";\n\n // API routes\n if (url.pathname.startsWith(\"/api/\")) {\n handleApiRoute(method, url.pathname, req, res);\n return;\n }\n\n // Preview route — returns rendered preview HTML\n if (url.pathname === \"/preview\") {\n const html = buildPreviewHtml();\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(html);\n return;\n }\n\n // Single-module preview (for dashboard module library)\n if (url.pathname === \"/module-preview\") {\n const moduleName = url.searchParams.get(\"module\") || \"\";\n const html = buildModulePreviewHtml(moduleName);\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(html || \"<!-- module not found -->\");\n return;\n }\n\n // Theme assets — serve uploaded images for preview\n if (url.pathname.startsWith(\"/theme-assets/\")) {\n serveThemeAsset(url.pathname.slice(\"/theme-assets/\".length), res);\n return;\n }\n\n // Static files from ui/ directory\n serveStatic(url.pathname, uiDir, req, res);\n}\n\n// ---------------------------------------------------------------------------\n// API routes\n// ---------------------------------------------------------------------------\n\nfunction handleApiRoute(\n method: string,\n path: string,\n req: IncomingMessage,\n res: ServerResponse\n): void {\n // CORS headers for local dev\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n switch (path) {\n case \"/api/session\":\n handleSessionRoute(method, res);\n break;\n\n case \"/api/modules\":\n handleModulesRoute(method, req, res);\n break;\n\n case \"/api/modules/reorder\":\n handleReorderRoute(req, res);\n break;\n\n case \"/api/upload\":\n handleUploadRoute(res);\n break;\n\n case \"/api/upload-files\":\n if (method === \"POST\") handleFileUploadRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/field\":\n handleFieldRoute(req, res);\n break;\n\n case \"/api/import\":\n handleImportRoute(req, res);\n break;\n\n case \"/api/setup\":\n handleSetupInfoRoute(res);\n break;\n\n case \"/api/setup/create\":\n handleSetupCreateRoute(req, res);\n break;\n\n case \"/api/setup/fetch\":\n handleSetupFetchRoute(req, res);\n break;\n\n case \"/api/setup/open\":\n handleSetupOpenRoute(req, res);\n break;\n\n case \"/api/setup/resume\":\n handleSetupResumeRoute(req, res);\n break;\n\n case \"/api/setup/apikey\":\n handleSetupApiKeyRoute(req, res);\n break;\n\n case \"/api/setup/remote-themes\":\n if (method === \"GET\") handleSetupRemoteThemesRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n // Settings routes\n case \"/api/settings/status\":\n if (method === \"GET\") handleSettingsStatusRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/engine\":\n if (method === \"POST\") handleSettingsEngineRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/apikey\":\n if (method === \"POST\") handleSettingsApiKeyRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/install\":\n if (method === \"POST\") handleSettingsInstallRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/hs-auth\":\n if (method === \"POST\") handleSettingsHsAuthRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/gh-auth\":\n if (method === \"POST\") handleSettingsGhAuthRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/hs-switch\":\n if (method === \"POST\") handleSettingsHsSwitchRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/gh-logout\":\n if (method === \"POST\") handleSettingsGhLogoutRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/cli-auth\":\n if (method === \"POST\") handleSettingsCLIAuthRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/hs-mode\":\n if (method === \"POST\") handleSettingsHsModeRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/settings/cli-toggle\":\n if (method === \"POST\") handleSettingsCliToggleRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/themes\":\n handleThemesRoute(method, req, res);\n break;\n\n case \"/api/themes/switch\":\n if (method === \"POST\") handleThemeSwitchRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/themes/delete-local\":\n if (method === \"POST\") handleDeleteLocalThemeRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/themes/rename\":\n if (method === \"POST\") handleRenameThemeRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/history\":\n if (method === \"GET\") handleHistoryRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/rollback\":\n if (method === \"POST\") handleRollbackRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n // Dashboard & template routes\n case \"/api/dashboard\":\n if (method === \"GET\") handleDashboardRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/templates\":\n handleTemplatesRoute(method, req, res);\n break;\n\n case \"/api/templates/activate\":\n if (method === \"POST\") handleTemplateActivateRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/templates/rename\":\n if (method === \"POST\") handleTemplateRenameRoute(req, res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/module-library\":\n if (method === \"GET\") handleModuleLibraryRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n case \"/api/brand-assets\":\n handleBrandAssetsRoute(method, req, res);\n break;\n\n case \"/api/download-zip\":\n if (method === \"GET\") handleDownloadZipRoute(res);\n else jsonResponse(res, 405, { error: \"Method not allowed\" });\n break;\n\n default:\n // Prefix match for job polling: /api/settings/job/:id\n if (path.startsWith(\"/api/settings/job/\") && method === \"GET\") {\n handleSettingsJobRoute(path, res);\n }\n // Prefix match for template add-module: /api/templates/:id/add-module\n else if (path.match(/^\\/api\\/templates\\/[^/]+\\/add-module$/) && method === \"POST\") {\n handleAddModuleToTemplateRoute(path, req, res);\n } else {\n jsonResponse(res, 404, { error: \"Not found\" });\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// WebSocket handler\n// ---------------------------------------------------------------------------\n\nfunction handleWsConnection(ws: WebSocket): void {\n ws.on(\"message\", async (data) => {\n let msg: { type: string; [key: string]: unknown };\n try {\n msg = JSON.parse(data.toString());\n } catch {\n ws.send(JSON.stringify({ type: \"error\", message: \"Invalid JSON\" }));\n return;\n }\n\n switch (msg.type) {\n case \"chat\": {\n const userMessage = String(msg.message || \"\");\n if (!userMessage.trim()) return;\n\n addMessage(\"user\", userMessage);\n saveSession();\n\n // Set up parse warning callback for this generation\n setParseWarningCallback((warning) => {\n ws.send(JSON.stringify({ type: \"parse_warning\", message: warning }));\n });\n\n // Stream AI response back via WebSocket\n const fileIds = Array.isArray(msg.fileIds) ? msg.fileIds as string[] : undefined;\n try {\n await handleGenerateStream(\n userMessage,\n (chunk) => {\n ws.send(JSON.stringify({ type: \"stream\", content: chunk }));\n },\n (status) => {\n ws.send(JSON.stringify({ type: \"stream_status\", content: status }));\n },\n fileIds\n );\n\n // Write modules to disk and commit for version history\n const currentSession = getSession();\n if (currentSession) {\n writeModulesToDisk();\n const activeTpl = getActiveTemplate();\n let commitHash: string | null = null;\n if (activeTpl) {\n const filePaths = activeTpl.moduleOrder.map((n: string) => `modules/${n}.module`);\n if (activeTpl.templateFile) filePaths.push(activeTpl.templateFile);\n if (activeTpl.sharedCss) filePaths.push(`css/${currentSession.themeName}-theme.css`);\n if (activeTpl.sharedJs) filePaths.push(`js/${currentSession.themeName}-animations.js`);\n commitHash = commitTemplateState(currentSession.themePath, activeTpl.id, userMessage, filePaths);\n } else {\n commitHash = commitThemeState(currentSession.themePath, userMessage);\n }\n if (commitHash) {\n ws.send(JSON.stringify({ type: \"version_created\", hash: commitHash }));\n }\n }\n\n // After generation, send updated preview\n ws.send(JSON.stringify({ type: \"generation_complete\" }));\n ws.send(JSON.stringify({\n type: \"modules_updated\",\n modules: getOrderedModules().map((m) => m.moduleName),\n }));\n } catch (err) {\n ws.send(JSON.stringify({\n type: \"error\",\n message: err instanceof Error ? err.message : String(err),\n }));\n }\n break;\n }\n\n case \"start_upload\": {\n const session = getSession();\n if (!session) {\n ws.send(JSON.stringify({ type: \"error\", message: \"No active session\" }));\n break;\n }\n\n try {\n writeModulesToDisk();\n\n // Apply auto-fixes before uploading\n const fixes = applyAutoFixes(session.themePath);\n if (fixes.length > 0) {\n ws.send(JSON.stringify({ type: \"upload_status\", phase: \"autofix\", fixes }));\n }\n\n const config = loadConfig();\n const uploadMode = config.hubspotUploadMode || \"api\";\n\n if (uploadMode === \"api\") {\n // --- API mode: direct HTTP uploads ---\n const pak = getHubSpotPak();\n if (!pak) {\n ws.send(JSON.stringify({\n type: \"upload_failed\",\n output: \"No HubSpot account configured. Open Settings → HubSpot to add one.\",\n errors: [{ file: \"\", message: \"No HubSpot account configured\", fixable: false }],\n }));\n break;\n }\n\n ws.send(JSON.stringify({ type: \"upload_started\", jobId: \"api-upload\" }));\n\n const result = await uploadTheme(pak, session.themePath, session.themeName, {\n onFileStart: (path) => {\n ws.send(JSON.stringify({ type: \"upload_output\", chunk: `Uploading ${path}\\n` }));\n },\n onFileComplete: (path) => {\n ws.send(JSON.stringify({ type: \"upload_output\", chunk: ` ✓ ${path}\\n` }));\n },\n onFileError: (path, err) => {\n ws.send(JSON.stringify({ type: \"upload_output\", chunk: ` ✗ ${path}: ${err.message}\\n` }));\n },\n onProgress: (completed, total) => {\n ws.send(JSON.stringify({ type: \"upload_progress\", completed, total }));\n },\n });\n\n if (result.success) {\n const acct = getActiveHubSpotAccount();\n ws.send(JSON.stringify({\n type: \"upload_complete\",\n output: `Uploaded ${result.uploaded} files`,\n portalId: acct?.portalId || \"\",\n dataCenter: acct?.dataCenter || \"na1\",\n themeName: session.themeName,\n }));\n } else {\n const errors = parseApiErrors(result.errors);\n ws.send(JSON.stringify({\n type: \"upload_failed\",\n output: result.errors.map((e) => `${e.file}: ${e.message}`).join(\"\\n\"),\n errors,\n }));\n }\n } else {\n // --- CLI mode: legacy hs cms upload subprocess ---\n const jobId = startStreamingJob(\n `hs cms upload \"${session.themePath}\" \"${session.themeName}\"`,\n \"Uploading to HubSpot\",\n { cwd: join(session.themePath, \"..\"), timeout: 180_000 }\n );\n\n ws.send(JSON.stringify({ type: \"upload_started\", jobId }));\n\n const chunkListener = (chunk: string) => {\n ws.send(JSON.stringify({ type: \"upload_output\", chunk }));\n };\n addJobListener(jobId, chunkListener);\n\n const pollInterval = setInterval(() => {\n const job = getJob(jobId);\n if (!job || job.status === \"running\") return;\n\n clearInterval(pollInterval);\n removeJobListener(jobId, chunkListener);\n\n if (job.status === \"completed\") {\n const auth = detectHubSpotAuth();\n const dc = auth.portalId ? detectDataCenter(auth.portalId) : \"na1\";\n ws.send(JSON.stringify({\n type: \"upload_complete\",\n output: job.output,\n portalId: auth.portalId || \"\",\n dataCenter: dc,\n themeName: session.themeName,\n }));\n } else {\n const errors = parseUploadErrors(job.output);\n ws.send(JSON.stringify({\n type: \"upload_failed\",\n output: job.output,\n errors,\n exitCode: job.exitCode,\n }));\n }\n }, 500);\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: \"error\",\n message: err instanceof Error ? err.message : String(err),\n }));\n }\n break;\n }\n\n case \"upload_fix_with_ai\": {\n const errorContext = String(msg.errorContext || \"\");\n if (!errorContext.trim()) {\n ws.send(JSON.stringify({ type: \"error\", message: \"No error context provided\" }));\n break;\n }\n\n const fixPrompt = `The HubSpot upload (\"hs cms upload\") failed. Below is the upload log output containing the errors.\n\nIMPORTANT: Be verbose in your response. For each error:\n1. State exactly which file has the problem and what the error is\n2. Explain WHY this error occurs (e.g. \"HubSpot doesn't support textarea field type\" or \"field name 'name' is reserved in HubSpot modules\")\n3. Describe the specific fix you're applying (e.g. \"Changing field type from textarea to text\" or \"Renaming field from 'name' to 'item_name'\")\n4. Apply the fix to the module files\n\nCRITICAL: After fixing the reported errors, scan ALL other module files in the theme for the same issues. For example, if you fix \"name\" → \"item_name\" in one module, check every other module's fields.json for the same problem. Fix all occurrences, not just the ones in the error log.\n\nAfter fixing all errors, summarize the changes you made.\n\nUpload log:\n${errorContext}`;\n addMessage(\"user\", fixPrompt);\n saveSession();\n\n ws.send(JSON.stringify({ type: \"upload_fix_started\" }));\n\n try {\n await handleGenerateStream(fixPrompt, (chunk) => {\n // Stream to both the chat panel and the upload panel\n ws.send(JSON.stringify({ type: \"stream\", content: chunk }));\n ws.send(JSON.stringify({ type: \"upload_fix_stream\", content: chunk }));\n });\n\n // Write fixes to disk and commit\n const fixSession = getSession();\n if (fixSession) {\n writeModulesToDisk();\n const fixHash = commitThemeState(fixSession.themePath, \"AI fix: upload errors\");\n if (fixHash) {\n ws.send(JSON.stringify({ type: \"version_created\", hash: fixHash }));\n }\n }\n\n ws.send(JSON.stringify({ type: \"upload_fix_complete\" }));\n ws.send(JSON.stringify({\n type: \"modules_updated\",\n modules: getOrderedModules().map((m) => m.moduleName),\n }));\n } catch (err) {\n ws.send(JSON.stringify({\n type: \"upload_failed\",\n output: err instanceof Error ? err.message : String(err),\n errors: [{ file: \"AI fix\", message: err instanceof Error ? err.message : String(err), fixable: false }],\n }));\n }\n break;\n }\n\n case \"ping\":\n ws.send(JSON.stringify({ type: \"pong\" }));\n break;\n\n default:\n ws.send(JSON.stringify({ type: \"error\", message: `Unknown type: ${msg.type}` }));\n }\n });\n\n // Send initial state\n const session = getSession();\n if (session) {\n const cfg = loadConfig();\n const engineLabels: Record<string, string> = {\n \"claude-code\": \"Claude Code\",\n \"anthropic-api\": \"Anthropic API\",\n \"openai-api\": \"OpenAI API\",\n \"gemini-cli\": \"Gemini CLI\",\n \"gemini-api\": \"Gemini API\",\n \"codex-cli\": \"Codex CLI\",\n \"api\": \"Anthropic API\",\n };\n const activeTpl = getActiveTemplate();\n ws.send(JSON.stringify({\n type: \"init\",\n sessionId: session.id,\n themeName: session.themeName,\n modules: getOrderedModules().map((m) => m.moduleName),\n messageCount: session.messages.length,\n messages: session.messages,\n gitAvailable: isGitAvailable(),\n engine: cfg.aiEngine ? engineLabels[cfg.aiEngine] || cfg.aiEngine : \"\",\n // Multi-template context\n templateId: activeTpl?.id || null,\n pageType: activeTpl?.pageType || null,\n templates: (session.templates || []).map((t) => ({\n id: t.id,\n label: t.label,\n pageType: t.pageType,\n moduleCount: t.modules.length,\n })),\n }));\n } else {\n ws.send(JSON.stringify({ type: \"needs_setup\" }));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Theme asset serving (uploaded images for preview)\n// ---------------------------------------------------------------------------\n\nfunction serveThemeAsset(filename: string, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"No session\");\n return;\n }\n const filePath = join(session.themePath, \"assets\", filename);\n if (!existsSync(filePath)) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Asset not found\");\n return;\n }\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n const buffer = readFileSync(filePath);\n res.writeHead(200, {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"no-cache\",\n });\n res.end(buffer);\n}\n\n// ---------------------------------------------------------------------------\n// Static file serving\n// ---------------------------------------------------------------------------\n\nconst staticCache = new Map<string, { buffer: Buffer; etag: string; contentType: string }>();\n\nfunction serveStatic(pathname: string, uiDir: string, req: IncomingMessage, res: ServerResponse): void {\n // Default to index.html\n let filePath = pathname === \"/\" ? \"/index.html\" : pathname;\n const fullPath = join(uiDir, filePath);\n\n if (!existsSync(fullPath)) {\n // SPA fallback — serve index.html for unknown routes\n const indexPath = join(uiDir, \"index.html\");\n if (existsSync(indexPath)) {\n const content = readFileSync(indexPath);\n res.writeHead(200, { \"Content-Type\": \"text/html\", \"Cache-Control\": \"no-cache\" });\n res.end(content);\n } else {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not found\");\n }\n return;\n }\n\n const ext = extname(fullPath);\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n const isHtml = ext === \".html\";\n\n try {\n let cached = staticCache.get(fullPath);\n if (!cached) {\n const buffer = readFileSync(fullPath);\n const etag = '\"' + createHash(\"md5\").update(buffer).digest(\"hex\").slice(0, 16) + '\"';\n cached = { buffer, etag, contentType };\n staticCache.set(fullPath, cached);\n }\n\n // Check If-None-Match for 304\n const clientEtag = req.headers[\"if-none-match\"];\n if (clientEtag === cached.etag) {\n res.writeHead(304);\n res.end();\n return;\n }\n\n res.writeHead(200, {\n \"Content-Type\": cached.contentType,\n \"Cache-Control\": isHtml ? \"no-cache\" : \"public, max-age=3600\",\n \"ETag\": cached.etag,\n });\n res.end(cached.buffer);\n } catch {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(\"Internal Server Error\");\n }\n}\n","/**\n * Session state for the vibe coding workspace.\n * Tracks conversation history, generated modules, and theme state.\n */\n\nimport { readFileSync, readdirSync, existsSync, writeFileSync, mkdirSync, rmSync, renameSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { ModuleFiles, GeneratedAssets } from \"../ai/engine.js\";\nimport { ensureGitRepo } from \"./project-git.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessage {\n role: \"user\" | \"assistant\";\n content: string;\n timestamp: number;\n}\n\nexport type PageType = \"landing_page\" | \"blog_post\" | \"website_page\" | \"module_only\";\n\nexport interface TemplateEntry {\n id: string; // e.g. \"lp-main\", \"blog-post\"\n label: string; // \"Main Landing Page\"\n pageType: PageType;\n templateFile: string; // \"templates/lp-main.html\"\n modules: ModuleFiles[];\n moduleOrder: string[];\n sharedCss: string;\n sharedJs: string;\n template: string; // HubL template content\n messages: ChatMessage[]; // per-template chat history\n}\n\nexport interface SessionAsset {\n id: string;\n filename: string;\n originalName: string;\n type: \"image\" | \"document\";\n usage: \"asset\" | \"context\";\n mimeType: string;\n size: number;\n addedAt: string;\n extractedText?: string;\n}\n\nexport interface VibeSession {\n id: string;\n themePath: string;\n themeName: string;\n\n // Multi-template support\n templates: TemplateEntry[];\n activeTemplateId: string;\n brandAssets?: {\n styleguide?: string;\n brandvoice?: string;\n humanify?: boolean;\n };\n assets?: SessionAsset[];\n\n // Legacy flat fields — kept for backward compat, redirected to active template\n messages: ChatMessage[];\n modules: ModuleFiles[];\n sharedCss: string;\n sharedJs: string;\n template: string;\n moduleOrder: string[];\n createdAt: number;\n updatedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// Session management\n// ---------------------------------------------------------------------------\n\nconst SESSIONS_DIR = join(homedir(), \".vibespot\", \"sessions\");\nconst INDEX_PATH = join(SESSIONS_DIR, \"_index.json\");\n\ninterface SessionIndexEntry {\n id: string;\n themeName: string;\n updatedAt: number;\n moduleCount: number;\n templateCount: number;\n}\n\nlet _indexCache: SessionIndexEntry[] | null = null;\n\nfunction readIndex(): SessionIndexEntry[] {\n if (_indexCache) return _indexCache;\n try {\n if (!existsSync(INDEX_PATH)) return rebuildIndex();\n _indexCache = JSON.parse(readFileSync(INDEX_PATH, \"utf-8\"));\n return _indexCache!;\n } catch {\n return rebuildIndex();\n }\n}\n\nfunction writeIndex(entries: SessionIndexEntry[]): void {\n _indexCache = entries;\n try {\n mkdirSync(SESSIONS_DIR, { recursive: true });\n writeFileSync(INDEX_PATH, JSON.stringify(entries), \"utf-8\");\n } catch { /* non-critical */ }\n}\n\nfunction rebuildIndex(): SessionIndexEntry[] {\n if (!existsSync(SESSIONS_DIR)) return [];\n const entries: SessionIndexEntry[] = [];\n for (const f of readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(\".json\") && f !== \"_index.json\")) {\n try {\n const data = JSON.parse(readFileSync(join(SESSIONS_DIR, f), \"utf-8\"));\n const templates = data.templates || [];\n entries.push({\n id: data.id,\n themeName: data.themeName,\n updatedAt: data.updatedAt,\n moduleCount: templates.reduce((n: number, t: any) => n + (t.modules?.length || 0), 0),\n templateCount: templates.length,\n });\n } catch { /* skip corrupt files */ }\n }\n _indexCache = entries;\n writeIndex(entries);\n return entries;\n}\n\nfunction upsertIndex(session: VibeSession): void {\n const entries = readIndex();\n const templates = session.templates || [];\n const entry: SessionIndexEntry = {\n id: session.id,\n themeName: session.themeName,\n updatedAt: session.updatedAt,\n moduleCount: templates.reduce((n, t) => n + (t.modules?.length || 0), 0),\n templateCount: templates.length,\n };\n const idx = entries.findIndex((e) => e.id === session.id);\n if (idx >= 0) entries[idx] = entry;\n else entries.push(entry);\n writeIndex(entries);\n}\n\nfunction removeFromIndex(sessionId: string): void {\n const entries = readIndex().filter((e) => e.id !== sessionId);\n writeIndex(entries);\n}\n\nfunction removeFromIndexByTheme(themeName: string): void {\n const entries = readIndex().filter((e) => e.themeName !== themeName);\n writeIndex(entries);\n}\n\nlet activeSession: VibeSession | null = null;\n\nexport function createSession(themePath: string, themeName: string): VibeSession {\n const session: VibeSession = {\n id: generateId(),\n themePath,\n themeName,\n templates: [],\n activeTemplateId: \"\",\n messages: [],\n modules: [],\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n moduleOrder: [],\n createdAt: Date.now(),\n updatedAt: Date.now(),\n };\n\n activeSession = session;\n ensureGitRepo(themePath);\n return session;\n}\n\n// ---------------------------------------------------------------------------\n// Template management\n// ---------------------------------------------------------------------------\n\n/**\n * Migrate a legacy flat session (v0.3.0) into the templates array.\n * Called when loading a session that has modules but no templates.\n */\nexport function migrateSession(session: VibeSession): void {\n if (session.templates && session.templates.length > 0) return;\n if (!session.modules || session.modules.length === 0) {\n session.templates = [];\n session.activeTemplateId = \"\";\n return;\n }\n\n const templateId = `lp-${session.themeName}`;\n const entry: TemplateEntry = {\n id: templateId,\n label: `${session.themeName} Landing Page`,\n pageType: \"landing_page\",\n templateFile: `templates/lp-${session.themeName}.html`,\n modules: [...session.modules],\n moduleOrder: [...session.moduleOrder],\n sharedCss: session.sharedCss || \"\",\n sharedJs: session.sharedJs || \"\",\n template: session.template || \"\",\n messages: [...session.messages],\n };\n\n session.templates = [entry];\n session.activeTemplateId = templateId;\n}\n\n/**\n * Get the active template entry, or null if none set.\n */\nexport function getActiveTemplate(): TemplateEntry | null {\n if (!activeSession) return null;\n if (!activeSession.activeTemplateId || !activeSession.templates?.length) return null;\n return activeSession.templates.find((t) => t.id === activeSession!.activeTemplateId) || null;\n}\n\n/**\n * Set the active template by ID. Syncs flat fields from the template.\n */\nexport function setActiveTemplate(templateId: string): boolean {\n if (!activeSession) return false;\n const tpl = activeSession.templates.find((t) => t.id === templateId);\n if (!tpl) return false;\n\n activeSession.activeTemplateId = templateId;\n syncFlatFieldsFromTemplate(tpl);\n activeSession.updatedAt = Date.now();\n return true;\n}\n\n/**\n * Create a new template entry and add it to the session.\n */\nexport function addTemplate(pageType: PageType, label: string): TemplateEntry {\n if (!activeSession) throw new Error(\"No active session\");\n\n const slug = label\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n const prefix = pageType === \"blog_post\" ? \"bp\" :\n pageType === \"website_page\" ? \"wp\" :\n pageType === \"module_only\" ? \"mo\" : \"lp\";\n const id = `${prefix}-${slug}`;\n\n const entry: TemplateEntry = {\n id,\n label,\n pageType,\n templateFile: pageType === \"module_only\" ? \"\" : `templates/${id}.html`,\n modules: [],\n moduleOrder: [],\n sharedCss: \"\",\n sharedJs: \"\",\n template: \"\",\n messages: [],\n };\n\n activeSession.templates.push(entry);\n activeSession.activeTemplateId = id;\n syncFlatFieldsFromTemplate(entry);\n activeSession.updatedAt = Date.now();\n return entry;\n}\n\n/**\n * Rename a template's display label.\n */\nexport function renameTemplate(templateId: string, newLabel: string): boolean {\n if (!activeSession) return false;\n const tpl = activeSession.templates.find((t) => t.id === templateId);\n if (!tpl) return false;\n tpl.label = newLabel;\n activeSession.updatedAt = Date.now();\n return true;\n}\n\n/**\n * Remove a template by ID.\n */\nexport function removeTemplate(templateId: string): boolean {\n if (!activeSession) return false;\n const idx = activeSession.templates.findIndex((t) => t.id === templateId);\n if (idx < 0) return false;\n\n activeSession.templates.splice(idx, 1);\n\n // If we removed the active template, switch to the first remaining one\n if (activeSession.activeTemplateId === templateId) {\n if (activeSession.templates.length > 0) {\n setActiveTemplate(activeSession.templates[0].id);\n } else {\n activeSession.activeTemplateId = \"\";\n activeSession.modules = [];\n activeSession.moduleOrder = [];\n activeSession.sharedCss = \"\";\n activeSession.sharedJs = \"\";\n activeSession.template = \"\";\n activeSession.messages = [];\n }\n }\n\n activeSession.updatedAt = Date.now();\n return true;\n}\n\n/**\n * Get deduplicated modules across all templates (the module library).\n */\nexport function getModuleLibrary(): Array<{ module: ModuleFiles; usedIn: string[] }> {\n if (!activeSession) return [];\n const map = new Map<string, { module: ModuleFiles; usedIn: string[] }>();\n\n for (const tpl of activeSession.templates) {\n for (const mod of tpl.modules) {\n const existing = map.get(mod.moduleName);\n if (existing) {\n existing.usedIn.push(tpl.label);\n } else {\n map.set(mod.moduleName, { module: mod, usedIn: [tpl.label] });\n }\n }\n }\n\n return Array.from(map.values());\n}\n\n/**\n * Sync flat session fields from a template (compatibility layer).\n * Existing code reads session.modules, session.messages, etc.\n * This keeps those in sync with the active template.\n */\nfunction syncFlatFieldsFromTemplate(tpl: TemplateEntry): void {\n if (!activeSession) return;\n activeSession.modules = tpl.modules;\n activeSession.moduleOrder = tpl.moduleOrder;\n activeSession.sharedCss = tpl.sharedCss;\n activeSession.sharedJs = tpl.sharedJs;\n activeSession.template = tpl.template;\n activeSession.messages = tpl.messages;\n}\n\n/**\n * Sync changes from flat session fields back to the active template.\n * Called after any mutation to session.modules/sharedCss/etc.\n */\nfunction syncFlatFieldsToTemplate(): void {\n if (!activeSession) return;\n const tpl = getActiveTemplate();\n if (!tpl) return;\n tpl.modules = activeSession.modules;\n tpl.moduleOrder = activeSession.moduleOrder;\n tpl.sharedCss = activeSession.sharedCss;\n tpl.sharedJs = activeSession.sharedJs;\n tpl.template = activeSession.template;\n tpl.messages = activeSession.messages;\n}\n\nexport function getSession(): VibeSession | null {\n return activeSession;\n}\n\nexport function addMessage(role: \"user\" | \"assistant\", content: string): void {\n if (!activeSession) return;\n activeSession.messages.push({ role, content, timestamp: Date.now() });\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n saveChatToTheme();\n}\n\nexport function addSessionAsset(asset: SessionAsset): void {\n if (!activeSession) return;\n if (!activeSession.assets) activeSession.assets = [];\n activeSession.assets.push(asset);\n activeSession.updatedAt = Date.now();\n saveSession();\n}\n\n/**\n * Update session with newly generated/modified modules.\n * Merges new modules into existing state (updates existing, adds new).\n */\nexport function updateModules(assets: Partial<GeneratedAssets>): void {\n if (!activeSession) return;\n\n if (assets.sharedCss !== undefined) activeSession.sharedCss = assets.sharedCss;\n if (assets.sharedJs !== undefined) activeSession.sharedJs = assets.sharedJs;\n if (assets.template !== undefined) activeSession.template = assets.template;\n\n if (assets.modules) {\n for (const newMod of assets.modules) {\n const idx = activeSession.modules.findIndex(\n (m) => m.moduleName === newMod.moduleName\n );\n if (idx >= 0) {\n activeSession.modules[idx] = newMod;\n } else {\n activeSession.modules.push(newMod);\n activeSession.moduleOrder.push(newMod.moduleName);\n }\n }\n }\n\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Reorder modules (used by drag-and-drop in the UI).\n */\nexport function reorderModules(newOrder: string[]): void {\n if (!activeSession) return;\n activeSession.moduleOrder = newOrder;\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Remove a module by name.\n */\nexport function removeModule(moduleName: string): void {\n if (!activeSession) return;\n activeSession.modules = activeSession.modules.filter(\n (m) => m.moduleName !== moduleName\n );\n activeSession.moduleOrder = activeSession.moduleOrder.filter(\n (n) => n !== moduleName\n );\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Detach a module from the current template (remove from moduleOrder only).\n * The module data stays in the session so it can be re-added later.\n */\nexport function detachModule(moduleName: string): void {\n if (!activeSession) return;\n activeSession.moduleOrder = activeSession.moduleOrder.filter(\n (n) => n !== moduleName\n );\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Update a single field value in a module's fields.json.\n * Used by the field editor sidebar.\n */\nexport function updateFieldValue(\n moduleName: string,\n fieldPath: string,\n value: unknown\n): void {\n if (!activeSession) return;\n\n const mod = activeSession.modules.find((m) => m.moduleName === moduleName);\n if (!mod) return;\n\n try {\n const fields = JSON.parse(mod.fieldsJson);\n setFieldDefault(fields, fieldPath, value);\n mod.fieldsJson = JSON.stringify(fields, null, 2);\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n } catch {\n // Invalid JSON — skip\n }\n}\n\n/**\n * Get modules in display order.\n */\nexport function getOrderedModules(): ModuleFiles[] {\n if (!activeSession) return [];\n\n const ordered: ModuleFiles[] = [];\n for (const name of activeSession.moduleOrder) {\n const mod = activeSession.modules.find((m) => m.moduleName === name);\n if (mod) ordered.push(mod);\n }\n\n // Append any modules not in the order list\n for (const mod of activeSession.modules) {\n if (!activeSession.moduleOrder.includes(mod.moduleName)) {\n ordered.push(mod);\n }\n }\n\n return ordered;\n}\n\n// ---------------------------------------------------------------------------\n// Scan modules from disk (for loading existing themes)\n// ---------------------------------------------------------------------------\n\n/**\n * Scan a theme directory on disk and load existing modules into the session.\n */\nexport function scanThemeFromDisk(themePath: string): void {\n if (!activeSession) return;\n\n // Load persisted chat from theme directory (if session has no messages yet)\n const chatFromDisk = loadChatFromTheme(themePath);\n if (chatFromDisk.length > 0 && activeSession.messages.length === 0) {\n activeSession.messages = chatFromDisk;\n }\n\n // Ensure git repo exists (handles themes created before this feature)\n ensureGitRepo(themePath);\n\n const modulesDir = join(themePath, \"modules\");\n if (!existsSync(modulesDir)) return;\n\n const entries = readdirSync(modulesDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.endsWith(\".module\")) continue;\n\n const modDir = join(modulesDir, entry.name);\n const moduleName = entry.name.replace(/\\.module$/, \"\");\n\n const mod: ModuleFiles = {\n moduleName,\n fieldsJson: safeRead(join(modDir, \"fields.json\")),\n metaJson: safeRead(join(modDir, \"meta.json\")),\n moduleHtml: safeRead(join(modDir, \"module.html\")),\n moduleCss: safeRead(join(modDir, \"module.css\")),\n moduleJs: safeRead(join(modDir, \"module.js\")) || undefined,\n };\n\n if (mod.fieldsJson && mod.moduleHtml) {\n activeSession.modules.push(mod);\n activeSession.moduleOrder.push(moduleName);\n }\n }\n\n // Load shared CSS/JS\n const cssDir = join(themePath, \"css\");\n const jsDir = join(themePath, \"js\");\n\n if (existsSync(cssDir)) {\n const cssFiles = readdirSync(cssDir).filter(\n (f) => f.endsWith(\"-theme.css\") || f.endsWith(\"-theme.css\")\n );\n if (cssFiles.length > 0) {\n activeSession.sharedCss = safeRead(join(cssDir, cssFiles[0]));\n }\n }\n\n if (existsSync(jsDir)) {\n const jsFiles = readdirSync(jsDir).filter(\n (f) => f.endsWith(\"-animations.js\")\n );\n if (jsFiles.length > 0) {\n activeSession.sharedJs = safeRead(join(jsDir, jsFiles[0]));\n }\n }\n\n // Load brand assets from .vibespot/ directory\n const sgPath = join(themePath, \".vibespot\", \"styleguide.md\");\n const bvPath = join(themePath, \".vibespot\", \"brandvoice.md\");\n if (existsSync(sgPath) || existsSync(bvPath)) {\n if (!activeSession.brandAssets) activeSession.brandAssets = {};\n if (existsSync(sgPath)) activeSession.brandAssets.styleguide = safeRead(sgPath);\n if (existsSync(bvPath)) activeSession.brandAssets.brandvoice = safeRead(bvPath);\n }\n\n // Migrate flat fields to templates if this is a pre-existing theme\n if (!activeSession.templates) activeSession.templates = [];\n if (!activeSession.activeTemplateId) activeSession.activeTemplateId = \"\";\n migrateSession(activeSession);\n}\n\n// ---------------------------------------------------------------------------\n// Persistence — save/load sessions across restarts\n// ---------------------------------------------------------------------------\n\nexport function saveSession(): void {\n if (!activeSession) return;\n\n mkdirSync(SESSIONS_DIR, { recursive: true });\n const filePath = join(SESSIONS_DIR, `${activeSession.id}.json`);\n writeFileSync(filePath, JSON.stringify(activeSession, null, 2), \"utf-8\");\n upsertIndex(activeSession);\n}\n\nexport function loadSession(sessionId: string): VibeSession | null {\n const filePath = join(SESSIONS_DIR, sessionId + \".json\");\n if (!existsSync(filePath)) return null;\n\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n\n // Ensure templates array exists (backward compat with v0.3.0 sessions)\n if (!data.templates) data.templates = [];\n if (!data.activeTemplateId) data.activeTemplateId = \"\";\n\n // Migrate flat fields into templates if needed\n migrateSession(data);\n\n activeSession = data;\n return data;\n } catch {\n return null;\n }\n}\n\nexport function listSessions(): Array<{ id: string; themeName: string; updatedAt: number; moduleCount: number; templateCount: number }> {\n if (!existsSync(SESSIONS_DIR)) return [];\n return readIndex();\n}\n\nexport function deleteSession(sessionId: string, deleteFiles = false): void {\n const filePath = join(SESSIONS_DIR, sessionId + \".json\");\n\n // Read the session to get themeName (needed to find sibling sessions)\n let themeName = \"\";\n if (deleteFiles) {\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n themeName = data.themeName || \"\";\n if (data.themePath && existsSync(data.themePath)) {\n rmSync(data.themePath, { recursive: true, force: true });\n }\n } catch { /* ignore */ }\n } else {\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\"));\n themeName = data.themeName || \"\";\n } catch { /* ignore */ }\n }\n\n try {\n if (existsSync(filePath)) rmSync(filePath);\n } catch { /* ignore */ }\n\n // Also delete all other sessions for the same theme (prevents ghost entries)\n if (themeName && existsSync(SESSIONS_DIR)) {\n for (const f of readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(\".json\") && f !== \"_index.json\")) {\n try {\n const data = JSON.parse(readFileSync(join(SESSIONS_DIR, f), \"utf-8\"));\n if (data.themeName === themeName) {\n rmSync(join(SESSIONS_DIR, f));\n }\n } catch { /* ignore */ }\n }\n removeFromIndexByTheme(themeName);\n } else {\n removeFromIndex(sessionId);\n }\n\n if (activeSession?.id === sessionId) {\n activeSession = null;\n }\n}\n\n/**\n * Rename a project: update themeName in all sessions, rename disk folder,\n * rename CSS/JS files, and update the session index.\n */\nexport function renameSession(sessionId: string, newName: string): { ok: boolean; error?: string } {\n // Load the session to get the current theme name\n const filePath = join(SESSIONS_DIR, sessionId + \".json\");\n if (!existsSync(filePath)) return { ok: false, error: \"Session not found\" };\n\n let session: VibeSession;\n try {\n session = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return { ok: false, error: \"Failed to read session\" };\n }\n\n const oldName = session.themeName;\n if (oldName === newName) return { ok: true };\n\n const oldPath = session.themePath;\n const newPath = join(dirname(oldPath), newName);\n\n // Rename the folder on disk\n if (existsSync(oldPath)) {\n if (existsSync(newPath)) return { ok: false, error: \"A project with that name already exists\" };\n try {\n renameSync(oldPath, newPath);\n } catch (err) {\n return { ok: false, error: `Failed to rename folder: ${err instanceof Error ? err.message : String(err)}` };\n }\n\n // Rename CSS/JS files inside the new folder\n const cssOld = join(newPath, \"css\", `${oldName}-theme.css`);\n const cssNew = join(newPath, \"css\", `${newName}-theme.css`);\n if (existsSync(cssOld)) try { renameSync(cssOld, cssNew); } catch { /* non-critical */ }\n\n const jsOld = join(newPath, \"js\", `${oldName}-animations.js`);\n const jsNew = join(newPath, \"js\", `${newName}-animations.js`);\n if (existsSync(jsOld)) try { renameSync(jsOld, jsNew); } catch { /* non-critical */ }\n\n // Update theme.json label/name\n const themeJsonPath = join(newPath, \"theme.json\");\n if (existsSync(themeJsonPath)) {\n try {\n const themeData = JSON.parse(readFileSync(themeJsonPath, \"utf-8\"));\n themeData.label = newName;\n themeData.name = newName;\n writeFileSync(themeJsonPath, JSON.stringify(themeData, null, 2), \"utf-8\");\n } catch { /* non-critical */ }\n }\n }\n\n // Update all sessions that reference this theme\n if (existsSync(SESSIONS_DIR)) {\n for (const f of readdirSync(SESSIONS_DIR).filter((f) => f.endsWith(\".json\") && f !== \"_index.json\")) {\n try {\n const data = JSON.parse(readFileSync(join(SESSIONS_DIR, f), \"utf-8\"));\n if (data.themeName === oldName) {\n data.themeName = newName;\n data.themePath = newPath;\n data.updatedAt = Date.now();\n writeFileSync(join(SESSIONS_DIR, f), JSON.stringify(data, null, 2), \"utf-8\");\n }\n } catch { /* skip corrupt files */ }\n }\n }\n\n // Update the in-memory active session\n if (activeSession && activeSession.themeName === oldName) {\n activeSession.themeName = newName;\n activeSession.themePath = newPath;\n activeSession.updatedAt = Date.now();\n }\n\n // Rebuild the index\n rebuildIndex();\n\n return { ok: true };\n}\n\n// ---------------------------------------------------------------------------\n// Write modules back to disk (for upload)\n// ---------------------------------------------------------------------------\n\nexport function writeModulesToDisk(): void {\n if (!activeSession) return;\n\n const themePath = activeSession.themePath;\n\n // Collect all modules from all templates (deduplicated by name)\n const allModules = new Map<string, ModuleFiles>();\n if (activeSession.templates.length > 0) {\n for (const tpl of activeSession.templates) {\n for (const mod of tpl.modules) {\n allModules.set(mod.moduleName, mod);\n }\n }\n }\n // Also include flat session modules (backward compat / active template)\n for (const mod of activeSession.modules) {\n allModules.set(mod.moduleName, mod);\n }\n\n // Pre-create all module directories in one pass\n const modulesBaseDir = join(themePath, \"modules\");\n mkdirSync(modulesBaseDir, { recursive: true });\n for (const mod of allModules.values()) {\n mkdirSync(join(modulesBaseDir, `${mod.moduleName}.module`), { recursive: true });\n }\n\n for (const mod of allModules.values()) {\n const modDir = join(modulesBaseDir, `${mod.moduleName}.module`);\n writeFileSync(join(modDir, \"fields.json\"), mod.fieldsJson, \"utf-8\");\n writeFileSync(join(modDir, \"meta.json\"), mod.metaJson, \"utf-8\");\n writeFileSync(join(modDir, \"module.html\"), mod.moduleHtml, \"utf-8\");\n writeFileSync(join(modDir, \"module.css\"), mod.moduleCss, \"utf-8\");\n if (mod.moduleJs) {\n writeFileSync(join(modDir, \"module.js\"), mod.moduleJs, \"utf-8\");\n }\n }\n\n // Write shared CSS/JS\n if (activeSession.sharedCss) {\n const cssDir = join(themePath, \"css\");\n mkdirSync(cssDir, { recursive: true });\n writeFileSync(\n join(cssDir, `${activeSession.themeName}-theme.css`),\n activeSession.sharedCss,\n \"utf-8\"\n );\n }\n\n if (activeSession.sharedJs) {\n const jsDir = join(themePath, \"js\");\n mkdirSync(jsDir, { recursive: true });\n writeFileSync(\n join(jsDir, `${activeSession.themeName}-animations.js`),\n activeSession.sharedJs,\n \"utf-8\"\n );\n }\n\n // Write page templates for all templates in the session\n if (activeSession.templates.length > 0) {\n const templatesDir = join(themePath, \"templates\");\n mkdirSync(templatesDir, { recursive: true });\n\n for (const tpl of activeSession.templates) {\n if (tpl.pageType === \"module_only\") continue; // No template for module-only\n if (tpl.modules.length === 0) continue;\n\n const templateContent = tpl.template || generateTemplateForEntry(tpl);\n const annotated = ensureTemplateAnnotations(templateContent, tpl.label, tpl.pageType);\n writeFileSync(\n join(templatesDir, `${tpl.id}.html`),\n annotated,\n \"utf-8\"\n );\n\n // For blog posts, also generate a listing template\n if (tpl.pageType === \"blog_post\") {\n writeBlogListingTemplate(templatesDir, tpl);\n }\n }\n } else if (activeSession.modules.length > 0) {\n // Legacy fallback: single template from flat fields\n const template = activeSession.template || generateTemplateFromModules();\n const templatesDir = join(themePath, \"templates\");\n mkdirSync(templatesDir, { recursive: true });\n const annotated = ensureTemplateAnnotations(template, `${activeSession.themeName} Landing Page`);\n writeFileSync(\n join(templatesDir, `lp-${activeSession.themeName}.html`),\n annotated,\n \"utf-8\"\n );\n }\n\n // Patch base.html to load template_js (animations won't work without this)\n patchBaseTemplate();\n\n // Populate theme.json with proper metadata\n updateThemeJson();\n}\n\n// ---------------------------------------------------------------------------\n// Chat persistence — store chat in theme directory\n// ---------------------------------------------------------------------------\n\n/**\n * Persist chat to {themePath}/.vibespot/chat.json (gitignored).\n */\nfunction saveChatToTheme(): void {\n if (!activeSession) return;\n try {\n const chatDir = join(activeSession.themePath, \".vibespot\");\n mkdirSync(chatDir, { recursive: true });\n const chatData = {\n sessionId: activeSession.id,\n themeName: activeSession.themeName,\n messages: activeSession.messages,\n updatedAt: Date.now(),\n };\n writeFileSync(join(chatDir, \"chat.json\"), JSON.stringify(chatData, null, 2), \"utf-8\");\n } catch {\n // Non-critical — don't block on chat persistence errors\n }\n}\n\n/**\n * Load chat history from a theme's .vibespot/chat.json.\n */\nfunction loadChatFromTheme(themePath: string): ChatMessage[] {\n const chatPath = join(themePath, \".vibespot\", \"chat.json\");\n if (!existsSync(chatPath)) return [];\n try {\n const data = JSON.parse(readFileSync(chatPath, \"utf-8\"));\n return Array.isArray(data.messages) ? data.messages : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Clear in-memory modules and re-scan from disk.\n * Used after a git rollback to sync session state with restored files.\n */\nexport function reloadModulesFromDisk(): void {\n if (!activeSession) return;\n activeSession.modules = [];\n activeSession.moduleOrder = [];\n activeSession.sharedCss = \"\";\n activeSession.sharedJs = \"\";\n activeSession.template = \"\";\n scanThemeFromDisk(activeSession.themePath);\n activeSession.updatedAt = Date.now();\n syncFlatFieldsToTemplate();\n}\n\n/**\n * Reload only the active template's modules from disk.\n * Used after a scoped rollback to avoid affecting other templates.\n */\nexport function reloadActiveTemplateFromDisk(): void {\n if (!activeSession) return;\n const tpl = getActiveTemplate();\n if (!tpl) return;\n\n const themePath = activeSession.themePath;\n const modulesDir = join(themePath, \"modules\");\n\n // Reload modules that belong to this template\n tpl.modules = [];\n for (const name of tpl.moduleOrder) {\n const modDir = join(modulesDir, `${name}.module`);\n if (!existsSync(modDir)) continue;\n const mod: ModuleFiles = {\n moduleName: name,\n fieldsJson: safeRead(join(modDir, \"fields.json\")),\n metaJson: safeRead(join(modDir, \"meta.json\")),\n moduleHtml: safeRead(join(modDir, \"module.html\")),\n moduleCss: safeRead(join(modDir, \"module.css\")),\n moduleJs: safeRead(join(modDir, \"module.js\")) || undefined,\n };\n if (mod.fieldsJson && mod.moduleHtml) {\n tpl.modules.push(mod);\n }\n }\n\n // Reload template file\n if (tpl.templateFile) {\n const tplPath = join(themePath, tpl.templateFile);\n if (existsSync(tplPath)) {\n tpl.template = safeRead(tplPath);\n }\n }\n\n // Sync flat fields from the updated template\n syncFlatFieldsFromTemplate(tpl);\n activeSession.updatedAt = Date.now();\n}\n\n// ---------------------------------------------------------------------------\n// Theme metadata — populate theme.json + validate template annotations\n// ---------------------------------------------------------------------------\n\n/**\n * Patch base.html to load template_js (the boilerplate only loads template_css).\n * Without this, shared animations JS never runs and scroll-animate elements stay invisible.\n */\nfunction patchBaseTemplate(): void {\n if (!activeSession) return;\n const basePath = join(activeSession.themePath, \"templates\", \"layouts\", \"base.html\");\n if (!existsSync(basePath)) return;\n\n try {\n let content = readFileSync(basePath, \"utf-8\");\n // Already patched?\n if (content.includes(\"template_js\")) return;\n\n // Insert {% if template_js %} block right after the main.js require line\n const mainJsLine = '{{ require_js(get_asset_url(\"../../js/main.js\")) }}';\n if (content.includes(mainJsLine)) {\n content = content.replace(\n mainJsLine,\n mainJsLine + '\\n {% if template_js %}\\n {{ require_js(get_asset_url(template_js)) }}\\n {% endif %}'\n );\n } else {\n // Fallback: insert before standard_footer_includes\n content = content.replace(\n \"{{ standard_footer_includes }}\",\n '{% if template_js %}\\n {{ require_js(get_asset_url(template_js)) }}\\n {% endif %}\\n {{ standard_footer_includes }}'\n );\n }\n\n writeFileSync(basePath, content, \"utf-8\");\n } catch {\n // Non-critical — the generated template has its own require_js fallback\n }\n}\n\n/**\n * Update theme.json with proper name/label and ensure template annotations.\n * Called during writeModulesToDisk.\n */\nfunction updateThemeJson(): void {\n if (!activeSession) return;\n const themeJsonPath = join(activeSession.themePath, \"theme.json\");\n if (!existsSync(themeJsonPath)) return;\n\n try {\n const themeData = JSON.parse(readFileSync(themeJsonPath, \"utf-8\"));\n themeData.label = activeSession.themeName;\n themeData.name = activeSession.themeName;\n writeFileSync(themeJsonPath, JSON.stringify(themeData, null, 2), \"utf-8\");\n } catch {\n // Non-critical\n }\n}\n\n/**\n * Ensure the page template has proper HubSpot annotations.\n */\nfunction ensureTemplateAnnotations(templateContent: string, label: string, pageType: PageType = \"landing_page\"): string {\n // Check if annotations already exist\n if (templateContent.includes(\"templateType\")) return templateContent;\n\n const templateType = pageType === \"blog_post\" ? \"blog_post\" : \"page\";\n const annotations = `<!--\n templateType: ${templateType}\n isAvailableForNewContent: true\n label: \"${label}\"\n-->\\n`;\n return annotations + templateContent;\n}\n\n// ---------------------------------------------------------------------------\n// Template generation — build page templates from module data\n// ---------------------------------------------------------------------------\n\n/**\n * Build a HubSpot page template for a specific TemplateEntry.\n */\nfunction generateTemplateForEntry(tpl: TemplateEntry): string {\n if (tpl.modules.length === 0) return \"\";\n\n const name = activeSession!.themeName;\n const ordered = getOrderedModulesFrom(tpl);\n\n const sections = ordered.map((mod) => {\n return ` {% dnd_section padding={\"top\":\"0\",\"bottom\":\"0\",\"left\":\"0\",\"right\":\"0\"}, full_width=true %}\n {% dnd_module path=\"../modules/${mod.moduleName}.module\" %}\n {% end_dnd_module %}\n {% end_dnd_section %}`;\n }).join(\"\\n\\n\");\n\n const templateType = tpl.pageType === \"blog_post\" ? \"blog_post\" : \"page\";\n\n return `<!--\n templateType: ${templateType}\n isAvailableForNewContent: true\n label: \"${tpl.label}\"\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% set template_css = \"../../css/${name}-theme.css\" %}\n{% set template_js = \"../../js/${name}-animations.js\" %}\n\n{% block header %}\n{% endblock header %}\n\n{% block body %}\n<div class=\"${name}-page\">\n {% dnd_area \"main_content\" label=\"${tpl.label}\" %}\n\n${sections}\n\n {% end_dnd_area %}\n</div>\n{{ require_js(get_asset_url(\"../../js/${name}-animations.js\")) }}\n{% endblock body %}\n\n{% block footer %}\n{% endblock footer %}\n`;\n}\n\n/**\n * Write a blog listing template alongside a blog post template.\n */\nfunction writeBlogListingTemplate(templatesDir: string, tpl: TemplateEntry): void {\n const listingContent = `<!--\n templateType: blog_listing\n isAvailableForNewContent: true\n label: \"${tpl.label} - Listing\"\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% block body %}\n<div class=\"blog-listing\">\n <h1>{{ group.public_title }}</h1>\n {% for content in contents %}\n <article class=\"blog-listing__post\">\n <h2><a href=\"{{ content.absolute_url }}\">{{ content.name }}</a></h2>\n {% if content.featured_image %}\n <img src=\"{{ content.featured_image }}\" alt=\"{{ content.featured_image_alt_text }}\">\n {% endif %}\n <p>{{ content.post_summary|truncatewords(30) }}</p>\n <span class=\"blog-listing__date\">{{ content.publish_date|datetimeformat('%B %d, %Y') }}</span>\n </article>\n {% endfor %}\n {% if next_page_num %}\n <a href=\"{{ next_page_url }}\">Next Page</a>\n {% endif %}\n</div>\n{% endblock body %}\n`;\n writeFileSync(\n join(templatesDir, `${tpl.id}-listing.html`),\n listingContent,\n \"utf-8\"\n );\n}\n\n/**\n * Get modules in display order for a specific template entry.\n */\nfunction getOrderedModulesFrom(tpl: TemplateEntry): ModuleFiles[] {\n const ordered: ModuleFiles[] = [];\n for (const name of tpl.moduleOrder) {\n const mod = tpl.modules.find((m) => m.moduleName === name);\n if (mod) ordered.push(mod);\n }\n for (const mod of tpl.modules) {\n if (!tpl.moduleOrder.includes(mod.moduleName)) {\n ordered.push(mod);\n }\n }\n return ordered;\n}\n\n/**\n * Build a HubSpot page template that assembles all modules in display order.\n * Legacy — used when no templates array exists (flat session).\n */\nfunction generateTemplateFromModules(): string {\n if (!activeSession || activeSession.modules.length === 0) return \"\";\n\n const name = activeSession.themeName;\n const ordered = getOrderedModules();\n\n const sections = ordered.map((mod) => {\n return ` {% dnd_section padding={\"top\":\"0\",\"bottom\":\"0\",\"left\":\"0\",\"right\":\"0\"}, full_width=true %}\n {% dnd_module path=\"../modules/${mod.moduleName}.module\" %}\n {% end_dnd_module %}\n {% end_dnd_section %}`;\n }).join(\"\\n\\n\");\n\n return `<!--\n templateType: page\n isAvailableForNewContent: true\n label: \"${name} Landing Page\"\n-->\n{% extends \"./layouts/base.html\" %}\n\n{% set template_css = \"../../css/${name}-theme.css\" %}\n{% set template_js = \"../../js/${name}-animations.js\" %}\n\n{% block header %}\n{% endblock header %}\n\n{% block body %}\n<div class=\"${name}-page\">\n {% dnd_area \"main_content\" label=\"${name} Landing Page\" %}\n\n${sections}\n\n {% end_dnd_area %}\n</div>\n{{ require_js(get_asset_url(\"../../js/${name}-animations.js\")) }}\n{% endblock body %}\n\n{% block footer %}\n{% endblock footer %}\n`;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generateId(): string {\n return `vibe-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction safeRead(filePath: string): string {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return \"\";\n }\n}\n\n/**\n * Set a default value at a dot-separated field path in a fields.json array.\n */\nfunction setFieldDefault(fields: FieldDef[], path: string, value: unknown): void {\n const parts = path.split(\".\");\n const fieldName = parts[0];\n const field = fields.find((f: FieldDef) => f.name === fieldName);\n if (!field) return;\n\n if (parts.length === 1) {\n field.default = value;\n } else if (field.children) {\n setFieldDefault(field.children, parts.slice(1).join(\".\"), value);\n }\n}\n\ninterface FieldDef {\n name: string;\n default?: unknown;\n children?: FieldDef[];\n}\n","/**\n * Per-project local git — auto-commits, version history, rollback.\n * All operations are local-only. Git is optional; if unavailable,\n * every function degrades gracefully (returns null / false / []).\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\n\nexport interface GitCommitInfo {\n hash: string; // short hash (7 chars)\n fullHash: string; // full SHA\n message: string; // first line of commit message\n timestamp: number; // unix epoch ms\n date: string; // ISO string for display\n}\n\n// ---------------------------------------------------------------------------\n// Git availability (cached)\n// ---------------------------------------------------------------------------\n\nlet gitAvailableCache: boolean | null = null;\n\nexport function isGitAvailable(): boolean {\n if (gitAvailableCache !== null) return gitAvailableCache;\n const result = run(\"git --version\");\n gitAvailableCache = result.success;\n return gitAvailableCache;\n}\n\n// ---------------------------------------------------------------------------\n// Repo initialization\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure a git repo exists in the theme directory.\n * Creates .gitignore, .vibespot/ dir, and initial commit if needed.\n * Safe to call multiple times (idempotent).\n */\nexport function ensureGitRepo(themePath: string): boolean {\n if (!isGitAvailable()) return false;\n\n // Already initialized\n if (existsSync(join(themePath, \".git\"))) {\n ensureVibeSpotDir(themePath);\n return true;\n }\n\n // Init repo\n const init = run(\"git init\", { cwd: themePath });\n if (!init.success) {\n console.warn(`[project-git] git init failed in ${themePath}: ${init.stderr}`);\n return false;\n }\n\n // Create .gitignore\n writeGitIgnore(themePath);\n\n // Create .vibespot/ dir for chat persistence\n ensureVibeSpotDir(themePath);\n\n // Initial commit\n run(\"git add -A\", { cwd: themePath });\n run('git commit -m \"Initial theme\"', { cwd: themePath });\n\n return true;\n}\n\nfunction ensureVibeSpotDir(themePath: string): void {\n const dir = join(themePath, \".vibespot\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nfunction writeGitIgnore(themePath: string): void {\n const gitignorePath = join(themePath, \".gitignore\");\n const lines = [\".vibespot/\", \"node_modules/\", \"\"];\n writeFileSync(gitignorePath, lines.join(\"\\n\"), \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// Committing\n// ---------------------------------------------------------------------------\n\n/**\n * Stage all changes and commit with the given message.\n * Returns the short commit hash, or null if nothing to commit or error.\n */\nexport function commitThemeState(themePath: string, message: string): string | null {\n if (!isGitAvailable()) return null;\n if (!existsSync(join(themePath, \".git\"))) return null;\n\n // Stage everything\n run(\"git add -A\", { cwd: themePath });\n\n // Check if there are staged changes\n const diff = run(\"git diff --cached --quiet\", { cwd: themePath });\n if (diff.success) return null; // exit 0 = nothing staged\n\n // Truncate message to 72 chars\n const truncated = message.length > 72\n ? message.slice(0, 69) + \"...\"\n : message;\n\n // Commit (use -- to prevent message from being interpreted as flags)\n const commitResult = run(`git commit -m \"${truncated.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n if (!commitResult.success) {\n console.warn(`[project-git] commit failed: ${commitResult.stderr}`);\n return null;\n }\n\n // Get short hash\n const hashResult = run(\"git rev-parse --short HEAD\", { cwd: themePath });\n return hashResult.success ? hashResult.stdout : null;\n}\n\n/**\n * Stage only specific files and commit with a template-scoped message.\n * Used for per-template version history so rollback doesn't affect other templates.\n */\nexport function commitTemplateState(\n themePath: string,\n templateId: string,\n message: string,\n filePaths: string[]\n): string | null {\n if (!isGitAvailable()) return null;\n if (!existsSync(join(themePath, \".git\"))) return null;\n\n // Stage only the specified paths\n for (const fp of filePaths) {\n const fullPath = join(themePath, fp);\n if (existsSync(fullPath)) {\n run(`git add \"${fp}\"`, { cwd: themePath });\n }\n }\n\n // Check if there are staged changes\n const diff = run(\"git diff --cached --quiet\", { cwd: themePath });\n if (diff.success) return null; // nothing staged\n\n // Build prefixed message: [templateId] user message\n const prefix = `[${templateId}] `;\n const maxMsg = 72 - prefix.length;\n const truncated = message.length > maxMsg\n ? message.slice(0, maxMsg - 3) + \"...\"\n : message;\n const fullMessage = prefix + truncated;\n\n const commitResult = run(`git commit -m \"${fullMessage.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n if (!commitResult.success) {\n console.warn(`[project-git] template commit failed: ${commitResult.stderr}`);\n return null;\n }\n\n const hashResult = run(\"git rev-parse --short HEAD\", { cwd: themePath });\n return hashResult.success ? hashResult.stdout : null;\n}\n\n// ---------------------------------------------------------------------------\n// History\n// ---------------------------------------------------------------------------\n\n/**\n * Get commit history (most recent first).\n */\nexport function getHistory(themePath: string, limit: number = 50): GitCommitInfo[] {\n if (!isGitAvailable()) return [];\n if (!existsSync(join(themePath, \".git\"))) return [];\n\n const result = run(\n `git log --pretty=format:\"%h|%H|%s|%at\" -n ${limit}`,\n { cwd: themePath }\n );\n if (!result.success || !result.stdout.trim()) return [];\n\n const commits: GitCommitInfo[] = [];\n for (const line of result.stdout.split(\"\\n\")) {\n const parts = line.split(\"|\");\n if (parts.length < 4) continue;\n const timestamp = parseInt(parts[3], 10) * 1000;\n commits.push({\n hash: parts[0],\n fullHash: parts[1],\n message: parts[2],\n timestamp,\n date: new Date(timestamp).toISOString(),\n });\n }\n return commits;\n}\n\n/**\n * Get commit history filtered to a specific template (by commit message prefix).\n */\nexport function getTemplateHistory(\n themePath: string,\n templateId: string,\n limit: number = 50\n): GitCommitInfo[] {\n if (!isGitAvailable()) return [];\n if (!existsSync(join(themePath, \".git\"))) return [];\n\n const escapedId = templateId.replace(/[[\\]\\\\]/g, \"\\\\$&\");\n const result = run(\n `git log --grep=\"\\\\[${escapedId}\\\\]\" --pretty=format:\"%h|%H|%s|%at\" -n ${limit}`,\n { cwd: themePath }\n );\n if (!result.success || !result.stdout.trim()) return [];\n\n const commits: GitCommitInfo[] = [];\n for (const line of result.stdout.split(\"\\n\")) {\n const parts = line.split(\"|\");\n if (parts.length < 4) continue;\n const timestamp = parseInt(parts[3], 10) * 1000;\n commits.push({\n hash: parts[0],\n fullHash: parts[1],\n message: parts[2],\n timestamp,\n date: new Date(timestamp).toISOString(),\n });\n }\n return commits;\n}\n\n// ---------------------------------------------------------------------------\n// Rollback\n// ---------------------------------------------------------------------------\n\n/**\n * Restore theme files to a specific commit's state.\n * Creates a new commit (\"Rollback to: <original message>\") to keep linear history.\n * Does NOT touch .vibespot/ (gitignored) — chat is preserved.\n */\nexport function rollbackToCommit(\n themePath: string,\n commitHash: string\n): { success: boolean; error?: string } {\n if (!isGitAvailable()) return { success: false, error: \"Git not available\" };\n if (!existsSync(join(themePath, \".git\"))) return { success: false, error: \"Not a git repo\" };\n\n // Verify commit exists\n const verify = run(`git cat-file -t ${commitHash}`, { cwd: themePath });\n if (!verify.success || verify.stdout.trim() !== \"commit\") {\n return { success: false, error: `Commit ${commitHash} not found` };\n }\n\n // Get original commit message\n const msgResult = run(`git log --format=\"%s\" -1 ${commitHash}`, { cwd: themePath });\n const origMessage = msgResult.success ? msgResult.stdout : commitHash;\n\n // Restore all files from that commit\n const checkout = run(`git checkout ${commitHash} -- .`, { cwd: themePath });\n if (!checkout.success) {\n return { success: false, error: `Checkout failed: ${checkout.stderr}` };\n }\n\n // Commit the rollback\n const rollbackMsg = `Rollback to: ${origMessage}`.slice(0, 72);\n run(`git commit -m \"${rollbackMsg.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n\n return { success: true };\n}\n\n/**\n * Restore only specific template files to a commit's state.\n * Other templates' files are left untouched.\n */\nexport function rollbackTemplateToCommit(\n themePath: string,\n templateId: string,\n commitHash: string,\n filePaths: string[]\n): { success: boolean; error?: string } {\n if (!isGitAvailable()) return { success: false, error: \"Git not available\" };\n if (!existsSync(join(themePath, \".git\"))) return { success: false, error: \"Not a git repo\" };\n\n // Verify commit exists\n const verify = run(`git cat-file -t ${commitHash}`, { cwd: themePath });\n if (!verify.success || verify.stdout.trim() !== \"commit\") {\n return { success: false, error: `Commit ${commitHash} not found` };\n }\n\n // Get original commit message\n const msgResult = run(`git log --format=\"%s\" -1 ${commitHash}`, { cwd: themePath });\n const origMessage = msgResult.success ? msgResult.stdout : commitHash;\n\n // Restore only the specified paths from that commit\n let restored = 0;\n for (const fp of filePaths) {\n const checkout = run(`git checkout ${commitHash} -- \"${fp}\"`, { cwd: themePath });\n if (checkout.success) restored++;\n // Skip paths that didn't exist at that commit (git errors silently ignored)\n }\n\n if (restored === 0) {\n return { success: false, error: \"No files could be restored from that commit\" };\n }\n\n // Stage and commit the scoped rollback\n run(\"git add -A\", { cwd: themePath });\n const prefix = `[${templateId}] `;\n const rollbackMsg = `${prefix}Rollback to: ${origMessage}`.slice(0, 72);\n run(`git commit -m \"${rollbackMsg.replace(/\"/g, '\\\\\"')}\"`, { cwd: themePath });\n\n return { success: true };\n}\n","/**\n * Lightweight HubL subset renderer for local preview.\n *\n * Supports the constructs that AI-generated HubSpot modules actually use:\n * {{ module.field }} — variable access\n * {{ module.group.child }} — nested access\n * {% if module.field %}...{% endif %} — conditionals (+ {% else %})\n * {% for item in module.list %}...{% endfor %} — loops\n * {{ item.field }} — loop variable access\n *\n * get_asset_url(\"assets/...\") is resolved to /theme-assets/ for local preview.\n * Everything else (require_css, dnd_area, etc.) is stripped.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface FieldDef {\n name: string;\n type: string;\n default?: unknown;\n children?: FieldDef[];\n occurrence?: { min: number; max: number };\n tab?: string;\n}\n\nexport interface RenderContext {\n module: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a render context from a fields.json array, using each field's default.\n */\nexport function buildContextFromFields(fields: FieldDef[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const field of fields) {\n if (field.type === \"group\" && field.occurrence && Array.isArray(field.default)) {\n // Repeater group — default is an array of objects\n result[field.name] = field.default;\n } else if (field.type === \"group\" && field.children) {\n // Nested group (e.g. styles) — recurse into children\n result[field.name] = buildContextFromFields(field.children);\n } else {\n result[field.name] = field.default ?? \"\";\n }\n }\n\n return result;\n}\n\n/**\n * Render a HubL template string with the given context.\n * Returns plain HTML suitable for browser rendering.\n */\nexport function renderHubL(template: string, context: RenderContext): string {\n let output = template;\n\n // 1. Strip HubSpot-only directives that don't apply in preview\n output = stripDirectives(output);\n\n // 2. Process {% for %} loops (must come before if/expressions)\n output = processForLoops(output, context);\n\n // 3. Process {% if %} / {% else %} / {% endif %} conditionals\n output = processConditionals(output, context);\n\n // 4. Resolve {{ expression }} variable references\n output = resolveExpressions(output, context);\n\n // 5. Clean up any remaining unresolved tags\n output = cleanupRemaining(output);\n\n return output;\n}\n\n/**\n * Assemble a full preview HTML page from rendered modules + CSS/JS.\n */\nexport function assemblePreview(opts: {\n renderedModules: string[];\n sharedCss?: string;\n moduleCssArray: string[];\n sharedJs?: string;\n moduleJsArray: string[];\n}): string {\n const styleBlocks = [\n opts.sharedCss || \"\",\n ...opts.moduleCssArray,\n ]\n .filter(Boolean)\n .map((css) => `<style>${css}</style>`)\n .join(\"\\n\");\n\n const scriptBlocks = [\n opts.sharedJs || \"\",\n ...opts.moduleJsArray,\n ]\n .filter(Boolean)\n .map((js) => `<script>${js}</script>`)\n .join(\"\\n\");\n\n const body = opts.renderedModules.join(\"\\n\");\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n${styleBlocks}\n<style>\nhtml{scroll-behavior:smooth}\n.vsp-img-wrap{position:relative;display:inline-block}\n.vsp-img-badge{position:absolute;top:8px;right:8px;background:rgba(0,0,0,.75);color:#fff;font:500 11px/1 -apple-system,sans-serif;padding:5px 8px;border-radius:4px;pointer-events:none;opacity:.85;white-space:nowrap;z-index:10}\n</style>\n</head>\n<body>\n${body}\n${scriptBlocks}\n<script>\n// Anchor link handler — smooth scroll to module sections\ndocument.addEventListener('click',function(e){\n var a=e.target.closest('a[href^=\"#\"]');\n if(!a)return;\n var id=a.getAttribute('href').slice(1);\n if(!id)return;\n var el=document.getElementById(id);\n if(el){\n e.preventDefault();\n el.scrollIntoView({behavior:'smooth',block:'start'});\n }\n});\n// Placeholder image badges\ndocument.querySelectorAll('img').forEach(function(img){\n var src=img.src||img.getAttribute('src')||'';\n if(src.indexOf('placehold')!==-1){\n var w=document.createElement('span');\n w.className='vsp-img-wrap';\n img.parentNode.insertBefore(w,img);\n w.appendChild(img);\n var b=document.createElement('span');\n b.className='vsp-img-badge';\n b.textContent='Placeholder — replace in HubSpot';\n w.appendChild(b);\n }\n});\n</script>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\n// Pre-compiled regex patterns for stripDirectives (avoid recompilation per render)\nconst RE_REQUIRE_TAG = /\\{%[-\\s]*require_(css|js)\\b.*?%\\}/gs;\nconst RE_END_REQUIRE_TAG = /\\{%[-\\s]*end_require_(css|js)\\s*%\\}/gs;\nconst RE_REQUIRE_EXPR = /\\{\\{[-\\s]*require_(css|js)\\(.*?\\)\\s*\\}\\}/gs;\nconst RE_GET_ASSET_URL = /\\{\\{[-\\s]*get_asset_url\\([\"'](?:[^\"'\\/]+\\/)?assets\\/(.*?)[\"']\\)\\s*\\}\\}/gs;\nconst RE_GET_ASSET_URL_STRIP = /\\{\\{[-\\s]*get_asset_url\\(.*?\\)\\s*\\}\\}/gs;\nconst RE_DND_TAGS = /\\{%[-\\s]*(end_)?(dnd_area|dnd_section|dnd_column|dnd_row|dnd_module)\\b.*?%\\}/gs;\nconst RE_MODULE_TAG = /\\{%[-\\s]*module\\b.*?%\\}/gs;\nconst RE_TEMPLATE_TAGS = /\\{%[-\\s]*(extends|block|endblock|set)\\b.*?%\\}/gs;\nconst RE_ANNOTATIONS = /\\{#.*?#\\}/gs;\nconst RE_CONTENT_VARS = /\\{\\{[-\\s]*content\\.\\w+.*?\\}\\}/gs;\nconst RE_IF_PATTERN = /\\{%[-\\s]*if\\s+(.*?)\\s*-?%\\}([\\s\\S]*?)\\{%[-\\s]*endif\\s*-?%\\}/g;\n\n/**\n * Strip HubSpot-specific directives that have no meaning in local preview.\n */\nfunction stripDirectives(tpl: string): string {\n tpl = tpl.replace(RE_REQUIRE_TAG, \"\");\n tpl = tpl.replace(RE_END_REQUIRE_TAG, \"\");\n tpl = tpl.replace(RE_REQUIRE_EXPR, \"\");\n // Resolve get_asset_url(\"assets/filename\") → /theme-assets/filename for preview\n RE_GET_ASSET_URL.lastIndex = 0;\n tpl = tpl.replace(RE_GET_ASSET_URL, (_match, filename) => `/theme-assets/${filename}`);\n // Strip any remaining get_asset_url() calls with non-standard paths\n RE_GET_ASSET_URL_STRIP.lastIndex = 0;\n tpl = tpl.replace(RE_GET_ASSET_URL_STRIP, \"\");\n tpl = tpl.replace(RE_DND_TAGS, \"\");\n tpl = tpl.replace(RE_MODULE_TAG, \"\");\n tpl = tpl.replace(RE_TEMPLATE_TAGS, \"\");\n tpl = tpl.replace(RE_ANNOTATIONS, \"\");\n tpl = tpl.replace(RE_CONTENT_VARS, \"\");\n return tpl;\n}\n\n/**\n * Process {% for VAR in PATH %}...{% endfor %} loops.\n * Uses balanced tag matching to handle nested for-loops correctly.\n */\nfunction processForLoops(tpl: string, context: RenderContext): string {\n let result = tpl;\n let safety = 0;\n\n while (safety < 30) {\n safety++;\n const match = findOutermostFor(result);\n if (!match) break;\n\n const { varName, iterExpr, body, start, end } = match;\n const items = resolveIterable(iterExpr, context);\n\n let rendered = \"\";\n if (Array.isArray(items)) {\n rendered = items\n .map((item, index) => {\n const loopContext: RenderContext = {\n ...context,\n [varName]: item,\n loop: { index: index + 1, index0: index, first: index === 0, last: index === items.length - 1, length: items.length },\n };\n\n let out = processForLoops(body, loopContext);\n out = processConditionals(out, loopContext);\n out = resolveExpressions(out, loopContext);\n return out;\n })\n .join(\"\");\n }\n\n result = result.slice(0, start) + rendered + result.slice(end);\n }\n\n return result;\n}\n\n/**\n * Find the first outermost {% for %}...{% endfor %} block with balanced nesting.\n */\nfunction findOutermostFor(tpl: string): { varName: string; iterExpr: string; body: string; start: number; end: number } | null {\n const openTag = /\\{%[-\\s]*for\\s+(\\w+)\\s+in\\s+([\\w.]+(?:\\([^)]*\\))?(?:\\|[\\w(),\"' ]+)*)\\s*-?%\\}/g;\n const forOrEndfor = /\\{%[-\\s]*(for\\s|endfor)\\s*.*?-?%\\}/g;\n\n const firstOpen = openTag.exec(tpl);\n if (!firstOpen) return null;\n\n const varName = firstOpen[1];\n const iterExpr = firstOpen[2];\n const bodyStart = firstOpen.index + firstOpen[0].length;\n\n // Find matching endfor by counting nesting depth\n forOrEndfor.lastIndex = bodyStart;\n let depth = 1;\n let m: RegExpExecArray | null;\n\n while ((m = forOrEndfor.exec(tpl)) !== null) {\n if (m[1].startsWith(\"for\")) {\n depth++;\n } else {\n depth--;\n if (depth === 0) {\n const body = tpl.slice(bodyStart, m.index);\n return { varName, iterExpr, body, start: firstOpen.index, end: m.index + m[0].length };\n }\n }\n }\n\n return null; // Unmatched for-loop\n}\n\n/**\n * Process {% if EXPR %}...{% else %}...{% endif %} conditionals.\n * Supports {% elif %} as well.\n */\nfunction processConditionals(tpl: string, context: RenderContext): string {\n // Process from innermost out\n let result = tpl;\n let safety = 0;\n\n while (RE_IF_PATTERN.test(result) && safety < 50) {\n safety++;\n result = result.replace(RE_IF_PATTERN, (_match, condition: string, body: string) => {\n // Split on {% else %} and {% elif %}\n const elseMatch = body.split(/\\{%[-\\s]*else\\s*-?%\\}/);\n const ifBody = elseMatch[0];\n const elseBody = elseMatch[1] || \"\";\n\n // Check for {% elif %} (treat as nested if-else)\n const elifParts = ifBody.split(/\\{%[-\\s]*elif\\s+(.*?)\\s*-?%\\}/);\n\n if (elifParts.length > 1) {\n // Has elif branches\n if (evaluateCondition(condition, context)) {\n return elifParts[0];\n }\n // Check elif branches\n for (let i = 1; i < elifParts.length; i += 2) {\n const elifCondition = elifParts[i];\n const elifBody = elifParts[i + 1] || \"\";\n if (evaluateCondition(elifCondition, context)) {\n return elifBody;\n }\n }\n return elseBody;\n }\n\n if (evaluateCondition(condition, context)) {\n return ifBody;\n }\n return elseBody;\n });\n\n RE_IF_PATTERN.lastIndex = 0;\n }\n\n return result;\n}\n\n/**\n * Resolve all {{ expression }} references in the template.\n */\nfunction resolveExpressions(tpl: string, context: RenderContext): string {\n return tpl.replace(/\\{\\{[-\\s]*(.*?)[-\\s]*\\}\\}/g, (_match, expr: string) => {\n const trimmed = expr.trim();\n\n // Handle filters: {{ value|filter }}\n const filterParts = trimmed.split(\"|\");\n const path = filterParts[0].trim();\n\n let value = resolvePath(context, path);\n\n // Apply basic filters\n for (let i = 1; i < filterParts.length; i++) {\n value = applyFilter(value, filterParts[i].trim());\n }\n\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"object\") return JSON.stringify(value);\n return String(value);\n });\n}\n\n/**\n * Clean up any remaining HubL tags that weren't handled.\n */\nfunction cleanupRemaining(tpl: string): string {\n // Remove any remaining {% ... %} tags\n tpl = tpl.replace(/\\{%.*?%\\}/gs, \"\");\n // Remove any remaining {{ ... }} that reference unknown paths\n tpl = tpl.replace(/\\{\\{.*?\\}\\}/gs, \"\");\n return tpl;\n}\n\n/**\n * Resolve an iterable expression for {% for %} loops.\n * Handles dotted paths (module.services) and range(start, end) calls.\n */\nfunction resolveIterable(expr: string, context: RenderContext): unknown {\n // Handle range(start, end) — with possible filter on args\n const rangeMatch = expr.match(/^range\\(\\s*(.+?)\\s*,\\s*(.+?)\\s*\\)$/);\n if (rangeMatch) {\n const start = resolveNumericArg(rangeMatch[1], context);\n const end = resolveNumericArg(rangeMatch[2], context);\n const arr: number[] = [];\n for (let i = start; i < end; i++) arr.push(i);\n return arr;\n }\n\n // Handle split('...') filter: \"value|split('\\n')\"\n const splitMatch = expr.match(/^(.+?)\\|split\\(['\"](.+?)['\"]\\)$/);\n if (splitMatch) {\n const val = resolvePath(context, splitMatch[1].trim());\n if (typeof val === \"string\") return val.split(splitMatch[2]);\n return [];\n }\n\n return resolvePath(context, expr);\n}\n\n/**\n * Resolve a numeric argument that may be a literal, a path, or a path|filter.\n */\nfunction resolveNumericArg(arg: string, context: RenderContext): number {\n const trimmed = arg.trim();\n\n // Apply filters (e.g. \"item.rating|int\")\n const filterParts = trimmed.split(\"|\");\n const path = filterParts[0].trim();\n\n // Literal number\n if (!isNaN(Number(path))) return Number(path);\n\n // Path lookup\n let value = resolvePath(context, path);\n for (let i = 1; i < filterParts.length; i++) {\n value = applyFilter(value, filterParts[i].trim());\n }\n return Number(value) || 0;\n}\n\n/**\n * Resolve a dot-path expression against a context object.\n * E.g. \"module.styles.bg_color.color\" → context.module.styles.bg_color.color\n */\nfunction resolvePath(context: RenderContext, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = context;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n\n/**\n * Evaluate a simple condition expression.\n * Supports: path truthiness, \"not path\", \"path == value\", \"path != value\"\n */\nfunction evaluateCondition(expr: string, context: RenderContext): boolean {\n const trimmed = expr.trim();\n\n // Handle \"not\" prefix\n if (trimmed.startsWith(\"not \")) {\n return !evaluateCondition(trimmed.slice(4), context);\n }\n\n // Handle \"and\" / \"or\"\n if (trimmed.includes(\" and \")) {\n return trimmed.split(\" and \").every((part) => evaluateCondition(part, context));\n }\n if (trimmed.includes(\" or \")) {\n return trimmed.split(\" or \").some((part) => evaluateCondition(part, context));\n }\n\n // Handle comparison operators\n const eqMatch = trimmed.match(/^(.+?)\\s*(==|!=|>=|<=|>|<)\\s*(.+)$/);\n if (eqMatch) {\n const left = resolvePath(context, eqMatch[1].trim());\n const operator = eqMatch[2];\n let right: unknown = eqMatch[3].trim();\n\n // Parse right side: string literal, number, or path\n if (\n (typeof right === \"string\" && right.startsWith('\"') && right.endsWith('\"')) ||\n (typeof right === \"string\" && right.startsWith(\"'\") && right.endsWith(\"'\"))\n ) {\n right = (right as string).slice(1, -1);\n } else if (!isNaN(Number(right))) {\n right = Number(right);\n } else {\n right = resolvePath(context, right as string);\n }\n\n switch (operator) {\n case \"==\": return left == right;\n case \"!=\": return left != right;\n case \">\": return Number(left) > Number(right);\n case \"<\": return Number(left) < Number(right);\n case \">=\": return Number(left) >= Number(right);\n case \"<=\": return Number(left) <= Number(right);\n }\n }\n\n // Simple truthiness\n const value = resolvePath(context, trimmed);\n return isTruthy(value);\n}\n\n/**\n * Check HubL-style truthiness (empty strings and 0 are falsy).\n */\nfunction isTruthy(value: unknown): boolean {\n if (value === null || value === undefined) return false;\n if (value === \"\") return false;\n if (value === 0) return false;\n if (value === false) return false;\n if (Array.isArray(value) && value.length === 0) return false;\n return true;\n}\n\n/**\n * Apply a basic HubL filter.\n */\nfunction applyFilter(value: unknown, filter: string): unknown {\n const str = value === null || value === undefined ? \"\" : String(value);\n\n // Handle filters with arguments: truncate(100), default(\"fallback\")\n const argMatch = filter.match(/^(\\w+)\\((.*)\\)$/);\n const filterName = argMatch ? argMatch[1] : filter;\n const filterArg = argMatch ? argMatch[2].replace(/^[\"']|[\"']$/g, \"\") : undefined;\n\n switch (filterName) {\n case \"escape\":\n case \"e\":\n return str.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n case \"lower\":\n return str.toLowerCase();\n case \"upper\":\n return str.toUpperCase();\n case \"capitalize\":\n return str.charAt(0).toUpperCase() + str.slice(1);\n case \"trim\":\n return str.trim();\n case \"truncate\":\n if (filterArg) {\n const len = parseInt(filterArg, 10);\n return str.length > len ? str.slice(0, len) + \"...\" : str;\n }\n return str;\n case \"default\":\n return isTruthy(value) ? value : (filterArg ?? \"\");\n case \"length\":\n if (Array.isArray(value)) return value.length;\n return str.length;\n case \"join\":\n if (Array.isArray(value)) return value.join(filterArg ?? \", \");\n return str;\n case \"int\":\n case \"float\":\n return Number(str) || 0;\n case \"abs\":\n return Math.abs(Number(str));\n case \"round\":\n return Math.round(Number(str));\n default:\n // Unknown filter — pass through\n return value;\n }\n}\n","/**\n * Preview builder — assembles rendered HubL modules into a full HTML page.\n */\n\nimport {\n renderHubL,\n buildContextFromFields,\n assemblePreview,\n type FieldDef,\n} from \"../hubl/renderer.js\";\nimport { getSession, getOrderedModules } from \"./session.js\";\n\n/**\n * Build a full preview HTML page from the current session state.\n * Each module's HubL template is rendered with its fields.json defaults,\n * then assembled with shared CSS/JS into a complete page.\n */\nexport function buildPreviewHtml(): string {\n const session = getSession();\n if (!session) {\n return welcomePreview();\n }\n\n const modules = getOrderedModules();\n if (modules.length === 0) {\n return welcomePreview();\n }\n\n const renderedModules: string[] = [];\n const moduleCssArray: string[] = [];\n const moduleJsArray: string[] = [];\n\n for (const mod of modules) {\n // Skip template-like content that was accidentally stored as a module\n if (mod.moduleHtml.includes(\"dnd_area\") || mod.moduleHtml.includes(\"extends \")) {\n continue;\n }\n\n // Build context from fields.json defaults\n let context: { module: Record<string, unknown> };\n try {\n const fields: FieldDef[] = JSON.parse(mod.fieldsJson);\n context = { module: buildContextFromFields(fields) };\n } catch {\n context = { module: {} };\n }\n\n // Render HubL template with context\n const rendered = renderHubL(mod.moduleHtml, context);\n\n // Wrap each module in a container with id + data attribute for anchor links\n const anchorId = mod.moduleName.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-|-$/g, \"\");\n renderedModules.push(\n `<div class=\"vibespot-module\" id=\"${anchorId}\" data-module=\"${mod.moduleName}\">${rendered}</div>`\n );\n\n if (mod.moduleCss) moduleCssArray.push(mod.moduleCss);\n if (mod.moduleJs) moduleJsArray.push(mod.moduleJs);\n }\n\n return assemblePreview({\n renderedModules,\n sharedCss: session.sharedCss,\n moduleCssArray,\n sharedJs: session.sharedJs,\n moduleJsArray,\n });\n}\n\n/**\n * Static welcome screen — shown before first generation.\n */\nfunction welcomePreview(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n background: #0f0f14;\n color: #888;\n }\n .welcome {\n text-align: center;\n padding: 2rem;\n }\n .welcome__wave {\n font-size: 4rem;\n margin-bottom: 1.2rem;\n opacity: 0.4;\n animation: float 3s ease-in-out infinite;\n }\n @keyframes float {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-6px); }\n }\n .welcome__title {\n font-size: 1.4rem;\n font-weight: 600;\n color: #bbb;\n letter-spacing: 0.5px;\n margin-bottom: 0.4rem;\n }\n .welcome__sub {\n font-size: 1rem;\n color: #666;\n font-weight: 300;\n }\n</style>\n</head>\n<body>\n<div class=\"welcome\">\n <div class=\"welcome__wave\">\\u224B</div>\n <div class=\"welcome__title\">vibeSpot</div>\n <div class=\"welcome__sub\">Build Something Great</div>\n</div>\n</body>\n</html>`;\n}\n\n/**\n * Build a preview HTML page for a single module (used by the dashboard module library).\n */\nexport function buildModulePreviewHtml(moduleName: string): string {\n const session = getSession();\n if (!session) return \"\";\n\n // Find the module across all templates\n let mod: typeof session.modules[0] | undefined;\n for (const tpl of session.templates) {\n mod = tpl.modules.find((m) => m.moduleName === moduleName);\n if (mod) break;\n }\n // Fallback: check flat modules array\n if (!mod) {\n mod = session.modules.find((m) => m.moduleName === moduleName);\n }\n if (!mod) return \"\";\n\n let context: { module: Record<string, unknown> };\n try {\n const fields: FieldDef[] = JSON.parse(mod.fieldsJson);\n context = { module: buildContextFromFields(fields) };\n } catch {\n context = { module: {} };\n }\n\n const rendered = renderHubL(mod.moduleHtml, context);\n\n return assemblePreview({\n renderedModules: [\n `<div class=\"vibespot-module\" data-module=\"${mod.moduleName}\">${rendered}</div>`,\n ],\n sharedCss: session.sharedCss,\n moduleCssArray: mod.moduleCss ? [mod.moduleCss] : [],\n sharedJs: session.sharedJs,\n moduleJsArray: mod.moduleJs ? [mod.moduleJs] : [],\n });\n}\n\n// Note: The generating screen (spinner + rotating messages) is now\n// rendered client-side in preview.js to avoid an extra server round-trip.\n","/**\n * AI handler coordinator for vibe coding mode.\n * Dispatches to engine implementations, manages generation state,\n * and delegates response parsing.\n */\n\nimport { execSync } from \"node:child_process\";\nimport { loadConfig, getApiKeyForEngine, type AIEngineType } from \"../utils/config.js\";\nimport { getSession, addMessage, saveSession } from \"./session.js\";\nimport { parseAndApplyModules } from \"./ai-parser.js\";\nimport { log } from \"./log.js\";\nimport {\n streamWithAnthropicAPI,\n streamWithOpenAIAPI,\n streamWithGeminiAPI,\n generateWithClaudeCode,\n generateWithCLI,\n} from \"./ai-engines.js\";\nimport { getFileContexts } from \"./routes/upload-files.js\";\n\n// ---------------------------------------------------------------------------\n// Parse warning callback — set by the WebSocket handler\n// ---------------------------------------------------------------------------\n\nlet parseWarningCallback: ((warning: string) => void) | null = null;\n\nexport function setParseWarningCallback(cb: ((warning: string) => void) | null): void {\n parseWarningCallback = cb;\n}\n\n// ---------------------------------------------------------------------------\n// Generation lock — prevents session switching while AI is generating\n// ---------------------------------------------------------------------------\n\nlet generatingSessionId: string | null = null;\n\nexport function isGenerating(): boolean {\n return generatingSessionId !== null;\n}\n\n// ---------------------------------------------------------------------------\n// Finish response — save message and parse modules\n// ---------------------------------------------------------------------------\n\nfunction finishResponse(fullResponse: string): void {\n if (generatingSessionId) {\n const current = getSession();\n if (!current || current.id !== generatingSessionId) {\n log.warn(\"ai-handler\", \"Session changed during generation — discarding AI output\");\n return;\n }\n }\n addMessage(\"assistant\", fullResponse);\n parseAndApplyModules(fullResponse, parseWarningCallback || undefined);\n saveSession();\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Stream an AI response for a chat message.\n * Calls onChunk with text fragments as they arrive.\n * After the full response, parses module JSON blocks and updates the session.\n */\nexport async function handleGenerateStream(\n userMessage: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void,\n fileIds?: string[]\n): Promise<void> {\n const session = getSession();\n if (!session) throw new Error(\"No active session\");\n\n const capturedSessionId = session.id;\n generatingSessionId = capturedSessionId;\n\n // Load file contexts for any attached files\n const fileContexts = fileIds?.length ? getFileContexts(fileIds) : undefined;\n\n try {\n const config = loadConfig();\n const engine = config.aiEngine || detectDefaultEngine();\n\n switch (engine) {\n case \"anthropic-api\":\n case \"api\": {\n const apiKey = getApiKeyForEngine(\"anthropic-api\", config);\n if (!apiKey) throw new Error(\"Anthropic API key not configured. Open Settings to add one.\");\n await streamWithAnthropicAPI(userMessage, apiKey, session.themeName,\n config.anthropicApiModel || \"claude-sonnet-4-6\", onChunk, onStatus, finishResponse, fileContexts);\n break;\n }\n case \"openai-api\": {\n const apiKey = getApiKeyForEngine(\"openai-api\", config);\n if (!apiKey) throw new Error(\"OpenAI API key not configured. Open Settings to add one.\");\n await streamWithOpenAIAPI(userMessage, apiKey, session.themeName,\n config.openaiApiModel || \"gpt-4o\", onChunk, onStatus, finishResponse, fileContexts);\n break;\n }\n case \"gemini-api\": {\n const apiKey = getApiKeyForEngine(\"gemini-api\", config);\n if (!apiKey) throw new Error(\"Gemini API key not configured. Open Settings to add one.\");\n await streamWithGeminiAPI(userMessage, apiKey, session.themeName, onChunk, onStatus, finishResponse, fileContexts);\n break;\n }\n case \"claude-code\":\n await generateWithClaudeCode(userMessage, session.themeName, onChunk, onStatus, finishResponse, fileContexts);\n break;\n case \"gemini-cli\":\n await generateWithCLI(\"gemini\", userMessage, session.themeName, onChunk, onStatus, finishResponse, fileContexts);\n break;\n case \"codex-cli\":\n await generateWithCLI(\"codex\", userMessage, session.themeName, onChunk, onStatus, finishResponse, fileContexts);\n break;\n default:\n throw new Error(`Unknown AI engine: ${engine}. Open Settings to configure one.`);\n }\n } finally {\n generatingSessionId = null;\n parseWarningCallback = null;\n }\n}\n\n/**\n * Detect the best available engine when none is configured.\n */\nfunction detectDefaultEngine(): AIEngineType {\n const config = loadConfig();\n if (config.anthropicApiKey || process.env.ANTHROPIC_API_KEY) return \"anthropic-api\";\n if (config.openaiApiKey || process.env.OPENAI_API_KEY) return \"openai-api\";\n if (config.geminiApiKey || process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY) return \"gemini-api\";\n try { execSync(\"claude --version\", { stdio: \"pipe\" }); return \"claude-code\"; } catch {}\n try { execSync(\"gemini --version\", { stdio: \"pipe\" }); return \"gemini-cli\"; } catch {}\n try { execSync(\"codex --version\", { stdio: \"pipe\" }); return \"codex-cli\"; } catch {}\n throw new Error(\"No AI engine available. Open Settings to configure one.\");\n}\n\n/**\n * Non-streaming generation (used by REST API fallback).\n */\nexport async function handleGenerate(userMessage: string): Promise<string> {\n let fullResponse = \"\";\n await handleGenerateStream(userMessage, (chunk) => {\n fullResponse += chunk;\n });\n return fullResponse;\n}\n","/**\n * Structured logging helper.\n * Prefixes all output with a context tag for easy filtering.\n * In SaaS, this can be swapped for a proper logging library (pino, winston).\n */\n\nexport const log = {\n info(context: string, message: string, data?: Record<string, unknown>): void {\n const line = data\n ? `[${context}] ${message} ${JSON.stringify(data)}`\n : `[${context}] ${message}`;\n console.log(line);\n },\n\n warn(context: string, message: string, data?: Record<string, unknown>): void {\n const line = data\n ? `[${context}] ${message} ${JSON.stringify(data)}`\n : `[${context}] ${message}`;\n console.warn(line);\n },\n\n error(context: string, message: string, err?: unknown): void {\n const errMsg = err instanceof Error ? err.message : err ? String(err) : \"\";\n const line = errMsg\n ? `[${context}] ${message}: ${errMsg}`\n : `[${context}] ${message}`;\n console.error(line);\n },\n};\n","/**\n * AI response parser — extracts vibespot-modules JSON from AI responses.\n */\n\nimport { updateModules } from \"./session.js\";\nimport type { ModuleFiles } from \"../ai/engine.js\";\nimport { log } from \"./log.js\";\n\n/**\n * Try JSON.parse, and if it fails, attempt to repair common AI JSON issues\n * (unescaped quotes inside string values) and retry.\n */\nexport function tryParseJSON(raw: string): unknown | null {\n try {\n return JSON.parse(raw);\n } catch {\n // Fall through to repair\n }\n\n let repaired = raw;\n let lastPos = -1;\n for (let attempt = 0; attempt < 20; attempt++) {\n try {\n return JSON.parse(repaired);\n } catch (err) {\n if (!(err instanceof SyntaxError)) return null;\n const posMatch = /position (\\d+)/.exec(err.message);\n if (!posMatch) return null;\n const pos = parseInt(posMatch[1], 10);\n if (pos <= lastPos) return null;\n lastPos = pos;\n const searchStart = Math.max(0, pos - 5);\n const nearSlice = repaired.slice(searchStart, pos + 1);\n const lastQuote = nearSlice.lastIndexOf('\"');\n if (lastQuote === -1) return null;\n const absPos = searchStart + lastQuote;\n if (absPos > 0 && repaired[absPos - 1] === \"\\\\\") return null;\n repaired = repaired.slice(0, absPos) + '\\\\\"' + repaired.slice(absPos + 1);\n }\n }\n return null;\n}\n\n/**\n * Attempt to salvage a truncated JSON response by finding complete module objects.\n */\nexport function tryRepairTruncatedJSON(raw: string): Record<string, unknown> | null {\n const modulesIdx = raw.indexOf('\"modules\"');\n if (modulesIdx === -1) return null;\n\n const arrayStart = raw.indexOf(\"[\", modulesIdx);\n if (arrayStart === -1) return null;\n\n let lastCompleteModule = -1;\n let braceDepth = 0;\n let inString = false;\n let escaped = false;\n\n for (let i = arrayStart + 1; i < raw.length; i++) {\n const ch = raw[i];\n if (escaped) { escaped = false; continue; }\n if (ch === \"\\\\\") { escaped = true; continue; }\n if (ch === '\"') { inString = !inString; continue; }\n if (inString) continue;\n\n if (ch === \"{\") braceDepth++;\n if (ch === \"}\") {\n braceDepth--;\n if (braceDepth === 0) {\n lastCompleteModule = i;\n }\n }\n }\n\n if (lastCompleteModule === -1) return null;\n\n const upToLastModule = raw.slice(0, lastCompleteModule + 1);\n const repaired = upToLastModule + \"]}\";\n\n const jsonStr = repaired.trimStart().startsWith(\"{\") ? repaired : \"{\" + repaired;\n return tryParseJSON(jsonStr) as Record<string, unknown> | null;\n}\n\n/**\n * Convert a raw module object from AI JSON into a ModuleFiles entry.\n */\nfunction toModuleFiles(m: Record<string, unknown>): ModuleFiles {\n return {\n moduleName: String(m.moduleName || \"\"),\n fieldsJson: typeof m.fieldsJson === \"string\"\n ? m.fieldsJson\n : JSON.stringify(m.fieldsJson, null, 2),\n metaJson: typeof m.metaJson === \"string\"\n ? m.metaJson\n : JSON.stringify(m.metaJson, null, 2),\n moduleHtml: String(m.moduleHtml || \"\"),\n moduleCss: String(m.moduleCss || \"\"),\n moduleJs: m.moduleJs ? String(m.moduleJs) : undefined,\n };\n}\n\n/**\n * Parse vibespot-modules JSON blocks from an AI response and update the session.\n */\nexport function parseAndApplyModules(\n response: string,\n onWarning?: (warning: string) => void\n): void {\n let modulesApplied = false;\n let match;\n\n // Look for ```vibespot-modules ... ``` blocks\n const blockPattern = /```vibespot-modules\\s*\\n?([\\s\\S]*?)```/g;\n\n while ((match = blockPattern.exec(response)) !== null) {\n try {\n log.info(\"parse\", \"Found vibespot-modules block\", { length: match[1].length });\n const data = tryParseJSON(match[1]);\n if (!data || typeof data !== \"object\") {\n log.warn(\"parse\", \"tryParseJSON returned non-object\", { result: typeof data });\n throw new Error(\"Invalid JSON after repair\");\n }\n\n const obj = data as Record<string, unknown>;\n if (obj.modules && Array.isArray(obj.modules)) {\n updateModules({\n modules: obj.modules.map((m: Record<string, unknown>) => toModuleFiles(m)),\n sharedCss: obj.sharedCss !== undefined ? String(obj.sharedCss) : undefined,\n sharedJs: obj.sharedJs !== undefined ? String(obj.sharedJs) : undefined,\n });\n modulesApplied = true;\n }\n } catch (err) {\n log.warn(\"parse\", \"Failed to parse vibespot-modules block\", { error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n // Also try to find standalone JSON that looks like module data\n if (!modulesApplied) {\n const jsonPattern = /```(?:json)?\\s*\\n([\\s\\S]*?)```/g;\n while ((match = jsonPattern.exec(response)) !== null) {\n if (!match[1].includes('\"modules\"')) continue;\n try {\n const data = tryParseJSON(match[1]);\n if (!data || typeof data !== \"object\") throw new Error(\"Invalid JSON after repair\");\n const obj = data as Record<string, unknown>;\n if (obj.modules && Array.isArray(obj.modules)) {\n updateModules({\n modules: obj.modules.map((m: Record<string, unknown>) => toModuleFiles(m)),\n sharedCss: obj.sharedCss !== undefined ? String(obj.sharedCss) : undefined,\n sharedJs: obj.sharedJs !== undefined ? String(obj.sharedJs) : undefined,\n });\n modulesApplied = true;\n }\n } catch (err) {\n log.warn(\"parse\", \"Failed to parse JSON module block\", { error: err instanceof Error ? err.message : String(err) });\n }\n }\n }\n\n // Handle truncated responses (hit max_tokens — unclosed code fence)\n if (!modulesApplied) {\n const fenceCount = (response.match(/```/g) || []).length;\n if (fenceCount % 2 !== 0 && response.includes('\"modules\"')) {\n log.info(\"parse\", \"Detected truncated response (odd fence count), attempting salvage\");\n const lastFenceIdx = response.lastIndexOf(\"```\");\n let truncated = response.slice(lastFenceIdx + 3);\n truncated = truncated.replace(/^[\\w-]*\\s*\\n?/, \"\");\n const salvaged = tryRepairTruncatedJSON(truncated);\n if (salvaged) {\n const obj = salvaged as Record<string, unknown>;\n if (obj.modules && Array.isArray(obj.modules) && obj.modules.length > 0) {\n log.info(\"parse\", \"Salvaged modules from truncated response\", { count: obj.modules.length });\n updateModules({\n modules: (obj.modules as Record<string, unknown>[]).map((m) => toModuleFiles(m)),\n sharedCss: obj.sharedCss !== undefined ? String(obj.sharedCss) : undefined,\n sharedJs: obj.sharedJs !== undefined ? String(obj.sharedJs) : undefined,\n });\n modulesApplied = true;\n if (onWarning) {\n onWarning(\"Response was truncated — some modules may be incomplete. Try sending your request again for the full set.\");\n }\n }\n }\n }\n }\n\n // Warn user if the response looked like it should contain modules but parsing failed\n if (!modulesApplied) {\n log.info(\"parse\", \"No modules applied\", {\n responseLength: response.length,\n hasVibespot: response.includes(\"vibespot-modules\"),\n hasModules: response.includes('\"modules\"'),\n fenceCount: (response.match(/```/g) || []).length,\n });\n const hasModuleRef = response.includes(\"vibespot-modules\") || response.includes('\"modules\"');\n const describesProse = /\\bmodule|modul/i.test(response) &&\n (/\\bcreated?\\b|\\berstellt\\b|\\bgenerat/i.test(response) || /\\|.*\\|.*\\|/m.test(response));\n\n if (hasModuleRef || describesProse) {\n const msg = hasModuleRef\n ? \"Module changes could not be applied — the AI response contained invalid JSON. Try sending your request again.\"\n : \"The AI described modules but did not include the required structured data. Try sending your request again.\";\n log.warn(\"parse\", msg);\n if (onWarning) {\n onWarning(msg);\n }\n }\n }\n}\n","/**\n * AI engine implementations — streaming handlers for each supported engine.\n */\n\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport { spawn } from \"node:child_process\";\nimport { getConversionGuide } from \"../ai/prompts.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { getSession } from \"./session.js\";\nimport { buildVibeSystemPrompt, buildStateContext, buildMessagesWithContext, getPromptContext, type MultimodalMessage } from \"./ai-prompts.js\";\nimport { log } from \"./log.js\";\nimport type { UploadedFileContext } from \"./routes/upload-files.js\";\n\n// ---------------------------------------------------------------------------\n// Lazy-loaded Anthropic SDK\n// ---------------------------------------------------------------------------\n\nlet _AnthropicCtor: typeof import(\"@anthropic-ai/sdk\").default | null = null;\nasync function getAnthropicSDK(): Promise<typeof import(\"@anthropic-ai/sdk\").default> {\n if (!_AnthropicCtor) {\n const mod = await import(\"@anthropic-ai/sdk\");\n _AnthropicCtor = mod.default;\n }\n return _AnthropicCtor;\n}\n\n// ---------------------------------------------------------------------------\n// File context helper (for CLI engines that don't support vision)\n// ---------------------------------------------------------------------------\n\nfunction buildFileContextText(fileContexts?: UploadedFileContext[]): string {\n if (!fileContexts?.length) return \"\";\n const parts: string[] = [];\n for (const fc of fileContexts) {\n if (fc.type === \"image\" && fc.usage === \"asset\" && fc.assetPath) {\n parts.push(`\\n[Uploaded image: ${fc.originalName} → use get_asset_url(\"${fc.assetPath}\")]`);\n }\n if (fc.type === \"document\" && fc.extractedText) {\n parts.push(`\\n\\n---\\n[Attached document: ${fc.originalName}]\\n${fc.extractedText}`);\n }\n }\n return parts.join(\"\");\n}\n\n// ---------------------------------------------------------------------------\n// CLI status messages (shown while waiting for buffered CLI output)\n// ---------------------------------------------------------------------------\n\nexport const CLI_STATUS_MESSAGES = [\n \"Analyzing your request...\",\n \"Reading the conversion guide...\",\n \"Planning module structure...\",\n \"Generating HTML templates...\",\n \"Writing CSS styles...\",\n \"Creating field definitions...\",\n \"Building module metadata...\",\n \"Assembling theme assets...\",\n \"Polishing the output...\",\n \"Almost there — hang tight...\",\n];\n\n// ---------------------------------------------------------------------------\n// Anthropic Streaming API\n// ---------------------------------------------------------------------------\n\nconst RATE_LIMIT_DELAYS = [10, 20, 40, 60, 120]; // seconds\n\nexport async function streamWithAnthropicAPI(\n userMessage: string,\n apiKey: string,\n themeName: string,\n model: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void,\n onFinish?: (fullResponse: string) => void,\n fileContexts?: UploadedFileContext[]\n): Promise<void> {\n const AnthropicSDK = await getAnthropicSDK();\n const client = new AnthropicSDK({ apiKey });\n const conversionGuide = getConversionGuide();\n const session = getSession()!;\n const editMode = session.modules.length > 0;\n const messages = buildMessagesWithContext(userMessage, fileContexts);\n const ctx = getPromptContext();\n const systemPrompt = buildVibeSystemPrompt(conversionGuide, themeName, editMode, ctx.pageType, ctx.brandAssets);\n\n for (let attempt = 0; ; attempt++) {\n try {\n let fullResponse = \"\";\n\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n const heartbeat = setInterval(() => {\n statusIndex++;\n sendStatus(CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)]);\n }, 6000);\n\n try {\n const stream = client.messages.stream({\n model,\n max_tokens: 48000,\n system: systemPrompt,\n messages,\n });\n\n for await (const event of stream) {\n if (\n event.type === \"content_block_delta\" &&\n event.delta.type === \"text_delta\"\n ) {\n const text = event.delta.text;\n fullResponse += text;\n onChunk(text);\n }\n }\n } finally {\n clearInterval(heartbeat);\n }\n\n if (onFinish) onFinish(fullResponse);\n return;\n } catch (err: unknown) {\n const status = (err as { status?: number }).status;\n const errType = (err as { error?: { type?: string } }).error?.type;\n const is429 = status === 429\n || errType === \"rate_limit_error\"\n || (err instanceof Error && err.message.includes(\"429\"));\n\n if (!is429 || attempt >= RATE_LIMIT_DELAYS.length) throw err;\n\n const wait = RATE_LIMIT_DELAYS[attempt];\n log.warn(\"ai-engine\", `Rate limited (429), attempt ${attempt + 1}/${RATE_LIMIT_DELAYS.length} — waiting ${wait}s`);\n if (onStatus) onStatus(`Rate limited by Anthropic API — retrying in ${wait}s...`);\n await new Promise((r) => setTimeout(r, wait * 1000));\n if (onStatus) onStatus(\"Retrying...\");\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI Streaming API (uses native fetch — no npm dependency)\n// ---------------------------------------------------------------------------\n\nexport async function streamWithOpenAIAPI(\n userMessage: string,\n apiKey: string,\n themeName: string,\n model: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void,\n onFinish?: (fullResponse: string) => void,\n fileContexts?: UploadedFileContext[]\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const editMode = getSession()!.modules.length > 0;\n const messages = buildMessagesWithContext(userMessage, fileContexts);\n const ctx = getPromptContext();\n\n // Convert multimodal messages to OpenAI format\n const openaiMessages = messages.map((m) => {\n if (typeof m.content === \"string\") return m;\n // Convert Anthropic-style content blocks to OpenAI format\n return {\n role: m.role,\n content: m.content.map((block) => {\n if (block.type === \"text\") return { type: \"text\" as const, text: block.text };\n return {\n type: \"image_url\" as const,\n image_url: { url: `data:${block.source.media_type};base64,${block.source.data}` },\n };\n }),\n };\n });\n\n const response = await fetch(\"https://api.openai.com/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model,\n max_tokens: 48000,\n stream: true,\n messages: [\n { role: \"system\", content: buildVibeSystemPrompt(conversionGuide, themeName, editMode, ctx.pageType, ctx.brandAssets) },\n ...openaiMessages,\n ],\n }),\n });\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`OpenAI API error (${response.status}): ${err}`);\n }\n\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n const heartbeat = setInterval(() => {\n statusIndex++;\n sendStatus(CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)]);\n }, 6000);\n\n let fullResponse = \"\";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const data = line.slice(6).trim();\n if (data === \"[DONE]\") break;\n\n try {\n const parsed = JSON.parse(data);\n const delta = parsed.choices?.[0]?.delta?.content;\n if (delta) {\n fullResponse += delta;\n onChunk(delta);\n }\n } catch { /* skip malformed SSE lines */ }\n }\n }\n } finally {\n clearInterval(heartbeat);\n }\n\n if (onFinish) onFinish(fullResponse);\n}\n\n// ---------------------------------------------------------------------------\n// Gemini Streaming API (uses native fetch — no npm dependency)\n// ---------------------------------------------------------------------------\n\nexport async function streamWithGeminiAPI(\n userMessage: string,\n apiKey: string,\n themeName: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void,\n onFinish?: (fullResponse: string) => void,\n fileContexts?: UploadedFileContext[]\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const session = getSession()!;\n const editMode = session.modules.length > 0;\n const stateContext = buildStateContext();\n const ctx = getPromptContext();\n\n const contents: Array<{ role: string; parts: Array<{ text?: string; inlineData?: { mimeType: string; data: string } }> }> = [];\n\n for (const m of session.messages.slice(-20)) {\n contents.push({\n role: m.role === \"assistant\" ? \"model\" : \"user\",\n parts: [{ text: m.content }],\n });\n }\n\n let userContent = stateContext\n ? `${userMessage}\\n\\n---\\n${stateContext}`\n : userMessage;\n\n // Add document text from file contexts\n if (fileContexts?.length) {\n for (const fc of fileContexts) {\n if (fc.type === \"document\" && fc.extractedText) {\n userContent += `\\n\\n---\\n[Attached document: ${fc.originalName}]\\n${fc.extractedText}`;\n }\n if (fc.type === \"image\" && fc.usage === \"asset\" && fc.assetPath) {\n userContent += `\\n\\n[Uploaded image: ${fc.originalName} → available as get_asset_url(\"${fc.assetPath}\")]`;\n }\n }\n }\n\n const userParts: Array<{ text?: string; inlineData?: { mimeType: string; data: string } }> = [];\n\n // Add image parts for Gemini vision\n if (fileContexts?.length) {\n for (const fc of fileContexts) {\n if (fc.type === \"image\" && fc.base64) {\n userParts.push({ inlineData: { mimeType: fc.mimeType, data: fc.base64 } });\n }\n }\n }\n\n userParts.push({ text: userContent });\n contents.push({ role: \"user\", parts: userParts });\n\n const model = \"gemini-2.5-flash\";\n const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${apiKey}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n systemInstruction: { parts: [{ text: buildVibeSystemPrompt(conversionGuide, themeName, editMode, ctx.pageType, ctx.brandAssets) }] },\n contents,\n generationConfig: { maxOutputTokens: 48000 },\n }),\n });\n\n if (!response.ok) {\n const err = await response.text();\n throw new Error(`Gemini API error (${response.status}): ${err}`);\n }\n\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n const heartbeat = setInterval(() => {\n statusIndex++;\n sendStatus(CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)]);\n }, 6000);\n\n let fullResponse = \"\";\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue;\n const data = line.slice(6).trim();\n\n try {\n const parsed = JSON.parse(data);\n const text = parsed.candidates?.[0]?.content?.parts?.[0]?.text;\n if (text) {\n fullResponse += text;\n onChunk(text);\n }\n } catch { /* skip malformed SSE lines */ }\n }\n }\n } finally {\n clearInterval(heartbeat);\n }\n\n if (onFinish) onFinish(fullResponse);\n}\n\n// ---------------------------------------------------------------------------\n// CLI subprocess helper — sends prompt via stdin to avoid shell arg limits\n// ---------------------------------------------------------------------------\n\nfunction spawnCLI(\n bin: string,\n args: string[],\n prompt: string,\n onChunk?: (chunk: string) => void\n): Promise<string> {\n return new Promise((resolve, reject) => {\n const env = { ...process.env };\n delete env.CLAUDECODE;\n\n const child = spawn(bin, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env,\n shell: true,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout.on(\"data\", (d: Buffer) => {\n const chunk = d.toString();\n stdout += chunk;\n if (onChunk) onChunk(chunk);\n });\n child.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n\n child.on(\"error\", (err) =>\n reject(new Error(`${bin} failed to start: ${err.message}`))\n );\n\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(\n `${bin} exited with code ${code}.\\n` +\n (stderr ? `Stderr: ${stderr.slice(0, 500)}\\n` : \"\") +\n (stdout ? `Output: ${stdout.slice(0, 500)}` : \"No output\")\n ));\n } else {\n resolve(stdout);\n }\n });\n\n child.stdin.on(\"error\", () => {});\n child.stdin.write(prompt);\n child.stdin.end();\n\n setTimeout(() => {\n child.kill();\n reject(new Error(`${bin} timed out after 10 minutes`));\n }, 600_000);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Claude Code subprocess\n// ---------------------------------------------------------------------------\n\nexport async function generateWithClaudeCode(\n userMessage: string,\n themeName: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void,\n onFinish?: (fullResponse: string) => void,\n fileContexts?: UploadedFileContext[]\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const config = loadConfig();\n const editMode = getSession()!.modules.length > 0;\n const ctx = getPromptContext();\n\n let prompt = buildVibeSystemPrompt(conversionGuide, themeName, editMode, ctx.pageType, ctx.brandAssets);\n prompt += \"\\n\\n## User Request\\n\" + userMessage;\n prompt += buildStateContext();\n prompt += buildFileContextText(fileContexts);\n\n const args = [\"--print\"];\n if (config.claudeCodeModel) args.push(\"--model\", config.claudeCodeModel);\n\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n\n const heartbeat = setInterval(() => {\n statusIndex++;\n const msg = CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)];\n sendStatus(msg);\n }, 6000);\n\n try {\n const result = await spawnCLI(\"claude\", args, prompt, (chunk) => {\n onChunk(chunk);\n });\n if (onFinish) onFinish(result);\n } finally {\n clearInterval(heartbeat);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Generic CLI subprocess (Gemini CLI, Codex CLI)\n// ---------------------------------------------------------------------------\n\nexport async function generateWithCLI(\n cli: \"gemini\" | \"codex\",\n userMessage: string,\n themeName: string,\n onChunk: (chunk: string) => void,\n onStatus?: (status: string) => void,\n onFinish?: (fullResponse: string) => void,\n fileContexts?: UploadedFileContext[]\n): Promise<void> {\n const conversionGuide = getConversionGuide();\n const editMode = getSession()!.modules.length > 0;\n const ctx = getPromptContext();\n\n let prompt = buildVibeSystemPrompt(conversionGuide, themeName, editMode, ctx.pageType, ctx.brandAssets);\n prompt += \"\\n\\n## User Request\\n\" + userMessage;\n prompt += buildStateContext();\n prompt += buildFileContextText(fileContexts);\n\n let bin: string;\n let args: string[];\n if (cli === \"gemini\") {\n bin = \"gemini\";\n args = [];\n } else {\n bin = \"codex\";\n args = [\"exec\", \"--full-auto\"];\n }\n\n let statusIndex = 0;\n const sendStatus = onStatus || (() => {});\n sendStatus(CLI_STATUS_MESSAGES[0]);\n\n const heartbeat = setInterval(() => {\n statusIndex++;\n const msg = CLI_STATUS_MESSAGES[Math.min(statusIndex, CLI_STATUS_MESSAGES.length - 1)];\n sendStatus(msg);\n }, 6000);\n\n try {\n const result = await spawnCLI(bin, args, prompt, (chunk) => {\n onChunk(chunk);\n });\n if (onFinish) onFinish(result);\n } finally {\n clearInterval(heartbeat);\n }\n}\n","/**\n * AI prompt construction — system prompts, state context, message building.\n */\n\nimport { getConversionGuide, getDesignGuide, getContentGuide, getHubspotRules, getPageTypeGuide, getHumanifyGuide } from \"../ai/prompts.js\";\nimport {\n getSession,\n getActiveTemplate,\n getModuleLibrary,\n} from \"./session.js\";\nimport type { UploadedFileContext } from \"./routes/upload-files.js\";\n\n// Multimodal content block types (compatible with Anthropic/OpenAI APIs)\nexport type ContentBlock =\n | { type: \"text\"; text: string }\n | { type: \"image\"; source: { type: \"base64\"; media_type: string; data: string } };\n\nexport type MultimodalMessage = {\n role: \"user\" | \"assistant\";\n content: string | ContentBlock[];\n};\n\n/**\n * Get the active template's page type and brand assets from the session.\n */\nexport function getPromptContext(): { pageType?: string; brandAssets?: { styleguide?: string; brandvoice?: string; humanify?: boolean } } {\n const session = getSession();\n if (!session) return {};\n const tpl = getActiveTemplate();\n return {\n pageType: tpl?.pageType,\n brandAssets: session.brandAssets,\n };\n}\n\n/**\n * Build the system prompt for vibe coding mode.\n */\nexport function buildVibeSystemPrompt(\n conversionGuide: string,\n themeName: string,\n editMode: boolean = false,\n pageType?: string,\n brandAssets?: { styleguide?: string; brandvoice?: string; humanify?: boolean }\n): string {\n const core = `You are vibeSpot, an AI that builds HubSpot CMS landing pages from natural language descriptions.\n\n## Your Role\nYou generate native HubSpot CMS modules directly from user descriptions. Every module you create is immediately compatible with HubSpot's drag-and-drop page editor.\n\n## Output Format — CRITICAL\nYou MUST include a \\`\\`\\`vibespot-modules code block with ALL module data as JSON. This is the ONLY way modules get created. A text summary, table, or description of modules does NOT work — you must output the actual JSON.\n\n\\`\\`\\`vibespot-modules\n{\n \"modules\": [\n {\n \"moduleName\": \"Hero\",\n \"fieldsJson\": \"...\",\n \"metaJson\": \"...\",\n \"moduleHtml\": \"...\",\n \"moduleCss\": \"...\",\n \"moduleJs\": null\n }\n ],\n \"sharedCss\": \"...\",\n \"sharedJs\": \"...\"\n}\n\\`\\`\\`\n\nNEVER respond with only a text summary. The vibespot-modules JSON block is mandatory.\n\n## Rules\n- fieldsJson, metaJson must be valid JSON strings\n- moduleHtml uses HubL template syntax ({{ module.field_name }})\n- moduleCss is vanilla CSS (no Tailwind, no Sass)\n- moduleJs is optional vanilla JS (wrapped in IIFE)\n- NEVER use CDN imports (@import url(), <link> to external CDNs like Google Fonts, cdnjs, unpkg, jsdelivr)\n- For fonts, use system font stacks with good fallbacks. Define them as CSS custom properties in sharedCss:\n --font-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --font-mono: 'SF Mono', SFMono-Regular, Consolas, monospace;\n- All assets must be self-contained — no external HTTP requests in CSS or HTML\n- Use \"type\": \"text\" (NEVER \"textarea\" — it's deprecated)\n- NEVER use \"name\": \"name\" (reserved) — use \"item_name\" instead\n- Wrap style fields in a \"styles\" group with \"tab\": \"STYLE\"\n- All CSS classes must use a unique prefix \"${themeName}-\" to avoid theme conflicts\n- Use BEM naming: ${themeName}-module__element--modifier\n- metaJson must include: host_template_types: [\"PAGE\"], is_available_for_new_content: true\n- For repeater groups, use \"occurrence\": { \"min\": 0, \"max\": 100 } and iterate with {% for %}\n- Color fields: type \"color\", default { \"color\": \"#hex\", \"opacity\": 100 }\n- Link fields: type \"link\", default { \"url\": { \"href\": \"#\", \"type\": \"EXTERNAL\" }, \"open_in_new_tab\": false, \"no_follow\": false }\n- Image fields: type \"image\", default { \"src\": \"https://placehold.co/800x600/1a1a2e/ffffff?text=Replace+in+HubSpot\", \"alt\": \"Placeholder image\", \"width\": 800, \"height\": 600 }\n\n## Images & Media\n- Users can upload images that get placed in the theme's assets/ folder automatically\n- When the user uploads an image and wants it on the page, reference it with: {{ get_asset_url(\"${themeName}/assets/filename.ext\") }}\n- IMPORTANT: get_asset_url() paths must include the theme name prefix \"${themeName}/\" because HubSpot resolves from the Design Manager root\n- For background images with uploaded assets: style=\"background-image: url('{{ get_asset_url(\\\\\"${themeName}/assets/filename.ext\\\\\") }}')\"\n- For images without an uploaded asset, use image fields (type \"image\") with placehold.co defaults\n- ALWAYS use image fields (type \"image\") so users can swap images in the page editor\n- Use placehold.co URLs as defaults so the preview looks complete (e.g. https://placehold.co/800x600/1a1a2e/ffffff?text=Hero+Image)\n- In module.html, render images with: <img src=\"{{ module.field_name.src }}\" alt=\"{{ module.field_name.alt }}\" width=\"{{ module.field_name.width }}\" height=\"{{ module.field_name.height }}\">\n- For background images in CSS, use inline styles: style=\"background-image: url('{{ module.field_name.src }}')\"\n- Size placeholders appropriately for their context (hero: 1920x800, cards: 600x400, icons: 200x200, avatars: 150x150)\n- If the user's intent is ambiguous (design reference vs page asset), ask them to clarify\n\n## Navigation & Anchor Links\n- Each module is automatically wrapped with an id derived from its moduleName (lowercase, hyphens for spaces)\n- For navigation/menu modules, use anchor links that match module names: e.g. if a module is named \"Features\", link to href=\"#features\"\n- The id is the moduleName lowercased with non-alphanumeric chars replaced by hyphens (e.g. \"Pricing Cards\" → id=\"pricing-cards\")\n- Always include smooth scrolling behavior in navigation link clicks\n- For nav modules, make menu items editable via a repeater group with \"label\" (text) and \"anchor\" (text) fields\n\n## When modifying existing modules\nWhen the user asks to change something, include ONLY the modules that changed. Keep module names consistent.\nIf the change affects shared CSS or JS, include those too.`;\n\n const pageTypeSection = pageType ? getPageTypeGuide(pageType) : \"\";\n const pageTypePrompt = pageTypeSection ? `\\n\\n## Page Type Context\\n${pageTypeSection}` : \"\";\n\n let brandPrompt = \"\";\n if (!editMode) {\n if (brandAssets?.styleguide) {\n brandPrompt += `\\n\\n## Brand Style Guide\\n${brandAssets.styleguide}`;\n }\n if (brandAssets?.brandvoice) {\n brandPrompt += `\\n\\n## Brand Voice\\n${brandAssets.brandvoice}`;\n }\n if (brandAssets?.humanify !== false) {\n const humanifyGuide = getHumanifyGuide();\n if (humanifyGuide) {\n brandPrompt += `\\n\\n## Anti-AI Copy Rules (Humanify)\\n${humanifyGuide}`;\n }\n }\n }\n\n if (editMode) {\n return core + pageTypePrompt + `\n\n## HubSpot CMS Rules\n${getHubspotRules()}`;\n }\n\n return core + pageTypePrompt + brandPrompt + `\n\n## Design Quality\n- Use modern, clean design with proper spacing and typography\n- Include responsive CSS (mobile breakpoint at 767px)\n- Add scroll animation classes where appropriate\n- Use CSS custom properties for the design system\n- Make content editable through fields.json (headlines, text, colors, images, links)\n\n## Scroll Animation CSS Fallback (IMPORTANT)\nWhen using scroll-animate classes (opacity: 0 → visible), you MUST include a CSS-only fallback animation in sharedCss that auto-reveals elements after a delay. This ensures content is visible even if the JS file fails to load:\n\\`\\`\\`css\n@keyframes scroll-animate-fallback {\n to { opacity: 1; transform: none; }\n}\n.scroll-animate {\n animation: scroll-animate-fallback 0.1s 3s forwards;\n}\n.scroll-animate.visible {\n animation: none;\n}\n\\`\\`\\`\nThis makes elements appear after 3 seconds if JS never adds the .visible class. Once JS runs normally and adds .visible, the animation is cancelled.\n\n## Design Guide\n${getDesignGuide()}\n\n## Content & Copywriting Guide\n${getContentGuide()}\n\n## HubSpot CMS Rules\n${getHubspotRules()}\n\n## Conversion Guide Reference\n${conversionGuide}`;\n}\n\n/**\n * Build a summary of the current module state for inclusion in user messages.\n */\nexport function buildStateContext(): string {\n const session = getSession()!;\n const parts: string[] = [];\n if (session.modules.length > 0) {\n parts.push(\"\\n\\n## Current Module State\\n\");\n for (const mod of session.modules) {\n parts.push(`\\n### ${mod.moduleName}.module\\n`);\n parts.push(`**fields.json:**\\n\\`\\`\\`json\\n${mod.fieldsJson}\\n\\`\\`\\`\\n`);\n parts.push(`**module.html:**\\n\\`\\`\\`html\\n${mod.moduleHtml}\\n\\`\\`\\`\\n`);\n parts.push(`**module.css:**\\n\\`\\`\\`css\\n${mod.moduleCss}\\n\\`\\`\\`\\n`);\n if (mod.moduleJs) {\n parts.push(`**module.js:**\\n\\`\\`\\`js\\n${mod.moduleJs}\\n\\`\\`\\`\\n`);\n }\n }\n if (session.sharedCss) {\n parts.push(`\\n### Shared CSS\\n\\`\\`\\`css\\n${session.sharedCss}\\n\\`\\`\\`\\n`);\n }\n if (session.sharedJs) {\n parts.push(`\\n### Shared JS\\n\\`\\`\\`js\\n${session.sharedJs}\\n\\`\\`\\`\\n`);\n }\n }\n\n const library = getModuleLibrary();\n const currentModuleNames = new Set(session.modules.map((m) => m.moduleName));\n const otherModules = library.filter((e) => !currentModuleNames.has(e.module.moduleName));\n if (otherModules.length > 0) {\n parts.push(\"\\n\\n## Available modules in this theme (reusable)\\n\");\n for (const entry of otherModules) {\n parts.push(`- ${entry.module.moduleName} (used in: ${entry.usedIn.join(\", \")})\\n`);\n }\n parts.push(\"\\nThe user can ask to reuse any of these modules by name.\\n\");\n }\n\n return parts.join(\"\");\n}\n\n/**\n * Build the messages array with state context appended to the latest user message.\n * When fileContexts are provided, the last message uses multimodal content blocks.\n */\nexport function buildMessagesWithContext(\n userMessage: string,\n fileContexts?: UploadedFileContext[]\n): MultimodalMessage[] {\n const session = getSession()!;\n const messages: MultimodalMessage[] =\n session.messages.slice(-20).map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const stateContext = buildStateContext();\n\n // Build asset manifest if there are any uploaded assets in the session\n let assetManifest = \"\";\n if (session.assets?.length) {\n const imageAssets = session.assets.filter((a) => a.type === \"image\" && a.usage === \"asset\");\n if (imageAssets.length > 0) {\n assetManifest = `\\n\\n## Available Theme Assets\\nThese images are in the theme's assets/ folder. Reference them with get_asset_url(\"${session.themeName}/assets/filename\"):\\n${imageAssets.map((a) => `- ${a.filename} (${a.originalName}) → get_asset_url(\"${session.themeName}/assets/${a.filename}\")`).join(\"\\n\")}`;\n }\n }\n\n let textContent = userMessage;\n if (stateContext) textContent += `\\n\\n---\\n${stateContext}`;\n if (assetManifest) textContent += assetManifest;\n\n // Add document text from attachments\n const hasFiles = fileContexts && fileContexts.length > 0;\n if (hasFiles) {\n for (const fc of fileContexts) {\n if (fc.type === \"document\" && fc.extractedText) {\n textContent += `\\n\\n---\\n[Attached document: ${fc.originalName}]\\n${fc.extractedText}`;\n }\n if (fc.type === \"image\" && fc.usage === \"asset\" && fc.assetPath) {\n textContent += `\\n\\n[Uploaded image: ${fc.originalName} → available as get_asset_url(\"${fc.assetPath}\")]`;\n }\n }\n }\n\n // Build multimodal content if there are image attachments\n const imageFiles = hasFiles ? fileContexts.filter((fc) => fc.type === \"image\" && fc.base64) : [];\n\n if (imageFiles.length > 0) {\n const contentBlocks: ContentBlock[] = [];\n // Add image blocks first so the AI \"sees\" them\n for (const img of imageFiles) {\n contentBlocks.push({\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: img.mimeType,\n data: img.base64!,\n },\n });\n }\n // Add the text content\n contentBlocks.push({ type: \"text\", text: textContent });\n messages.push({ role: \"user\", content: contentBlocks });\n } else {\n messages.push({ role: \"user\", content: textContent });\n }\n\n return messages;\n}\n","/**\n * File upload route — handles images (page assets) and documents (AI context).\n *\n * Images are copied to theme/assets/ and sent to AI as vision input.\n * Documents (PDF, DOCX, MD, TXT) are text-extracted for AI context only.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { createWriteStream, mkdirSync, existsSync, readFileSync, copyFileSync } from \"node:fs\";\nimport { join, extname } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { tmpdir } from \"node:os\";\nimport Busboy from \"busboy\";\nimport { jsonResponse } from \"../route-helpers.js\";\nimport { getSession, addSessionAsset, type SessionAsset } from \"../session.js\";\nimport { log } from \"../log.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB\n\nconst IMAGE_MIMES = new Set([\n \"image/png\", \"image/jpeg\", \"image/jpg\", \"image/svg+xml\",\n \"image/webp\", \"image/gif\",\n]);\n\nconst DOCUMENT_MIMES = new Set([\n \"application/pdf\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"text/markdown\", \"text/plain\",\n]);\n\nconst SUPPORTED_MIMES = new Set([...IMAGE_MIMES, ...DOCUMENT_MIMES]);\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Sanitize a filename for safe filesystem use. */\nfunction sanitizeFilename(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9._-]/g, \"_\")\n .replace(/_{2,}/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .toLowerCase();\n}\n\n/** Deduplicate filename if it already exists in the target directory. */\nfunction deduplicateFilename(dir: string, name: string): string {\n if (!existsSync(join(dir, name))) return name;\n const ext = extname(name);\n const base = name.slice(0, -ext.length || undefined);\n let counter = 1;\n while (existsSync(join(dir, `${base}-${counter}${ext}`))) counter++;\n return `${base}-${counter}${ext}`;\n}\n\n/** Extract text from a PDF file using pdf-parse. */\nasync function extractPdfText(filePath: string): Promise<string> {\n const pdfParse = (await import(\"pdf-parse\")).default;\n const buffer = readFileSync(filePath);\n const data = await pdfParse(buffer);\n return data.text;\n}\n\n/** Extract text from a DOCX file using mammoth. */\nasync function extractDocxText(filePath: string): Promise<string> {\n const mammoth = await import(\"mammoth\");\n const result = await mammoth.extractRawText({ path: filePath });\n return result.value;\n}\n\n/** Read plain text or markdown file. */\nfunction extractPlainText(filePath: string): string {\n return readFileSync(filePath, \"utf-8\");\n}\n\n// ---------------------------------------------------------------------------\n// Route handler\n// ---------------------------------------------------------------------------\n\nexport function handleFileUploadRoute(req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 400, { error: \"No active session\" });\n return;\n }\n\n const contentType = req.headers[\"content-type\"] || \"\";\n if (!contentType.includes(\"multipart/form-data\")) {\n jsonResponse(res, 400, { error: \"Expected multipart/form-data\" });\n return;\n }\n\n const results: SessionAsset[] = [];\n const errors: string[] = [];\n let fileCount = 0;\n const writePromises: Promise<void>[] = [];\n\n const bb = Busboy({ headers: req.headers, limits: { fileSize: MAX_FILE_SIZE, files: 10 } });\n\n bb.on(\"file\", (fieldname, fileStream, info) => {\n const { filename: originalName, mimeType } = info;\n fileCount++;\n\n if (!SUPPORTED_MIMES.has(mimeType)) {\n errors.push(`Unsupported file type: ${originalName} (${mimeType})`);\n fileStream.resume(); // drain the stream\n return;\n }\n\n const isImage = IMAGE_MIMES.has(mimeType);\n const sanitized = sanitizeFilename(originalName);\n const id = randomUUID();\n\n // Determine storage path\n let targetDir: string;\n let finalFilename: string;\n\n if (isImage) {\n // Images go to theme/assets/\n targetDir = join(session.themePath, \"assets\");\n mkdirSync(targetDir, { recursive: true });\n finalFilename = deduplicateFilename(targetDir, sanitized);\n } else {\n // Documents go to .vibespot/uploads/ (context only)\n targetDir = join(session.themePath, \".vibespot\", \"uploads\");\n mkdirSync(targetDir, { recursive: true });\n finalFilename = `${id}-${sanitized}`;\n }\n\n const targetPath = join(targetDir, finalFilename);\n const writeStream = createWriteStream(targetPath);\n let fileSize = 0;\n let truncated = false;\n\n fileStream.on(\"data\", (chunk: Buffer) => {\n fileSize += chunk.length;\n });\n\n fileStream.on(\"limit\", () => {\n truncated = true;\n errors.push(`File too large (>10MB): ${originalName}`);\n });\n\n fileStream.pipe(writeStream);\n\n // Track each file write as a promise so we can await them all\n writePromises.push(new Promise<void>((resolve) => {\n writeStream.on(\"finish\", () => {\n if (!truncated) {\n const asset: SessionAsset = {\n id,\n filename: finalFilename,\n originalName,\n type: isImage ? \"image\" : \"document\",\n usage: isImage ? \"asset\" : \"context\",\n mimeType,\n size: fileSize,\n addedAt: new Date().toISOString(),\n };\n results.push(asset);\n addSessionAsset(asset);\n }\n resolve();\n });\n writeStream.on(\"error\", () => {\n errors.push(`Failed to write: ${originalName}`);\n resolve();\n });\n }));\n });\n\n bb.on(\"finish\", async () => {\n // Wait for all file writes to complete before responding\n await Promise.all(writePromises);\n\n // Extract text from documents\n for (const asset of results) {\n if (asset.type === \"document\") {\n const filePath = join(session.themePath, \".vibespot\", \"uploads\", asset.filename);\n try {\n if (asset.mimeType === \"application/pdf\") {\n asset.extractedText = await extractPdfText(filePath);\n } else if (asset.mimeType === \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\") {\n asset.extractedText = await extractDocxText(filePath);\n } else {\n asset.extractedText = extractPlainText(filePath);\n }\n log.info(\"upload\", `Extracted text from ${asset.originalName} (${asset.extractedText.length} chars)`);\n } catch (err) {\n log.warn(\"upload\", `Failed to extract text from ${asset.originalName}: ${err}`);\n asset.extractedText = `[Could not extract text from ${asset.originalName}]`;\n }\n }\n }\n\n if (fileCount === 0) {\n jsonResponse(res, 400, { error: \"No files uploaded\" });\n return;\n }\n\n jsonResponse(res, 200, {\n files: results.map((a) => ({\n id: a.id,\n filename: a.filename,\n originalName: a.originalName,\n type: a.type,\n usage: a.usage,\n size: a.size,\n })),\n errors: errors.length > 0 ? errors : undefined,\n });\n });\n\n bb.on(\"error\", (err) => {\n log.error(\"upload\", `Busboy error: ${err}`);\n jsonResponse(res, 500, { error: \"Upload failed\" });\n });\n\n req.pipe(bb);\n}\n\n// ---------------------------------------------------------------------------\n// Get uploaded asset data (for AI context)\n// ---------------------------------------------------------------------------\n\nexport interface UploadedFileContext {\n id: string;\n filename: string;\n originalName: string;\n type: \"image\" | \"document\";\n usage: \"asset\" | \"context\";\n /** Base64-encoded image data (for vision API) */\n base64?: string;\n mimeType: string;\n /** Extracted text content (for documents) */\n extractedText?: string;\n /** Asset path for get_asset_url() references */\n assetPath?: string;\n}\n\n/** Load full context for uploaded files by their IDs. */\nexport function getFileContexts(fileIds: string[]): UploadedFileContext[] {\n const session = getSession();\n if (!session?.assets) return [];\n\n return fileIds\n .map((id) => {\n const asset = session.assets!.find((a) => a.id === id);\n if (!asset) return null;\n\n const ctx: UploadedFileContext = {\n id: asset.id,\n filename: asset.filename,\n originalName: asset.originalName,\n type: asset.type,\n usage: asset.usage,\n mimeType: asset.mimeType,\n };\n\n if (asset.type === \"image\") {\n // Load base64 for vision API\n const imgPath = join(session.themePath, \"assets\", asset.filename);\n if (existsSync(imgPath)) {\n ctx.base64 = readFileSync(imgPath).toString(\"base64\");\n }\n ctx.assetPath = `${session.themeName}/assets/${asset.filename}`;\n } else if (asset.type === \"document\") {\n // Load extracted text\n ctx.extractedText = asset.extractedText;\n }\n\n return ctx;\n })\n .filter((c): c is UploadedFileContext => c !== null);\n}\n\n/** Get the asset manifest (list of all image assets) for the AI system prompt. */\nexport function getAssetManifest(): string[] {\n const session = getSession();\n if (!session?.assets) return [];\n return session.assets\n .filter((a) => a.type === \"image\" && a.usage === \"asset\")\n .map((a) => a.filename);\n}\n","/**\n * Shared helpers for route handlers.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport function jsonResponse(res: ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n}\n\nexport function readBody(req: IncomingMessage, callback: (body: string) => void): void {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk) => chunks.push(chunk));\n req.on(\"end\", () => callback(Buffer.concat(chunks).toString(\"utf-8\")));\n}\n","/**\n * Background process manager for long-running CLI operations\n * (tool installation, OAuth flows, etc.)\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\n\nexport interface ProcessJob {\n id: string;\n command: string;\n description: string;\n status: \"running\" | \"completed\" | \"failed\";\n output: string;\n exitCode: number | null;\n startedAt: number;\n completedAt: number | null;\n}\n\nconst jobs = new Map<string, ProcessJob>();\n\nexport function startJob(\n command: string,\n description: string,\n opts?: { cwd?: string; env?: Record<string, string>; timeout?: number }\n): string {\n const id = `job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n\n const job: ProcessJob = {\n id,\n command,\n description,\n status: \"running\",\n output: \"\",\n exitCode: null,\n startedAt: Date.now(),\n completedAt: null,\n };\n\n jobs.set(id, job);\n\n const parts = command.split(\" \");\n const child: ChildProcess = spawn(parts[0], parts.slice(1), {\n cwd: opts?.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, ...opts?.env },\n shell: true,\n });\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n job.output += d.toString();\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n job.output += d.toString();\n });\n\n child.on(\"close\", (code) => {\n job.status = code === 0 ? \"completed\" : \"failed\";\n job.exitCode = code;\n job.completedAt = Date.now();\n });\n\n child.on(\"error\", (err) => {\n job.status = \"failed\";\n job.output += `\\nProcess error: ${err.message}`;\n job.completedAt = Date.now();\n });\n\n // Timeout safety net\n const timeout = opts?.timeout || 300_000;\n setTimeout(() => {\n if (job.status === \"running\") {\n child.kill();\n job.status = \"failed\";\n job.output += \"\\nProcess timed out\";\n job.completedAt = Date.now();\n }\n }, timeout);\n\n return id;\n}\n\nexport function getJob(id: string): ProcessJob | undefined {\n return jobs.get(id);\n}\n\nexport function cleanupOldJobs(): void {\n const cutoff = Date.now() - 30 * 60 * 1000;\n for (const [id, job] of jobs) {\n if (job.completedAt && job.completedAt < cutoff) {\n jobs.delete(id);\n }\n }\n}\n\n// Clean up periodically\nsetInterval(cleanupOldJobs, 10 * 60 * 1000);\n\n// ---------------------------------------------------------------------------\n// Streaming jobs — same as regular jobs but also emit output chunks to listeners\n// ---------------------------------------------------------------------------\n\nexport interface StreamingJob extends ProcessJob {\n listeners: Set<(chunk: string) => void>;\n}\n\nexport function startStreamingJob(\n command: string,\n description: string,\n opts?: { cwd?: string; env?: Record<string, string>; timeout?: number }\n): string {\n const id = `job-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n\n const job: StreamingJob = {\n id,\n command,\n description,\n status: \"running\",\n output: \"\",\n exitCode: null,\n startedAt: Date.now(),\n completedAt: null,\n listeners: new Set(),\n };\n\n jobs.set(id, job);\n\n const parts = command.split(\" \");\n const child: ChildProcess = spawn(parts[0], parts.slice(1), {\n cwd: opts?.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env, ...opts?.env },\n shell: true,\n });\n\n const emitChunk = (chunk: string) => {\n for (const listener of job.listeners) {\n try { listener(chunk); } catch { /* listener error — ignore */ }\n }\n };\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n const chunk = d.toString();\n job.output += chunk;\n emitChunk(chunk);\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n const chunk = d.toString();\n job.output += chunk;\n emitChunk(chunk);\n });\n\n child.on(\"close\", (code) => {\n job.status = code === 0 ? \"completed\" : \"failed\";\n job.exitCode = code;\n job.completedAt = Date.now();\n });\n\n child.on(\"error\", (err) => {\n job.status = \"failed\";\n job.output += `\\nProcess error: ${err.message}`;\n job.completedAt = Date.now();\n });\n\n // Timeout safety net\n const timeout = opts?.timeout || 300_000;\n setTimeout(() => {\n if (job.status === \"running\") {\n child.kill();\n job.status = \"failed\";\n job.output += \"\\nProcess timed out\";\n job.completedAt = Date.now();\n }\n }, timeout);\n\n return id;\n}\n\nexport function addJobListener(jobId: string, listener: (chunk: string) => void): void {\n const job = jobs.get(jobId);\n if (!job || !(\"listeners\" in job)) return;\n\n const streamingJob = job as StreamingJob;\n\n // Send buffered output first\n if (streamingJob.output) {\n try { listener(streamingJob.output); } catch { /* ignore */ }\n }\n\n streamingJob.listeners.add(listener);\n}\n\nexport function removeJobListener(jobId: string, listener: (chunk: string) => void): void {\n const job = jobs.get(jobId);\n if (!job || !(\"listeners\" in job)) return;\n\n (job as StreamingJob).listeners.delete(listener);\n}\n","/**\n * Setup routes — onboarding flow in the browser.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { existsSync, readdirSync, rmSync } from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { execSync } from \"node:child_process\";\nimport { jsonResponse, readBody } from \"../route-helpers.js\";\nimport { loadConfig, getHubSpotPak } from \"../../utils/config.js\";\nimport { createThemeScaffold } from \"../../hubspot/theme-scaffold.js\";\nimport { fetchTheme } from \"../../hubspot/fetcher.js\";\nimport { getMetadata, listRootFolders } from \"../../hubspot/api.js\";\nimport {\n getSession,\n createSession,\n scanThemeFromDisk,\n saveSession,\n loadSession,\n listSessions,\n} from \"../session.js\";\nimport { isGenerating } from \"../ai-handler.js\";\nimport { detectEnvironment } from \"../../utils/detect.js\";\nimport { saveConfig } from \"../../utils/config.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\n\nexport const WORKSPACE_DIR = join(homedir(), \"vibespot-themes\");\n\nlet _themeListCache: { data: Array<{ name: string; moduleCount: number }>; ts: number } | null = null;\nconst THEME_LIST_TTL = 5000;\n\nexport function getLocalThemes(): Array<{ name: string; moduleCount: number }> {\n if (_themeListCache && Date.now() - _themeListCache.ts < THEME_LIST_TTL) return _themeListCache.data;\n const themes: Array<{ name: string; moduleCount: number }> = [];\n if (existsSync(WORKSPACE_DIR)) {\n try {\n for (const entry of readdirSync(WORKSPACE_DIR, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n const themeJson = join(WORKSPACE_DIR, entry.name, \"theme.json\");\n if (existsSync(themeJson)) {\n let moduleCount = 0;\n const modulesDir = join(WORKSPACE_DIR, entry.name, \"modules\");\n if (existsSync(modulesDir)) {\n try {\n moduleCount = readdirSync(modulesDir, { withFileTypes: true })\n .filter((e) => e.isDirectory()).length;\n } catch { /* ignore */ }\n }\n themes.push({ name: entry.name, moduleCount });\n }\n }\n }\n } catch { /* ignore */ }\n }\n _themeListCache = { data: themes, ts: Date.now() };\n return themes;\n}\n\nexport function handleSetupInfoRoute(res: ServerResponse): void {\n const session = getSession();\n const env = detectEnvironment();\n\n let hsInstalled = false;\n try {\n execSync(\"hs --version\", { encoding: \"utf-8\", stdio: \"pipe\" });\n hsInstalled = true;\n } catch { /* not installed */ }\n\n const sessions = listSessions()\n .sort((a, b) => b.updatedAt - a.updatedAt)\n .slice(0, 10);\n\n const localThemes = getLocalThemes();\n\n jsonResponse(res, 200, {\n hasActiveSession: !!session,\n activeSession: session ? {\n id: session.id,\n themeName: session.themeName,\n moduleCount: session.modules.length,\n } : null,\n hsInstalled,\n aiAvailable: env.availableEngines.length > 0,\n availableEngines: env.availableEngines,\n activeEngine: env.activeEngine,\n sessions,\n localThemes,\n });\n}\n\nexport function handleSetupCreateRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { name } = JSON.parse(body);\n if (!name || typeof name !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n\n const themeName = name\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\n const themePath = join(WORKSPACE_DIR, themeName);\n ensureDir(WORKSPACE_DIR);\n\n if (existsSync(themePath)) {\n rmSync(themePath, { recursive: true, force: true });\n }\n\n // Create theme scaffold locally (no CLI dependency)\n createThemeScaffold(themePath, themeName);\n\n createSession(themePath, themeName);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName,\n themePath,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSetupFetchRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { name: rawName } = JSON.parse(body);\n if (!rawName || typeof rawName !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n\n // Strip leading/trailing slashes (HubSpot DM \"Copy path\" gives \"/theme-name\")\n const name = rawName.replace(/^\\/+|\\/+$/g, \"\");\n if (!name) {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n\n const pak = getHubSpotPak();\n const config = loadConfig();\n\n const themePath = join(WORKSPACE_DIR, name);\n ensureDir(WORKSPACE_DIR);\n\n if (config.hubspotUploadMode === \"cli\" || !pak) {\n // CLI fallback\n execSync(`hs cms fetch \"${name}\" \"${themePath}\"`, {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n });\n\n createSession(themePath, name);\n scanThemeFromDisk(themePath);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: name,\n themePath,\n moduleCount: getSession()?.modules.length || 0,\n });\n } else {\n // API mode (default)\n fetchTheme(pak, name, themePath)\n .then(() => {\n createSession(themePath, name);\n scanThemeFromDisk(themePath);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: name,\n themePath,\n moduleCount: getSession()?.modules.length || 0,\n });\n })\n .catch((err) => {\n jsonResponse(res, 500, {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n } catch (err) {\n jsonResponse(res, 500, {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n\nexport function handleSetupOpenRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { path: themePath } = JSON.parse(body);\n if (!themePath || typeof themePath !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme path is required\" });\n return;\n }\n\n let fullPath = themePath;\n if (!existsSync(fullPath)) {\n fullPath = join(WORKSPACE_DIR, themePath);\n }\n if (!existsSync(fullPath)) {\n jsonResponse(res, 400, { error: `Theme folder not found: ${themePath}` });\n return;\n }\n\n const themeName = basename(fullPath);\n createSession(fullPath, themeName);\n scanThemeFromDisk(fullPath);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n themeName,\n themePath: fullPath,\n moduleCount: getSession()?.modules.length || 0,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSetupResumeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n if (isGenerating()) { jsonResponse(res, 409, { error: \"Cannot switch projects while AI is generating.\", generating: true }); return; }\n const { sessionId } = JSON.parse(body);\n if (!sessionId || typeof sessionId !== \"string\") {\n jsonResponse(res, 400, { error: \"Session ID is required\" });\n return;\n }\n\n const session = loadSession(sessionId);\n if (!session) {\n jsonResponse(res, 404, { error: \"Session not found\" });\n return;\n }\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: session.themeName,\n themePath: session.themePath,\n moduleCount: session.modules.length,\n messageCount: session.messages.length,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSetupApiKeyRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { apiKey } = JSON.parse(body);\n if (!apiKey || typeof apiKey !== \"string\") {\n jsonResponse(res, 400, { error: \"API key is required\" });\n return;\n }\n\n saveConfig({ anthropicApiKey: apiKey });\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n/**\n * List themes available on HubSpot Design Manager.\n * Returns folders at the root level that look like themes (contain theme.json).\n */\nexport function handleSetupRemoteThemesRoute(res: ServerResponse): void {\n const pak = getHubSpotPak();\n if (!pak) {\n jsonResponse(res, 200, { themes: [], error: \"No HubSpot account connected\" });\n return;\n }\n\n (async () => {\n const folders = await listRootFolders(pak);\n\n if (folders.length === 0) {\n jsonResponse(res, 200, { themes: [] });\n return;\n }\n\n const themes: Array<{ name: string; path: string }> = [];\n\n // Check which folders have a theme.json (in parallel)\n const checks = folders.map(async (folder) => {\n const folderPath = folder.path || folder.name;\n try {\n const tjMeta = await getMetadata(pak, `${folderPath}/theme.json`);\n if (tjMeta && !tjMeta.folder) {\n themes.push({ name: folder.name, path: folderPath });\n }\n } catch { /* not a theme */ }\n });\n\n await Promise.all(checks);\n themes.sort((a, b) => a.name.localeCompare(b.name));\n\n const localThemes = getLocalThemes();\n const localNames = new Set(localThemes.map((t) => t.name));\n\n jsonResponse(res, 200, {\n themes: themes.map((t) => ({\n ...t,\n existsLocally: localNames.has(t.name),\n })),\n });\n })().catch((err) => {\n jsonResponse(res, 200, {\n themes: [],\n error: err instanceof Error ? err.message : String(err),\n });\n });\n}\n","/**\n * Settings routes — environment management, API keys, tool install, auth.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { existsSync, readFileSync, appendFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { jsonResponse, readBody } from \"../route-helpers.js\";\nimport { loadConfig, saveConfig, getApiKeyForEngine, addHubSpotAccount, removeHubSpotAccount, setActiveHubSpotAccount, setCliToolEnabled, type AIEngineType, type HubSpotAccountConfig } from \"../../utils/config.js\";\nimport { listSessions } from \"../session.js\";\nimport { getLocalThemes } from \"./setup.js\";\nimport { detectEnvironment, detectHubSpotCLI, detectHubSpotAuth, detectGitHubCLI, detectGitHubAuth } from \"../../utils/detect.js\";\nimport { validatePak } from \"../../hubspot/api.js\";\nimport { startJob, getJob } from \"../process-manager.js\";\n\n// ---------------------------------------------------------------------------\n// Live model catalog — fetched from provider APIs, cached 10 minutes\n// ---------------------------------------------------------------------------\n\ntype ModelEntry = { id: string; label: string };\nconst modelCache: { data: Record<string, ModelEntry[]>; ts: number } = { data: {}, ts: 0 };\nconst MODEL_CACHE_TTL = 10 * 60 * 1000;\n\nconst STATIC_MODELS: Record<string, ModelEntry[]> = {\n \"claude-code\": [\n { id: \"sonnet\", label: \"Claude Sonnet (default)\" },\n { id: \"opus\", label: \"Claude Opus\" },\n { id: \"haiku\", label: \"Claude Haiku\" },\n ],\n \"codex-cli\": [\n { id: \"o4-mini\", label: \"o4 Mini (default)\" },\n { id: \"o3\", label: \"o3\" },\n { id: \"gpt-4o\", label: \"GPT-4o\" },\n ],\n};\n\nasync function fetchAnthropicModels(apiKey: string): Promise<ModelEntry[]> {\n const resp = await fetch(\"https://api.anthropic.com/v1/models\", {\n headers: { \"x-api-key\": apiKey, \"anthropic-version\": \"2023-06-01\" },\n });\n if (!resp.ok) return [];\n const data = await resp.json() as { data: { id: string; display_name: string }[] };\n return data.data\n .filter((m) => !m.id.startsWith(\"claude-3-\") && !m.id.startsWith(\"claude-2\"))\n .map((m) => ({ id: m.id, label: m.display_name }));\n}\n\nasync function fetchOpenAIModels(apiKey: string): Promise<ModelEntry[]> {\n const resp = await fetch(\"https://api.openai.com/v1/models\", {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (!resp.ok) return [];\n const data = await resp.json() as { data: { id: string }[] };\n const keep = /^(gpt-4o|gpt-4o-mini|o[1-4](-mini)?|o[1-4]-pro)$/;\n return data.data\n .filter((m) => keep.test(m.id))\n .sort((a, b) => a.id.localeCompare(b.id))\n .map((m) => ({ id: m.id, label: m.id }));\n}\n\nasync function fetchGeminiModels(apiKey: string): Promise<ModelEntry[]> {\n const resp = await fetch(\n `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`,\n );\n if (!resp.ok) return [];\n const data = await resp.json() as { models: { name: string; displayName: string }[] };\n return data.models\n .filter((m) => m.name.includes(\"gemini-2\"))\n .map((m) => ({ id: m.name.replace(\"models/\", \"\"), label: m.displayName }));\n}\n\nasync function getModelCatalog(): Promise<Record<string, ModelEntry[]>> {\n if (Date.now() - modelCache.ts < MODEL_CACHE_TTL && Object.keys(modelCache.data).length > 0) {\n return modelCache.data;\n }\n\n const config = loadConfig();\n const catalog: Record<string, ModelEntry[]> = { ...STATIC_MODELS };\n\n const jobs: Promise<void>[] = [];\n\n const anthropicKey = getApiKeyForEngine(\"anthropic-api\", config);\n if (anthropicKey) {\n jobs.push(\n fetchAnthropicModels(anthropicKey)\n .then((models) => { if (models.length) catalog[\"anthropic-api\"] = models; })\n .catch(() => {}),\n );\n }\n\n const openaiKey = getApiKeyForEngine(\"openai-api\", config);\n if (openaiKey) {\n jobs.push(\n fetchOpenAIModels(openaiKey)\n .then((models) => { if (models.length) catalog[\"openai-api\"] = models; })\n .catch(() => {}),\n );\n }\n\n const geminiKey = getApiKeyForEngine(\"gemini-api\", config);\n if (geminiKey) {\n jobs.push(\n fetchGeminiModels(geminiKey)\n .then((models) => {\n if (models.length) {\n catalog[\"gemini-api\"] = models;\n catalog[\"gemini-cli\"] = models;\n }\n })\n .catch(() => {}),\n );\n }\n\n await Promise.all(jobs);\n\n modelCache.data = catalog;\n modelCache.ts = Date.now();\n return catalog;\n}\n\nexport function handleSettingsStatusRoute(res: ServerResponse): void {\n const env = detectEnvironment();\n const config = loadConfig();\n\n const configPayload = {\n aiEngine: config.aiEngine || null,\n claudeCodeModel: config.claudeCodeModel || null,\n anthropicApiModel: config.anthropicApiModel || null,\n openaiApiModel: config.openaiApiModel || null,\n hubspotUploadMode: config.hubspotUploadMode || \"api\",\n hubspotAccounts: (config.hubspotAccounts || []).map((a: HubSpotAccountConfig) => ({\n portalId: a.portalId,\n portalName: a.portalName,\n dataCenter: a.dataCenter,\n })),\n activeHubSpotAccount: config.activeHubSpotAccount || null,\n enabledCLITools: config.enabledCLITools || [],\n };\n\n const sessionCount = listSessions().length;\n const localThemeCount = getLocalThemes().length;\n\n getModelCatalog().then((models) => {\n jsonResponse(res, 200, {\n environment: env,\n config: configPayload,\n models,\n sessionCount,\n localThemeCount,\n });\n }).catch(() => {\n jsonResponse(res, 200, {\n environment: env,\n config: configPayload,\n models: STATIC_MODELS,\n sessionCount,\n localThemeCount,\n });\n });\n}\n\nexport function handleSettingsEngineRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { engine, model } = JSON.parse(body);\n\n const validEngines: AIEngineType[] = [\n \"claude-code\", \"anthropic-api\", \"openai-api\", \"gemini-cli\", \"gemini-api\", \"codex-cli\",\n ];\n if (!validEngines.includes(engine)) {\n jsonResponse(res, 400, { error: `Invalid engine: ${engine}` });\n return;\n }\n\n const configUpdate: Record<string, unknown> = { aiEngine: engine };\n if (model) {\n switch (engine) {\n case \"claude-code\":\n configUpdate.claudeCodeModel = model;\n break;\n case \"anthropic-api\":\n configUpdate.anthropicApiModel = model;\n break;\n case \"openai-api\":\n configUpdate.openaiApiModel = model;\n break;\n }\n }\n\n saveConfig(configUpdate as any);\n jsonResponse(res, 200, { ok: true, engine });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSettingsApiKeyRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { provider, apiKey } = JSON.parse(body);\n\n if (!provider || typeof provider !== \"string\") {\n jsonResponse(res, 400, { error: \"provider is required\" });\n return;\n }\n\n if (!apiKey) {\n const configUpdate: Record<string, unknown> = {};\n switch (provider) {\n case \"anthropic\": configUpdate.anthropicApiKey = \"\"; break;\n case \"openai\": configUpdate.openaiApiKey = \"\"; break;\n case \"gemini\": configUpdate.geminiApiKey = \"\"; break;\n default:\n jsonResponse(res, 400, { error: `Unknown provider: ${provider}` });\n return;\n }\n saveConfig(configUpdate as any);\n jsonResponse(res, 200, { ok: true, provider, deleted: true });\n return;\n }\n\n const configUpdate: Record<string, unknown> = {};\n switch (provider) {\n case \"anthropic\": configUpdate.anthropicApiKey = apiKey; break;\n case \"openai\": configUpdate.openaiApiKey = apiKey; break;\n case \"gemini\": configUpdate.geminiApiKey = apiKey; break;\n default:\n jsonResponse(res, 400, { error: `Unknown provider: ${provider}` });\n return;\n }\n\n saveConfig(configUpdate as any);\n\n let autoSelectedEngine: string | null = null;\n const currentConfig = loadConfig();\n if (!currentConfig.aiEngine) {\n const engineMap: Record<string, string> = {\n anthropic: \"anthropic-api\",\n openai: \"openai-api\",\n gemini: \"gemini-api\",\n };\n const engine = engineMap[provider];\n if (engine) {\n saveConfig({ aiEngine: engine } as any);\n autoSelectedEngine = engine;\n }\n }\n\n jsonResponse(res, 200, { ok: true, provider, autoSelectedEngine });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSettingsInstallRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { tool } = JSON.parse(body);\n\n const installCommands: Record<string, { cmd: string; desc: string }> = {\n hubspot: { cmd: \"npm install -g @hubspot/cli\", desc: \"Installing HubSpot CLI\" },\n claude: { cmd: \"npm install -g @anthropic-ai/claude-code\", desc: \"Installing Claude Code\" },\n gemini: { cmd: \"npm install -g @google/gemini-cli\", desc: \"Installing Gemini CLI\" },\n codex: { cmd: process.platform === \"darwin\" ? \"brew install --cask codex\" : \"npm install -g @openai/codex\", desc: \"Installing OpenAI Codex\" },\n gh: { cmd: process.platform === \"darwin\" ? \"brew install gh\" : \"npm install -g @cli/gh\", desc: \"Installing GitHub CLI\" },\n };\n\n const config = installCommands[tool];\n if (!config) {\n jsonResponse(res, 400, { error: `Unknown tool: ${tool}. Valid: ${Object.keys(installCommands).join(\", \")}` });\n return;\n }\n\n const jobId = startJob(config.cmd, config.desc, { timeout: 120_000 });\n jsonResponse(res, 200, { ok: true, jobId });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSettingsHsAuthRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const parsed = JSON.parse(body || \"{}\");\n const config = loadConfig();\n const uploadMode = config.hubspotUploadMode || \"api\";\n\n if (parsed.personalAccessKey) {\n if (uploadMode === \"api\") {\n // API mode: validate PAK directly via HTTP, store in config\n validatePak(parsed.personalAccessKey).then((info) => {\n addHubSpotAccount(parsed.personalAccessKey, info.portalId, info.portalName, info.dataCenter);\n jsonResponse(res, 200, {\n ok: true,\n portalName: info.portalName,\n portalId: info.portalId,\n dataCenter: info.dataCenter,\n });\n }).catch((err) => {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n });\n return;\n } else {\n // CLI mode: use hs auth command\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n jsonResponse(res, 400, { error: \"HubSpot CLI not installed\", needsInstall: true });\n return;\n }\n const jobId = startJob(\n `hs auth --pak=\"${parsed.personalAccessKey}\"`,\n \"Authenticating with HubSpot\",\n { timeout: 30_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n }\n\n // No key provided — check existing auth\n if (uploadMode === \"api\") {\n const accounts = config.hubspotAccounts || [];\n if (accounts.length > 0 && !parsed.force) {\n const active = accounts.find((a) => a.portalId === config.activeHubSpotAccount) || accounts[0];\n jsonResponse(res, 200, {\n ok: true,\n alreadyAuthenticated: true,\n portalName: active.portalName,\n portalId: active.portalId,\n });\n return;\n }\n } else {\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n jsonResponse(res, 400, { error: \"HubSpot CLI not installed\", needsInstall: true });\n return;\n }\n const auth = detectHubSpotAuth();\n if (auth.authenticated && !parsed.force) {\n jsonResponse(res, 200, {\n ok: true,\n alreadyAuthenticated: true,\n portalName: auth.portalName,\n portalId: auth.portalId,\n });\n return;\n }\n }\n\n jsonResponse(res, 200, {\n needsKey: true,\n instructions: \"Create a personal access key in HubSpot\",\n url: \"https://app.hubspot.com/portal-recommend/l?slug=personal-access-key\",\n steps: [\n \"Click the link above to open HubSpot\",\n \"Select your account\",\n \"Create a Personal Access Key with CMS permissions\",\n \"Copy the key and paste it below\",\n ],\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSettingsGhAuthRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const parsed = JSON.parse(body || \"{}\");\n\n const gh = detectGitHubCLI();\n if (!gh.found) {\n jsonResponse(res, 400, { error: \"GitHub CLI not installed\", needsInstall: true });\n return;\n }\n\n const auth = detectGitHubAuth();\n if (auth.authenticated && !parsed.force) {\n jsonResponse(res, 200, {\n ok: true,\n alreadyAuthenticated: true,\n username: auth.username,\n });\n return;\n }\n\n if (parsed.token) {\n const jobId = startJob(\n `echo \"${parsed.token}\" | gh auth login --with-token`,\n \"Authenticating with GitHub\",\n { timeout: 30_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n\n const jobId = startJob(\n \"gh auth login --web --git-protocol https\",\n \"GitHub authentication (check your browser)\",\n { timeout: 300_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, browserAuthRequired: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSettingsHsSwitchRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { portalId, action } = JSON.parse(body);\n const config = loadConfig();\n const uploadMode = config.hubspotUploadMode || \"api\";\n\n if (uploadMode === \"api\") {\n // API mode: synchronous config updates (no subprocess)\n if (action === \"remove\" && portalId) {\n removeHubSpotAccount(portalId);\n jsonResponse(res, 200, { ok: true });\n return;\n }\n if (portalId) {\n setActiveHubSpotAccount(portalId);\n jsonResponse(res, 200, { ok: true });\n return;\n }\n } else {\n // CLI mode: use hs accounts commands\n const hs = detectHubSpotCLI();\n if (!hs.found) {\n jsonResponse(res, 400, { error: \"HubSpot CLI not installed\" });\n return;\n }\n if (action === \"remove\" && portalId) {\n const jobId = startJob(`hs accounts remove ${portalId}`, `Removing HubSpot account ${portalId}`, { timeout: 15_000 });\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n if (portalId) {\n const jobId = startJob(`hs accounts use ${portalId}`, `Switching to HubSpot account ${portalId}`, { timeout: 15_000 });\n jsonResponse(res, 200, { ok: true, jobId });\n return;\n }\n }\n\n jsonResponse(res, 400, { error: \"portalId required\" });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleSettingsGhLogoutRoute(res: ServerResponse): void {\n const jobId = startJob(\n \"gh auth logout --hostname github.com -y\",\n \"Logging out of GitHub\",\n { timeout: 15_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId });\n}\n\nexport function handleSettingsCLIAuthRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { cli, apiKey } = JSON.parse(body || \"{}\");\n\n switch (cli) {\n case \"claude\": {\n const jobId = startJob(\n \"CLAUDECODE= claude --print -p 'reply OK'\",\n \"Authenticating Claude Code (check your browser if prompted)\",\n { timeout: 120_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, hint: \"If Claude Code opens a browser window, complete the sign-in there.\" });\n break;\n }\n case \"gemini\": {\n const jobId = startJob(\n \"gemini -p 'reply OK'\",\n \"Authenticating Gemini CLI (check your browser if prompted)\",\n { timeout: 120_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, hint: \"If Gemini opens a browser window, complete the sign-in there.\" });\n break;\n }\n case \"codex\": {\n if (apiKey && apiKey.trim()) {\n const key = apiKey.trim();\n process.env.OPENAI_API_KEY = key;\n saveConfig({ openaiApiKey: key } as any);\n if (process.platform !== \"win32\") {\n const profileLine = `export OPENAI_API_KEY=\"${key}\"`;\n const shellProfile = process.env.SHELL?.includes(\"zsh\")\n ? join(homedir(), \".zshrc\")\n : join(homedir(), \".bashrc\");\n try {\n const existing = existsSync(shellProfile)\n ? readFileSync(shellProfile, \"utf-8\")\n : \"\";\n if (!existing.includes(\"OPENAI_API_KEY\")) {\n appendFileSync(shellProfile, `\\n# Added by vibeSpot\\n${profileLine}\\n`);\n }\n } catch { /* ignore profile write errors */ }\n }\n jsonResponse(res, 200, { ok: true, message: \"API key saved\" });\n } else {\n const jobId = startJob(\n \"codex login\",\n \"Authenticating Codex CLI (check your browser if prompted)\",\n { timeout: 120_000 }\n );\n jsonResponse(res, 200, { ok: true, jobId, hint: \"Complete the sign-in in your browser.\" });\n }\n break;\n }\n default:\n jsonResponse(res, 400, { error: `Unknown CLI: ${cli}` });\n }\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// HubSpot upload mode toggle\n// ---------------------------------------------------------------------------\n\nexport function handleSettingsHsModeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { mode } = JSON.parse(body);\n if (mode !== \"api\" && mode !== \"cli\") {\n jsonResponse(res, 400, { error: `Invalid mode: ${mode}. Must be \"api\" or \"cli\".` });\n return;\n }\n saveConfig({ hubspotUploadMode: mode } as any);\n jsonResponse(res, 200, { ok: true, mode });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// CLI tool toggle\n// ---------------------------------------------------------------------------\n\nexport function handleSettingsCliToggleRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { toolId, enabled } = JSON.parse(body);\n if (!toolId || typeof enabled !== \"boolean\") {\n jsonResponse(res, 400, { error: \"toolId (string) and enabled (boolean) required\" });\n return;\n }\n setCliToolEnabled(toolId, enabled);\n jsonResponse(res, 200, { ok: true, toolId, enabled });\n } catch (err) {\n jsonResponse(res, 400, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Job polling\n// ---------------------------------------------------------------------------\n\nexport function handleSettingsJobRoute(path: string, res: ServerResponse): void {\n const jobId = path.replace(\"/api/settings/job/\", \"\");\n if (!jobId) {\n jsonResponse(res, 400, { error: \"Job ID required\" });\n return;\n }\n\n const job = getJob(jobId);\n if (!job) {\n jsonResponse(res, 404, { error: \"Job not found\" });\n return;\n }\n\n jsonResponse(res, 200, {\n id: job.id,\n status: job.status,\n description: job.description,\n output: job.output,\n exitCode: job.exitCode,\n startedAt: job.startedAt,\n completedAt: job.completedAt,\n });\n}\n","/**\n * Theme routes — list, switch, delete, rename themes.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { existsSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { jsonResponse, readBody } from \"../route-helpers.js\";\nimport {\n getSession,\n listSessions,\n loadSession,\n deleteSession,\n renameSession,\n saveSession,\n} from \"../session.js\";\nimport { WORKSPACE_DIR } from \"./setup.js\";\n\nexport function handleThemesRoute(method: string, req: IncomingMessage, res: ServerResponse): void {\n if (method === \"GET\") {\n const session = getSession();\n const sessions = listSessions()\n .sort((a, b) => b.updatedAt - a.updatedAt);\n\n jsonResponse(res, 200, {\n activeTheme: session\n ? { id: session.id, themeName: session.themeName }\n : null,\n sessions,\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n try {\n const { sessionId, deleteFiles } = JSON.parse(body);\n deleteSession(sessionId, deleteFiles);\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\nexport function handleThemeSwitchRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { sessionId } = JSON.parse(body);\n const session = loadSession(sessionId);\n if (!session) {\n jsonResponse(res, 404, { error: \"Session not found\" });\n return;\n }\n\n jsonResponse(res, 200, {\n ok: true,\n themeName: session.themeName,\n themePath: session.themePath,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleDeleteLocalThemeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { themeName } = JSON.parse(body);\n if (!themeName || typeof themeName !== \"string\") {\n jsonResponse(res, 400, { error: \"Theme name is required\" });\n return;\n }\n const themePath = join(WORKSPACE_DIR, themeName);\n if (!existsSync(themePath)) {\n jsonResponse(res, 404, { error: \"Theme not found on disk\" });\n return;\n }\n rmSync(themePath, { recursive: true, force: true });\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleRenameThemeRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { sessionId, newName } = JSON.parse(body);\n if (!sessionId || !newName || typeof newName !== \"string\") {\n jsonResponse(res, 400, { error: \"sessionId and newName are required\" });\n return;\n }\n const sanitized = newName.toLowerCase().replace(/[^a-z0-9-]/g, \"-\").replace(/^-|-$/g, \"\").replace(/-{2,}/g, \"-\");\n if (!sanitized) {\n jsonResponse(res, 400, { error: \"Invalid name\" });\n return;\n }\n const result = renameSession(sessionId, sanitized);\n if (result.ok) {\n jsonResponse(res, 200, { ok: true, newName: sanitized });\n } else {\n jsonResponse(res, 400, { error: result.error });\n }\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n","/**\n * Dashboard & template routes — CRUD, activate, rename, module library, brand assets, download.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { existsSync, readFileSync, rmSync } from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport { jsonResponse, readBody } from \"../route-helpers.js\";\nimport { log } from \"../log.js\";\nimport {\n getSession,\n saveSession,\n getOrderedModules,\n getActiveTemplate,\n setActiveTemplate,\n addTemplate,\n removeTemplate,\n getModuleLibrary,\n renameTemplate,\n type PageType,\n} from \"../session.js\";\nimport { ensureDir, writeFile } from \"../../utils/fs.js\";\n\nexport function handleDashboardRoute(res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n const library = getModuleLibrary();\n jsonResponse(res, 200, {\n themeName: session.themeName,\n themePath: session.themePath,\n templates: session.templates.map((t) => ({\n id: t.id,\n label: t.label,\n pageType: t.pageType,\n moduleCount: t.modules.length,\n messageCount: t.messages.length,\n })),\n activeTemplateId: session.activeTemplateId,\n moduleLibrary: library.map((entry) => ({\n moduleName: entry.module.moduleName,\n usedIn: entry.usedIn,\n })),\n brandAssets: {\n hasStyleguide: !!session.brandAssets?.styleguide,\n hasBrandvoice: !!session.brandAssets?.brandvoice,\n humanify: session.brandAssets?.humanify !== false,\n },\n });\n}\n\nexport function handleDownloadZipRoute(res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n const themePath = session.themePath;\n if (!existsSync(themePath)) {\n jsonResponse(res, 404, { error: \"Theme directory not found\" });\n return;\n }\n\n const themeName = session.themeName || \"theme\";\n const parentDir = join(themePath, \"..\");\n const folderName = basename(themePath);\n\n try {\n const zipFileName = `${themeName}.zip`;\n const tmpZip = join(parentDir, zipFileName);\n\n if (existsSync(tmpZip)) rmSync(tmpZip);\n\n execSync(\n `zip -r \"${zipFileName}\" \"${folderName}\" -x \"${folderName}/.git/*\" \"${folderName}/.vibespot/*\" \"${folderName}/node_modules/*\"`,\n { cwd: parentDir, timeout: 30_000 }\n );\n\n const zipData = readFileSync(tmpZip);\n rmSync(tmpZip);\n\n res.writeHead(200, {\n \"Content-Type\": \"application/zip\",\n \"Content-Disposition\": `attachment; filename=\"${zipFileName}\"`,\n \"Content-Length\": zipData.length,\n });\n res.end(zipData);\n } catch (err: any) {\n log.error(\"download-zip\", \"Failed to create zip archive\", err);\n jsonResponse(res, 500, { error: \"Failed to create zip archive\" });\n }\n}\n\nexport function handleTemplatesRoute(method: string, req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n if (method === \"GET\") {\n jsonResponse(res, 200, {\n templates: session.templates.map((t) => ({\n id: t.id,\n label: t.label,\n pageType: t.pageType,\n moduleCount: t.modules.length,\n })),\n activeTemplateId: session.activeTemplateId,\n });\n return;\n }\n\n if (method === \"POST\") {\n readBody(req, (body) => {\n try {\n const { pageType, label } = JSON.parse(body);\n if (!pageType || !label) {\n jsonResponse(res, 400, { error: \"pageType and label are required\" });\n return;\n }\n const validTypes: PageType[] = [\"landing_page\", \"blog_post\", \"website_page\", \"module_only\"];\n if (!validTypes.includes(pageType)) {\n jsonResponse(res, 400, { error: `Invalid pageType: ${pageType}` });\n return;\n }\n\n const entry = addTemplate(pageType, label);\n saveSession();\n\n jsonResponse(res, 200, {\n ok: true,\n template: {\n id: entry.id,\n label: entry.label,\n pageType: entry.pageType,\n },\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n try {\n const { templateId } = JSON.parse(body);\n if (!templateId) {\n jsonResponse(res, 400, { error: \"templateId is required\" });\n return;\n }\n const removed = removeTemplate(templateId);\n if (!removed) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\nexport function handleTemplateActivateRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { templateId } = JSON.parse(body);\n if (!templateId) {\n jsonResponse(res, 400, { error: \"templateId is required\" });\n return;\n }\n const success = setActiveTemplate(templateId);\n if (!success) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n saveSession();\n const session = getSession();\n jsonResponse(res, 200, {\n ok: true,\n modules: getOrderedModules().map((m) => m.moduleName),\n messageCount: session?.messages.length || 0,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleTemplateRenameRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { templateId, newLabel } = JSON.parse(body);\n if (!templateId || !newLabel || typeof newLabel !== \"string\") {\n jsonResponse(res, 400, { error: \"templateId and newLabel are required\" });\n return;\n }\n const success = renameTemplate(templateId, newLabel.trim());\n if (!success) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n saveSession();\n jsonResponse(res, 200, { ok: true, newLabel: newLabel.trim() });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleModuleLibraryRoute(res: ServerResponse): void {\n const library = getModuleLibrary();\n jsonResponse(res, 200, {\n modules: library.map((entry) => ({\n moduleName: entry.module.moduleName,\n usedIn: entry.usedIn,\n fieldsJson: entry.module.fieldsJson,\n })),\n });\n}\n\nexport function handleAddModuleToTemplateRoute(path: string, req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n readBody(req, (body) => {\n try {\n const { moduleName } = JSON.parse(body);\n if (!moduleName) {\n jsonResponse(res, 400, { error: \"moduleName is required\" });\n return;\n }\n\n const library = getModuleLibrary();\n const entry = library.find((e) => e.module.moduleName === moduleName);\n if (!entry) {\n jsonResponse(res, 404, { error: `Module \"${moduleName}\" not found in library` });\n return;\n }\n\n const modCopy = { ...entry.module };\n const existing = session.modules.find((m) => m.moduleName === modCopy.moduleName);\n if (!existing) {\n session.modules.push(modCopy);\n session.moduleOrder.push(modCopy.moduleName);\n session.updatedAt = Date.now();\n }\n\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n\nexport function handleBrandAssetsRoute(method: string, req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n if (method === \"GET\") {\n jsonResponse(res, 200, {\n styleguide: session.brandAssets?.styleguide || null,\n brandvoice: session.brandAssets?.brandvoice || null,\n });\n return;\n }\n\n if (method === \"POST\") {\n readBody(req, (body) => {\n try {\n const { type, content } = JSON.parse(body);\n if (!type) {\n jsonResponse(res, 400, { error: \"type is required\" });\n return;\n }\n\n if (!session.brandAssets) session.brandAssets = {};\n\n if (type === \"humanify\") {\n session.brandAssets.humanify = content === \"on\";\n session.updatedAt = Date.now();\n saveSession();\n jsonResponse(res, 200, { ok: true });\n return;\n }\n\n if (!content) {\n jsonResponse(res, 400, { error: \"content is required\" });\n return;\n }\n if (type !== \"styleguide\" && type !== \"brandvoice\") {\n jsonResponse(res, 400, { error: `Invalid type: ${type}. Must be \"styleguide\" or \"brandvoice\"` });\n return;\n }\n\n session.brandAssets[type] = content;\n session.updatedAt = Date.now();\n\n const assetDir = join(session.themePath, \".vibespot\");\n ensureDir(assetDir);\n writeFile(join(assetDir, `${type}.md`), content);\n\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n try {\n const { type } = JSON.parse(body);\n if (type !== \"styleguide\" && type !== \"brandvoice\") {\n jsonResponse(res, 400, { error: `Invalid type: ${type}` });\n return;\n }\n\n if (session.brandAssets) {\n delete session.brandAssets[type];\n }\n session.updatedAt = Date.now();\n\n const filePath = join(session.themePath, \".vibespot\", `${type}.md`);\n if (existsSync(filePath)) rmSync(filePath);\n\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n","/**\n * Module, field, import, session, upload, and history routes.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { join } from \"node:path\";\nimport { jsonResponse, readBody } from \"../route-helpers.js\";\nimport {\n getSession,\n getOrderedModules,\n removeModule,\n detachModule,\n reorderModules,\n updateFieldValue,\n saveSession,\n writeModulesToDisk,\n addMessage,\n reloadModulesFromDisk,\n reloadActiveTemplateFromDisk,\n getActiveTemplate,\n} from \"../session.js\";\nimport { isGenerating } from \"../ai-handler.js\";\nimport { applyAutoFixes } from \"../auto-fix.js\";\nimport { startStreamingJob } from \"../process-manager.js\";\nimport { analyzeSource } from \"../../wizard/source.js\";\nimport { commitThemeState, commitTemplateState, getHistory, getTemplateHistory, rollbackToCommit, rollbackTemplateToCommit, isGitAvailable } from \"../project-git.js\";\n\nexport function handleSessionRoute(method: string, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n jsonResponse(res, 200, {\n id: session.id,\n themeName: session.themeName,\n themePath: session.themePath,\n messageCount: session.messages.length,\n moduleCount: session.modules.length,\n moduleOrder: session.moduleOrder,\n });\n}\n\nexport function handleModulesRoute(\n method: string,\n req: IncomingMessage,\n res: ServerResponse\n): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n if (method === \"GET\") {\n const ordered = getOrderedModules();\n jsonResponse(res, 200, {\n modules: ordered.map((m) => ({\n moduleName: m.moduleName,\n fieldsJson: m.fieldsJson,\n moduleHtml: m.moduleHtml,\n moduleCss: m.moduleCss,\n moduleJs: m.moduleJs || null,\n })),\n sharedCss: session.sharedCss,\n sharedJs: session.sharedJs,\n });\n return;\n }\n\n if (method === \"DELETE\") {\n readBody(req, (body) => {\n const { moduleName, deleteEntirely } = JSON.parse(body);\n if (deleteEntirely) {\n removeModule(moduleName);\n } else {\n detachModule(moduleName);\n }\n saveSession();\n jsonResponse(res, 200, { ok: true });\n });\n return;\n }\n\n jsonResponse(res, 405, { error: \"Method not allowed\" });\n}\n\nexport function handleReorderRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n const { order } = JSON.parse(body);\n if (Array.isArray(order)) {\n reorderModules(order);\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } else {\n jsonResponse(res, 400, { error: \"order must be an array\" });\n }\n });\n}\n\nexport async function handleUploadRoute(res: ServerResponse): Promise<void> {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n try {\n writeModulesToDisk();\n const fixes = applyAutoFixes(session.themePath);\n\n const jobId = startStreamingJob(\n `hs cms upload \"${session.themePath}\" \"${session.themeName}\"`,\n \"Uploading to HubSpot\",\n { cwd: join(session.themePath, \"..\"), timeout: 180_000 }\n );\n\n jsonResponse(res, 200, {\n ok: true,\n jobId,\n fixes,\n });\n } catch (err) {\n jsonResponse(res, 500, { error: String(err) });\n }\n}\n\nexport function handleFieldRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { moduleName, fieldPath, value } = JSON.parse(body);\n updateFieldValue(moduleName, fieldPath, value);\n saveSession();\n jsonResponse(res, 200, { ok: true });\n } catch (err) {\n jsonResponse(res, 400, { error: String(err) });\n }\n });\n}\n\nexport function handleImportRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const { url } = JSON.parse(body);\n if (!url || typeof url !== \"string\") {\n jsonResponse(res, 400, { error: \"url is required\" });\n return;\n }\n\n const analysis = analyzeSource(url);\n\n const componentSummary = analysis.components\n .map((c) => `- ${c.name}: ${c.description}`)\n .join(\"\\n\");\n\n const summary = {\n sourceDir: analysis.sourceDir,\n componentCount: analysis.components.length,\n components: analysis.components.map((c) => ({\n name: c.name,\n description: c.description,\n })),\n hasTailwind: analysis.hasTailwind,\n cssVarCount: analysis.cssVarCount,\n fonts: analysis.fonts,\n interactions: analysis.interactions,\n conversionPrompt: `Import and convert the React landing page from ${url} to native HubSpot modules.\n\nSource analysis found ${analysis.components.length} components:\n${componentSummary}\n\nDesign system: ${analysis.hasTailwind ? \"Tailwind CSS\" : \"Custom CSS\"}, ${analysis.cssVarCount} CSS variables\nFonts: ${analysis.fonts.length > 0 ? analysis.fonts.join(\", \") : \"System fonts\"}\nInteractions: ${analysis.interactions.join(\", \")}\n\nRead the React source files from ${analysis.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.`,\n };\n\n jsonResponse(res, 200, summary);\n } catch (err) {\n jsonResponse(res, 500, {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Version history routes\n// ---------------------------------------------------------------------------\n\nexport function handleHistoryRoute(req: IncomingMessage, res: ServerResponse): void {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n if (!isGitAvailable()) {\n jsonResponse(res, 200, { available: false, commits: [] });\n return;\n }\n\n const url = new URL(req.url || \"/\", \"http://localhost\");\n const templateId = url.searchParams.get(\"templateId\");\n\n const commits = templateId\n ? getTemplateHistory(session.themePath, templateId, 50)\n : getHistory(session.themePath, 50);\n jsonResponse(res, 200, { available: true, commits, filtered: !!templateId });\n}\n\nexport function handleRollbackRoute(req: IncomingMessage, res: ServerResponse): void {\n readBody(req, (body) => {\n try {\n const session = getSession();\n if (!session) {\n jsonResponse(res, 404, { error: \"No active session\" });\n return;\n }\n\n const { hash, templateId } = JSON.parse(body);\n if (!hash || typeof hash !== \"string\") {\n jsonResponse(res, 400, { error: \"Commit hash is required\" });\n return;\n }\n\n addMessage(\"assistant\", `Rolled back to version ${hash.slice(0, 7)}.`);\n\n if (templateId) {\n const tpl = session.templates.find((t) => t.id === templateId);\n if (!tpl) {\n jsonResponse(res, 404, { error: \"Template not found\" });\n return;\n }\n const filePaths = tpl.moduleOrder.map((n) => `modules/${n}.module`);\n if (tpl.templateFile) filePaths.push(tpl.templateFile);\n\n const result = rollbackTemplateToCommit(session.themePath, templateId, hash, filePaths);\n if (!result.success) {\n jsonResponse(res, 500, { error: result.error || \"Rollback failed\" });\n return;\n }\n reloadActiveTemplateFromDisk();\n } else {\n const result = rollbackToCommit(session.themePath, hash);\n if (!result.success) {\n jsonResponse(res, 500, { error: result.error || \"Rollback failed\" });\n return;\n }\n reloadModulesFromDisk();\n }\n\n saveSession();\n jsonResponse(res, 200, {\n ok: true,\n modules: getOrderedModules().map((m) => m.moduleName),\n });\n } catch (err) {\n jsonResponse(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n });\n}\n","import { buildProgram } from \"./cli/program.js\";\n\nconst program = buildProgram();\nprogram.parseAsync(process.argv).catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":["Command","chalk","palette","noColor","hex","color","theme","VERSION","printBanner","v","theme","o","m","lines","line","join","homedir","readFileSync","existsSync","readdirSync","execSync","run","command","options","err","e","stdout","stderr","runPassthrough","command","options","execSync","join","homedir","readFileSync","writeFileSync","mkdirSync","existsSync","dirname","join","readFile","path","writeFile","content","fileExists","ensureDir","resolveAsset","name","paths","p","CONFIG_DIR","join","homedir","CONFIG_PATH","loadConfig","fileExists","raw","readFile","getApiKeyForEngine","engine","config","c","maskApiKey","key","saveConfig","merged","writeFile","getActiveHubSpotAccount","config","loadConfig","activeId","found","a","addHubSpotAccount","pak","portalId","portalName","dataCenter","accounts","idx","entry","saveConfig","removeHubSpotAccount","update","setActiveHubSpotAccount","getHubSpotPak","isCliToolEnabled","toolId","setCliToolEnabled","enabled","tools","whichCmd","detectNode","result","run","detectGit","detectHubSpotCLI","detectClaudeCode","claudeDir","join","homedir","authenticated","authDetail","existsSync","files","readdirSync","f","detectDataCenter","portalId","configPath","config","readFileSync","accountIdx","keyIdx","keyMatch","detectHubSpotAuth","accounts","defaultName","defaultId","defaultMatch","lines","line","tableMatch","name","authType","detectGeminiCLI","adcPath","hasAdc","hasEnvKey","detectCodexCLI","hasKey","hasOAuth","authFile","detail","detectGitHubCLI","detectGitHubAuth","output","match","altMatch","hasAnthropicKey","nodeVersionOk","version","hsCliVersionOk","major","detectHubSpotAuthFromConfig","loadConfig","uploadMode","configAccounts","a","active","getActiveHubSpotAccount","DISABLED_CLI","detectEnvironment","node","git","hsUploadMode","hsInfo","hs","hsAuth","dc","gh","ghAuth","enabledTools","claude","isCliToolEnabled","gemini","codex","keyStatus","configKey","envVars","maskApiKey","v","anthropicKey","openaiKey","geminiKey","available","readFileSync","basename","BASE_URL","MAX_RETRIES","RETRY_DELAY_MS","TOKEN_REFRESH_BUFFER_MS","tokenCache","exchangePakForToken","pak","cached","resp","body","data","token","authHeaders","accessToken","encodePath","remotePath","detectDataCenterFromPak","sleep","ms","resolve","parseErrorResponse","fallbackPath","message","category","detail","firstError","text","fetchWithRetry","url","options","retries","attempt","delay","validatePak","err","portalId","portalName","uploadFile","localFilePath","fileContent","fileName","formData","blob","error","deleteFile","downloadFile","arrayBuffer","getMetadata","listRootFolders","pak","headers","authHeaders","urlVariants","BASE_URL","url","resp","data","children","c","p","handleCancel","value","theme","intro","title","outro","message","note","text","opts","result","confirm","select","spinner","s","msg","log","logSuccess","logWarn","logError","runPreflight","intro","node","detectNode","logError","nodeVersionOk","logSuccess","git","detectGit","config","loadConfig","useApi","portalId","portalName","pak","getHubSpotPak","acct","getActiveHubSpotAccount","logWarn","note","key","text","v","s","spinner","info","validatePak","addHubSpotAccount","err","hs","detectHubSpotCLI","confirm","run","auth","detectHubSpotAuth","runPassthrough","claude","detectClaudeCode","gemini","detectGeminiCLI","codex","detectCodexCLI","hasKey","hasAnthropicKey","engineLabels","aiEngine","lastUsed","available","a","b","select","theme","saveConfig","model","outro","readdirSync","statSync","join","basename","extname","findComponents","dir","components","searchDirs","join","searchDir","fileExists","files","readdirSync","file","filePath","statSync","ext","extname","name","basename","content","readFile","desc","describeComponent","hints","analyzeCSS","cssFiles","varCount","fonts","cssFile","varMatches","fontMatches","m","font","importMatches","detectInteractions","interactions","hooksDir","hooks","hook","componentDir","analyzeSource","input","sourceDir","wasCloned","repoName","result","run","hasTailwind","setupSource","intro","text","v","logSuccess","theme","s","spinner","logError","logWarn","componentList","c","i","cssInfo","fontInfo","jsInfo","note","confirm","outro","join","mkdirSync","writeFileSync","join","createThemeScaffold","themePath","themeName","themeJson","landingTemplate","baseLayout","mkdirSync","writeFileSync","join","dirname","listFilesRecursive","pak","remotePath","meta","getMetadata","files","rawChildren","child","childName","childPath","childMeta","parallelMap","items","concurrency","fn","index","worker","i","workers","fetchTheme","themeName","targetPath","opts","remoteFiles","mkdirSync","relativePath","localPath","join","dirname","content","downloadFile","writeFileSync","setupTheme","intro","choice","select","themeName","themePath","workspaceDir","join","ensureDir","text","v","s","spinner","config","loadConfig","pak","getHubSpotPak","run","logError","fetchTheme","err","theme","createThemeScaffold","baseHtmlPath","fileExists","logSuccess","baseHtml","readFile","patched","logWarn","cssInsertPoint","insertBefore","jsLine","lineEnd","nextLine","block","insertAt","writeFile","hsignorePath","hsignore","outro","join","readdirSync","rmSync","spawn","join","basename","readdirSync","statSync","writeFileSync","guideCache","cachedAsset","name","val","readFile","resolveAsset","getConversionGuide","getDesignGuide","getContentGuide","getHubspotRules","getHumanifyGuide","getPageTypeGuide","pageType","fullGuide","header","startIdx","afterHeader","buildSystemPrompt","conversionGuide","buildModulePrompt","componentSource","moduleName","cssVars","buildCssPrompt","indexCss","tailwindConfig","pagePrefix","buildJsPrompt","hooksSource","interactiveComponents","buildTemplatePrompt","moduleNames","themeName","i","BOILERPLATE_TEMPLATES","ClaudeCodeEngine","model","opts","sourceDir","themePath","onProgress","guide","getConversionGuide","sourceComponents","existingModules","existingCss","join","existingJs","existingTemplates","prompt","stdout","stderr","progressInterval","resolve","reject","env","args","child","spawn","d","err","code","logPath","logContent","writeFileSync","basename","result","m","outputPreview","stderrPreview","newItems","currentCss","key","currentJs","currentModules","mod","counter","currentTemplates","of","getHubspotRules","cssDir","fileExists","file","readdirSync","readFile","jsDir","templatesDir","content","modulesDir","entry","modDir","statSync","moduleFiles","fj","mj","mh","mc","mjs","e","dir","matches","srcDir","count","fullPath","Anthropic","join","basename","readdirSync","ClaudeAPIEngine","apiKey","Anthropic","opts","sourceDir","themePath","conversionGuide","onProgress","systemPrompt","buildSystemPrompt","dirName","basename","pagePrefix","indexCss","tailwindConfig","cssContent","buildCssPrompt","cssPath","join","writeFile","hooksSource","interactiveSource","jsContent","buildJsPrompt","jsPath","components","modules","i","comp","moduleName","source","readFile","response","buildModulePrompt","parsed","mod","modDir","ensureDir","moduleNames","m","templateContent","buildTemplatePrompt","templatePath","system","user","b","dir","paths","p","fileExists","hooksDir","readdirSync","f","interactive","content","searchDirs","searchDir","count","spawn","join","readdirSync","statSync","GeminiCLIEngine","opts","sourceDir","themePath","onProgress","guide","getConversionGuide","prompt","resolve","reject","child","spawn","stdout","stderr","d","err","code","result","cssDir","join","fileExists","file","readdirSync","readFile","jsDir","templatesDir","content","modulesDir","entry","modDir","statSync","moduleFiles","fj","mj","mh","mc","mjs","spawn","join","readdirSync","statSync","CodexCLIEngine","opts","sourceDir","themePath","onProgress","guide","getConversionGuide","prompt","resolve","reject","child","spawn","stdout","stderr","d","err","code","result","cssDir","join","fileExists","file","readdirSync","readFile","jsDir","templatesDir","content","modulesDir","entry","modDir","statSync","moduleFiles","fj","mj","mh","mc","mjs","createEngine","type","model","ClaudeCodeEngine","GeminiCLIEngine","CodexCLIEngine","ClaudeAPIEngine","runConversion","opts","intro","note","engine","conversionGuide","getConversionGuide","s","spinner","startTime","result","step","detail","logSuccess","elapsed","fixes","validateAndFix","fix","checklist","buildChecklist","lines","item","icon","severity","passed","c","criticalFailures","cosmeticFailures","logError","confirm","logWarn","logPath","join","fileExists","rmSync","outro","themePath","validateTemplates","validateModuleMeta","modulesDir","entry","readdirSync","fieldsPath","moduleName","content","readFile","changed","fields","jsonFixed","fixChoiceFields","fixLinkFields","writeFile","htmlPath","html","templatesDir","file","filePath","fixed","field","f","label","def","href","items","moduleCount","fieldsOk","m","allHaveHtml","missingCss","allHaveCss","hasStyleTab","templateAnnotated","hasTemplateType","hasAvailable","commentEnd","annotation","metaPath","meta","join","basename","join","readdirSync","rmSync","parseApiErrors","apiErrors","errors","err","msg","fixable","parseUploadErrors","output","fileMatch","fieldMatch","applyAutoFixes","themePath","fixes","fixTextareaFields","fixReservedNames","fixNowFunction","fixHubDbTemplates","fixLinkFieldDefaults","fixColorFieldDefaults","fixCdnImports","autoFixError","error","fixed","modulesDir","join","fileExists","entry","readdirSync","fieldsPath","content","readFile","writeFile","htmlPath","templatesDir","file","filePath","rmSync","fields","fixLinkFieldsRecursive","cssDir","cleaned","cssPath","fixColorFieldsRecursive","field","f","def","colorVal","isValidHexColor","converted","convertToHex","color","hex3","rgba","r","g","b","hex","opacity","named","lower","href","readdirSync","join","relative","EXCLUDED_DIRS","walkDir","dir","files","entry","readdirSync","fullPath","join","parallelMap","items","concurrency","fn","index","worker","i","workers","uploadTheme","pak","themePath","themeName","opts","localFiles","total","uploaded","failed","errors","localPath","rel","relative","remotePath","result","uploadFile","err","countUploadedFiles","output","runUpload","themePath","intro","themeName","basename","config","loadConfig","pak","getHubSpotPak","useApi","s","spinner","MAX_RETRIES","attempt","errors","uploadedCount","success","result","uploadTheme","parseApiErrors","run","join","fullOutput","parseUploadErrors","outro","logError","logWarn","confirm","anyFixed","error","autoFixError","logSuccess","deleteFile","execSync","rmSync","basename","showNextSteps","opts","portalId","sourceDir","themePath","wasCloned","intro","host","detectDataCenter","note","theme","confirm","url","platform","execSync","logSuccess","log","dirsToClean","fileExists","basename","dir","rmSync","logWarn","outro","wizardCommand","printBanner","preflight","runPreflight","source","setupSource","saveConfig","themeInfo","setupTheme","runConversion","runUpload","showNextSteps","initCommand","printBanner","runPreflight","convertCommand","printBanner","config","loadConfig","logError","source","setupSource","themeInfo","setupTheme","runConversion","uploadCommand","printBanner","config","loadConfig","confirm","runUpload","path","text","v","doctorCommand","printBanner","intro","issues","node","detectNode","nodeVersionOk","logSuccess","logWarn","log","logError","git","detectGit","hs","detectHubSpotCLI","hsCliVersionOk","auth","detectHubSpotAuth","claude","detectClaudeCode","theme","gemini","detectGeminiCLI","codex","detectCodexCLI","config","loadConfig","anthropicKey","openaiKey","geminiKey","engineLabels","outro","join","existsSync","execSync","chalk","createServer","readFileSync","existsSync","join","extname","createHash","WebSocketServer","readFileSync","readdirSync","existsSync","writeFileSync","mkdirSync","rmSync","renameSync","join","dirname","homedir","existsSync","writeFileSync","mkdirSync","join","gitAvailableCache","isGitAvailable","run","ensureGitRepo","themePath","existsSync","join","ensureVibeSpotDir","init","writeGitIgnore","dir","mkdirSync","gitignorePath","writeFileSync","commitThemeState","message","truncated","commitResult","hashResult","commitTemplateState","templateId","filePaths","fp","fullPath","prefix","maxMsg","fullMessage","getHistory","limit","result","commits","line","parts","timestamp","getTemplateHistory","escapedId","rollbackToCommit","commitHash","verify","msgResult","origMessage","checkout","rollbackMsg","rollbackTemplateToCommit","restored","SESSIONS_DIR","join","homedir","INDEX_PATH","_indexCache","readIndex","existsSync","readFileSync","rebuildIndex","writeIndex","entries","mkdirSync","writeFileSync","f","readdirSync","data","templates","n","t","upsertIndex","session","entry","idx","e","removeFromIndex","sessionId","removeFromIndexByTheme","themeName","activeSession","createSession","themePath","generateId","ensureGitRepo","migrateSession","templateId","getActiveTemplate","setActiveTemplate","tpl","syncFlatFieldsFromTemplate","addTemplate","pageType","label","slug","id","renameTemplate","newLabel","removeTemplate","getModuleLibrary","map","mod","existing","syncFlatFieldsToTemplate","getSession","addMessage","role","content","saveChatToTheme","addSessionAsset","asset","saveSession","updateModules","assets","newMod","m","reorderModules","newOrder","removeModule","moduleName","detachModule","updateFieldValue","fieldPath","value","fields","setFieldDefault","getOrderedModules","ordered","name","scanThemeFromDisk","chatFromDisk","loadChatFromTheme","modulesDir","modDir","safeRead","cssDir","jsDir","cssFiles","jsFiles","sgPath","bvPath","filePath","loadSession","listSessions","deleteSession","deleteFiles","rmSync","renameSession","newName","oldName","oldPath","newPath","dirname","renameSync","err","cssOld","cssNew","jsOld","jsNew","themeJsonPath","themeData","writeModulesToDisk","allModules","modulesBaseDir","templatesDir","templateContent","generateTemplateForEntry","annotated","ensureTemplateAnnotations","writeBlogListingTemplate","template","generateTemplateFromModules","patchBaseTemplate","updateThemeJson","chatDir","chatData","chatPath","reloadModulesFromDisk","reloadActiveTemplateFromDisk","tplPath","basePath","mainJsLine","sections","getOrderedModulesFrom","listingContent","path","parts","fieldName","field","buildContextFromFields","fields","result","field","renderHubL","template","context","output","stripDirectives","processForLoops","processConditionals","resolveExpressions","cleanupRemaining","assemblePreview","opts","styleBlocks","css","scriptBlocks","js","body","RE_REQUIRE_TAG","RE_END_REQUIRE_TAG","RE_REQUIRE_EXPR","RE_GET_ASSET_URL","RE_GET_ASSET_URL_STRIP","RE_DND_TAGS","RE_MODULE_TAG","RE_TEMPLATE_TAGS","RE_ANNOTATIONS","RE_CONTENT_VARS","RE_IF_PATTERN","tpl","_match","filename","safety","match","findOutermostFor","varName","iterExpr","start","end","items","resolveIterable","rendered","item","index","loopContext","out","openTag","forOrEndfor","firstOpen","bodyStart","depth","m","condition","elseMatch","ifBody","elseBody","elifParts","evaluateCondition","i","elifCondition","elifBody","expr","filterParts","path","value","resolvePath","applyFilter","rangeMatch","resolveNumericArg","arr","splitMatch","val","arg","parts","current","part","trimmed","eqMatch","left","operator","right","isTruthy","filter","str","argMatch","filterName","filterArg","len","buildPreviewHtml","session","getSession","welcomePreview","modules","getOrderedModules","renderedModules","moduleCssArray","moduleJsArray","mod","context","fields","buildContextFromFields","rendered","renderHubL","anchorId","assemblePreview","buildModulePreviewHtml","moduleName","tpl","m","execSync","log","context","message","data","line","err","errMsg","tryParseJSON","raw","repaired","lastPos","attempt","err","posMatch","pos","searchStart","lastQuote","absPos","tryRepairTruncatedJSON","modulesIdx","arrayStart","lastCompleteModule","braceDepth","inString","escaped","i","ch","jsonStr","toModuleFiles","m","parseAndApplyModules","response","onWarning","modulesApplied","match","blockPattern","log","data","obj","updateModules","jsonPattern","lastFenceIdx","truncated","salvaged","hasModuleRef","describesProse","msg","spawn","getPromptContext","session","getSession","getActiveTemplate","buildVibeSystemPrompt","conversionGuide","themeName","editMode","pageType","brandAssets","core","pageTypeSection","getPageTypeGuide","pageTypePrompt","brandPrompt","humanifyGuide","getHumanifyGuide","getHubspotRules","getDesignGuide","getContentGuide","buildStateContext","parts","mod","library","getModuleLibrary","currentModuleNames","m","otherModules","e","entry","buildMessagesWithContext","userMessage","fileContexts","messages","stateContext","assetManifest","imageAssets","a","textContent","hasFiles","fc","imageFiles","contentBlocks","img","_AnthropicCtor","getAnthropicSDK","buildFileContextText","fileContexts","parts","fc","CLI_STATUS_MESSAGES","RATE_LIMIT_DELAYS","streamWithAnthropicAPI","userMessage","apiKey","themeName","model","onChunk","onStatus","onFinish","AnthropicSDK","client","conversionGuide","getConversionGuide","editMode","getSession","messages","buildMessagesWithContext","ctx","getPromptContext","systemPrompt","buildVibeSystemPrompt","attempt","fullResponse","statusIndex","sendStatus","heartbeat","stream","event","text","err","status","errType","wait","log","r","streamWithOpenAIAPI","openaiMessages","m","block","response","reader","decoder","buffer","done","value","lines","line","data","delta","streamWithGeminiAPI","session","stateContext","buildStateContext","contents","userContent","userParts","url","spawnCLI","bin","args","prompt","resolve","reject","env","child","spawn","stdout","stderr","d","chunk","code","generateWithClaudeCode","config","loadConfig","msg","result","generateWithCLI","cli","createWriteStream","mkdirSync","existsSync","readFileSync","join","extname","randomUUID","Busboy","jsonResponse","res","status","data","readBody","req","callback","chunks","chunk","MAX_FILE_SIZE","IMAGE_MIMES","DOCUMENT_MIMES","SUPPORTED_MIMES","sanitizeFilename","name","deduplicateFilename","dir","existsSync","join","ext","extname","base","counter","extractPdfText","filePath","pdfParse","buffer","readFileSync","extractDocxText","extractPlainText","handleFileUploadRoute","req","res","session","getSession","jsonResponse","results","errors","fileCount","writePromises","bb","Busboy","fieldname","fileStream","info","originalName","mimeType","isImage","sanitized","id","randomUUID","targetDir","finalFilename","mkdirSync","targetPath","writeStream","createWriteStream","fileSize","truncated","chunk","resolve","asset","addSessionAsset","log","err","a","getFileContexts","fileIds","ctx","imgPath","c","parseWarningCallback","setParseWarningCallback","cb","generatingSessionId","isGenerating","finishResponse","fullResponse","current","getSession","log","addMessage","parseAndApplyModules","saveSession","handleGenerateStream","userMessage","onChunk","onStatus","fileIds","session","fileContexts","getFileContexts","config","loadConfig","engine","detectDefaultEngine","apiKey","getApiKeyForEngine","streamWithAnthropicAPI","streamWithOpenAIAPI","streamWithGeminiAPI","generateWithClaudeCode","generateWithCLI","execSync","spawn","jobs","startJob","command","description","opts","id","job","parts","child","d","code","err","timeout","getJob","cleanupOldJobs","cutoff","startStreamingJob","emitChunk","chunk","listener","addJobListener","jobId","streamingJob","removeJobListener","existsSync","readdirSync","rmSync","join","basename","homedir","execSync","WORKSPACE_DIR","join","homedir","_themeListCache","THEME_LIST_TTL","getLocalThemes","themes","existsSync","entry","readdirSync","themeJson","moduleCount","modulesDir","e","handleSetupInfoRoute","res","session","getSession","env","detectEnvironment","hsInstalled","execSync","sessions","listSessions","a","b","localThemes","jsonResponse","handleSetupCreateRoute","req","readBody","body","isGenerating","name","themeName","themePath","ensureDir","rmSync","createThemeScaffold","createSession","saveSession","err","handleSetupFetchRoute","rawName","pak","getHubSpotPak","config","loadConfig","scanThemeFromDisk","fetchTheme","handleSetupOpenRoute","fullPath","basename","handleSetupResumeRoute","sessionId","loadSession","handleSetupApiKeyRoute","apiKey","saveConfig","handleSetupRemoteThemesRoute","folders","listRootFolders","checks","folder","folderPath","tjMeta","getMetadata","localNames","t","existsSync","readFileSync","appendFileSync","join","homedir","modelCache","MODEL_CACHE_TTL","STATIC_MODELS","fetchAnthropicModels","apiKey","resp","m","fetchOpenAIModels","data","keep","a","b","fetchGeminiModels","getModelCatalog","config","loadConfig","catalog","jobs","anthropicKey","getApiKeyForEngine","models","openaiKey","geminiKey","handleSettingsStatusRoute","res","env","detectEnvironment","configPayload","sessionCount","listSessions","localThemeCount","getLocalThemes","jsonResponse","handleSettingsEngineRoute","req","readBody","body","engine","model","configUpdate","saveConfig","err","handleSettingsApiKeyRoute","provider","autoSelectedEngine","handleSettingsInstallRoute","tool","installCommands","jobId","startJob","handleSettingsHsAuthRoute","parsed","uploadMode","validatePak","info","addHubSpotAccount","detectHubSpotCLI","accounts","active","auth","detectHubSpotAuth","handleSettingsGhAuthRoute","detectGitHubCLI","detectGitHubAuth","handleSettingsHsSwitchRoute","portalId","action","removeHubSpotAccount","setActiveHubSpotAccount","handleSettingsGhLogoutRoute","handleSettingsCLIAuthRoute","cli","key","profileLine","shellProfile","join","homedir","existsSync","readFileSync","appendFileSync","handleSettingsHsModeRoute","mode","handleSettingsCliToggleRoute","toolId","enabled","setCliToolEnabled","handleSettingsJobRoute","path","job","getJob","existsSync","rmSync","join","handleThemesRoute","method","req","res","session","getSession","sessions","listSessions","a","b","jsonResponse","readBody","body","sessionId","deleteFiles","deleteSession","err","handleThemeSwitchRoute","loadSession","handleDeleteLocalThemeRoute","themeName","themePath","join","WORKSPACE_DIR","existsSync","rmSync","handleRenameThemeRoute","newName","sanitized","result","renameSession","existsSync","readFileSync","rmSync","join","basename","execSync","handleDashboardRoute","res","session","getSession","jsonResponse","library","getModuleLibrary","t","entry","handleDownloadZipRoute","themePath","existsSync","themeName","parentDir","join","folderName","basename","zipFileName","tmpZip","rmSync","execSync","zipData","readFileSync","err","log","handleTemplatesRoute","method","req","readBody","body","pageType","label","addTemplate","saveSession","templateId","removeTemplate","handleTemplateActivateRoute","setActiveTemplate","getOrderedModules","m","handleTemplateRenameRoute","newLabel","renameTemplate","handleModuleLibraryRoute","handleAddModuleToTemplateRoute","path","moduleName","e","modCopy","handleBrandAssetsRoute","type","content","assetDir","ensureDir","writeFile","filePath","join","handleSessionRoute","method","res","session","getSession","jsonResponse","handleModulesRoute","req","ordered","getOrderedModules","m","readBody","body","moduleName","deleteEntirely","removeModule","detachModule","saveSession","handleReorderRoute","order","reorderModules","handleUploadRoute","writeModulesToDisk","fixes","applyAutoFixes","jobId","startStreamingJob","join","err","handleFieldRoute","fieldPath","value","updateFieldValue","handleImportRoute","url","analysis","analyzeSource","componentSummary","c","summary","handleHistoryRoute","isGitAvailable","templateId","commits","getTemplateHistory","getHistory","handleRollbackRoute","hash","addMessage","tpl","t","filePaths","n","result","rollbackTemplateToCommit","reloadActiveTemplateFromDisk","rollbackToCommit","reloadModulesFromDisk","MIME_TYPES","startServer","opts","port","uiDir","server","createServer","req","res","handleRequest","wss","WebSocketServer","ws","handleWsConnection","resolve","reject","err","url","method","handleApiRoute","html","buildPreviewHtml","moduleName","buildModulePreviewHtml","serveThemeAsset","serveStatic","path","handleSessionRoute","handleModulesRoute","handleReorderRoute","handleUploadRoute","handleFileUploadRoute","jsonResponse","handleFieldRoute","handleImportRoute","handleSetupInfoRoute","handleSetupCreateRoute","handleSetupFetchRoute","handleSetupOpenRoute","handleSetupResumeRoute","handleSetupApiKeyRoute","handleSetupRemoteThemesRoute","handleSettingsStatusRoute","handleSettingsEngineRoute","handleSettingsApiKeyRoute","handleSettingsInstallRoute","handleSettingsHsAuthRoute","handleSettingsGhAuthRoute","handleSettingsHsSwitchRoute","handleSettingsGhLogoutRoute","handleSettingsCLIAuthRoute","handleSettingsHsModeRoute","handleSettingsCliToggleRoute","handleThemesRoute","handleThemeSwitchRoute","handleDeleteLocalThemeRoute","handleRenameThemeRoute","handleHistoryRoute","handleRollbackRoute","handleDashboardRoute","handleTemplatesRoute","handleTemplateActivateRoute","handleTemplateRenameRoute","handleModuleLibraryRoute","handleBrandAssetsRoute","handleDownloadZipRoute","handleSettingsJobRoute","handleAddModuleToTemplateRoute","data","msg","userMessage","addMessage","saveSession","setParseWarningCallback","warning","fileIds","handleGenerateStream","chunk","status","currentSession","getSession","writeModulesToDisk","activeTpl","getActiveTemplate","commitHash","filePaths","n","commitTemplateState","commitThemeState","getOrderedModules","m","session","fixes","applyAutoFixes","loadConfig","pak","getHubSpotPak","result","uploadTheme","completed","total","acct","getActiveHubSpotAccount","errors","parseApiErrors","e","jobId","startStreamingJob","join","chunkListener","addJobListener","pollInterval","job","getJob","removeJobListener","auth","detectHubSpotAuth","dc","detectDataCenter","parseUploadErrors","errorContext","fixPrompt","fixSession","fixHash","cfg","engineLabels","isGitAvailable","t","filename","filePath","existsSync","ext","extname","contentType","buffer","readFileSync","staticCache","pathname","fullPath","indexPath","content","isHtml","cached","etag","createHash","DEFAULT_PORT","vibeCommand","accent","chalk","dim","uiDir","resolveUiDir","port","close","startServer","url","execSync","resolve","saveSession","err","candidates","join","dir","existsSync","buildProgram","program","Command","vibeCommand","wizardCommand","initCommand","convertCommand","uploadCommand","doctorCommand","program","buildProgram","err"]}
|