vibespot 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibespot",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "AI-powered HubSpot CMS landing page builder — vibe coding & React converter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,6 +23,7 @@
23
23
  "benchmark": "tsx test/eval/benchmark.ts",
24
24
  "prompts:pull": "tsx scripts/sync-prompts.ts",
25
25
  "prompts:seed": "tsx scripts/sync-prompts.ts --from-local",
26
+ "prompts:push": "tsx scripts/sync-prompts.ts --push",
26
27
  "prepublishOnly": "npm run build",
27
28
  "contact-monitor": "tsx scripts/contact-monitor.ts",
28
29
  "docker:publish": "scripts/docker-publish.sh",
@@ -30,7 +31,7 @@
30
31
  "docker:smoke": "scripts/docker-publish.sh --smoke --dry-run"
31
32
  },
32
33
  "dependencies": {
33
- "@anthropic-ai/sdk": "^0.96.0",
34
+ "@anthropic-ai/sdk": "^0.99.0",
34
35
  "@clack/prompts": "^1.3.0",
35
36
  "@codemirror/lang-css": "^6.3.1",
36
37
  "@codemirror/lang-html": "^6.4.11",
@@ -42,6 +43,7 @@
42
43
  "codemirror": "^6.0.2",
43
44
  "commander": "^14.0.3",
44
45
  "execa": "^9.6.1",
46
+ "jszip": "^3.10.1",
45
47
  "mammoth": "^1.11.0",
46
48
  "marked": "^18.0.2",
47
49
  "pdf-parse": "^2.4.5",
package/ui/chat.js CHANGED
@@ -2703,6 +2703,10 @@ function updateModuleList(moduleNames) {
2703
2703
  const pageTreeCountEl = document.getElementById("page-tree-module-count");
2704
2704
  if (pageTreeCountEl) pageTreeCountEl.textContent = moduleNames.length;
2705
2705
 
2706
+ // Download is only meaningful once the theme has at least one module.
2707
+ const downloadBtn = document.getElementById("btn-download");
2708
+ if (downloadBtn) downloadBtn.disabled = moduleNames.length === 0;
2709
+
2706
2710
  // Preserve which items were marked as recently changed across re-renders so
2707
2711
  // the dots survive the per-module `modules_updated` events that happen
2708
2712
  // mid-run.
@@ -3244,6 +3248,19 @@ document.getElementById("btn-upload").addEventListener("click", () => {
3244
3248
  }
3245
3249
  });
3246
3250
 
3251
+ // Download button — fetches the HubSpot-ready .zip of the active theme.
3252
+ // The server streams it as an attachment; an anchor lets the browser save it.
3253
+ document.getElementById("btn-download")?.addEventListener("click", () => {
3254
+ const btn = document.getElementById("btn-download");
3255
+ if (!btn || btn.disabled) return;
3256
+ const a = document.createElement("a");
3257
+ a.href = "/api/download-zip";
3258
+ a.download = "";
3259
+ document.body.appendChild(a);
3260
+ a.click();
3261
+ a.remove();
3262
+ });
3263
+
3247
3264
  // Resize handle
3248
3265
  const resizeHandle = document.getElementById("resize-handle");
3249
3266
  const panelLeft = document.getElementById("panel-left");
@@ -104,6 +104,9 @@
104
104
  <a class="doc-nav__link doc-nav__link--sub" href="#field-editor">Field Editor</a>
105
105
  <a class="doc-nav__link doc-nav__link--sub" href="#brand-kit">Brand Kit</a>
106
106
  <a class="doc-nav__link doc-nav__link--sub" href="#design-system">Design System</a>
107
+ <a class="doc-nav__link" href="#observability">Observability &amp; Cost</a>
108
+ <a class="doc-nav__link doc-nav__link--sub" href="#cost-tracking">Per-Page Cost</a>
109
+ <a class="doc-nav__link doc-nav__link--sub" href="#langfuse">Langfuse Tracing</a>
107
110
  </div>
108
111
 
109
112
  <div class="doc-nav__section">
@@ -361,6 +364,10 @@ vibespot</code></pre>
361
364
  <tr><td><code>enabledCLITools</code></td><td>string[]</td><td>Array of enabled CLI tool IDs: <code>["claude-code", "gemini-cli", "codex-cli"]</code>. Only enabled tools are checked on startup.</td></tr>
362
365
  <tr><td><code>agenticMode</code></td><td>boolean</td><td>Enable the 4-stage agentic pipeline. <code>undefined</code> on first run (vibeSpot prompts you to choose), then <code>true</code> or <code>false</code>.</td></tr>
363
366
  <tr><td><code>agenticConcurrency</code></td><td>number</td><td>Max parallel module generation calls (default: <code>20</code>)</td></tr>
367
+ <tr><td><code>langfuseEnabled</code></td><td>boolean</td><td>Opt in to <a href="#langfuse">Langfuse tracing</a>. Off by default; required even when keys are set.</td></tr>
368
+ <tr><td><code>langfusePublicKey</code></td><td>string</td><td>Langfuse public key (<code>pk-lf-</code>)</td></tr>
369
+ <tr><td><code>langfuseSecretKey</code></td><td>string</td><td>Langfuse secret key (<code>sk-lf-</code>)</td></tr>
370
+ <tr><td><code>langfuseBaseUrl</code></td><td>string</td><td>Langfuse ingestion endpoint (default: <code>https://cloud.langfuse.com</code>)</td></tr>
364
371
  </tbody>
365
372
  </table>
366
373
 
@@ -383,6 +390,10 @@ vibespot</code></pre>
383
390
  <tr><td><code>VIBESPOT_AGENTIC_MODE</code></td><td>Set <code>true</code> to enable the multi-stage agentic pipeline</td></tr>
384
391
  <tr><td><code>VIBESPOT_PORT</code></td><td>Override the HTTP server port (default: <code>4200</code>)</td></tr>
385
392
  <tr><td><code>VIBESPOT_NO_OPEN</code></td><td>Set <code>1</code> to suppress auto-opening the browser on startup</td></tr>
393
+ <tr><td><code>LANGFUSE_ENABLED</code></td><td>Set <code>true</code> to send <a href="#langfuse">Langfuse traces</a>. Required &mdash; keys alone don't enable it.</td></tr>
394
+ <tr><td><code>LANGFUSE_PUBLIC_KEY</code></td><td>Langfuse public key (<code>pk-lf-</code>)</td></tr>
395
+ <tr><td><code>LANGFUSE_SECRET_KEY</code></td><td>Langfuse secret key (<code>sk-lf-</code>)</td></tr>
396
+ <tr><td><code>LANGFUSE_BASE_URL</code></td><td>Langfuse ingestion endpoint (default: <code>https://cloud.langfuse.com</code>)</td></tr>
386
397
  </tbody>
387
398
  </table>
388
399
  </div>
@@ -1171,6 +1182,95 @@ testimonial carousel, and a minimal footer with social links.</code></pre>
1171
1182
  </ul>
1172
1183
  </div>
1173
1184
 
1185
+ <!-- ============================================================
1186
+ Section 6b: Observability & Cost
1187
+ ============================================================ -->
1188
+ <div class="doc-section" id="observability">
1189
+ <h2 id="observability-heading">Observability &amp; Cost <a href="#observability" class="doc-anchor">#</a></h2>
1190
+ <p>Every AI generation spends tokens, which cost money and take time. vibeSpot surfaces both. The per-page cost line is always on and needs no setup. For deeper inspection &mdash; full prompts, per-stage breakdowns, latency, and history across runs &mdash; you can opt in to <a href="https://langfuse.com" target="_blank">Langfuse</a> tracing.</p>
1191
+
1192
+ <h3 id="cost-tracking">Per-Page Cost</h3>
1193
+ <p>After each generation, the chat shows what that page cost. There is nothing to configure &mdash; it works with no keys and no Langfuse.</p>
1194
+ <ul>
1195
+ <li><strong>Per-message cost</strong> &mdash; a small line under each assistant reply showing the estimated USD for that generation, summed across every model call the pipeline made (intent analysis, design system, module planning, and each module).</li>
1196
+ <li><strong>Per-project total</strong> &mdash; a running total chip in the chat header that accumulates across every generation in the theme.</li>
1197
+ </ul>
1198
+ <p>Costs are estimates from an approximate per-model price table, not your provider invoice. When a call uses a model vibeSpot can't price, the total is shown as a lower bound (<code>&ge;</code>). CLI engines (Claude Code, Gemini CLI, Codex CLI) don't report token usage, so no cost is shown for them. This is display-only &mdash; no billing, credits, or quotas.</p>
1199
+
1200
+ <h3 id="langfuse">Langfuse Tracing</h3>
1201
+ <p>Langfuse is an LLM observability platform. With it connected, vibeSpot sends a trace for every generation so you can inspect the exact input and output of each model call, token usage, estimated cost, and latency &mdash; and compare runs over time. It is <strong>opt-in and off by default</strong>.</p>
1202
+ <p>vibeSpot runs locally, not on a backend we operate, so traces go straight from your machine to your Langfuse instance &mdash; Langfuse Cloud or your own self-hosted install. The integration is a small, dependency-free client; it never pulls in a heavy SDK or adds startup overhead when it's off.</p>
1203
+
1204
+ <h4 id="langfuse-model">How a trace is structured</h4>
1205
+ <p>vibeSpot maps the pipeline onto Langfuse's nesting so cost and latency roll up at every level:</p>
1206
+ <ul>
1207
+ <li><strong>Trace</strong> &mdash; one user action (a page generation, a Figma conversion, a brand extraction). The Langfuse <em>session</em> is set to the theme name, so every trace for a project groups together.</li>
1208
+ <li><strong>Span</strong> &mdash; one pipeline stage: intent analysis, design system, module planning, and module development.</li>
1209
+ <li><strong>Generation</strong> &mdash; one model call. The N parallel module calls (plus any retries) nest under the single module-development span.</li>
1210
+ </ul>
1211
+ <p>A full page reads as <code>trace &rarr; stage spans &rarr; generations</code>, with token cost summing up the tree.</p>
1212
+
1213
+ <h4 id="langfuse-instance">Get a Langfuse instance</h4>
1214
+ <p>You need somewhere to send the traces. Pick one: Langfuse's hosted cloud (fastest to start) or your own self-hosted install (your data stays on your infrastructure). Either way you end up with a <strong>public key</strong>, a <strong>secret key</strong>, and a <strong>host URL</strong> &mdash; the three things vibeSpot needs in the next step.</p>
1215
+
1216
+ <p><strong>Option A &mdash; Langfuse Cloud</strong></p>
1217
+ <ol class="doc-steps">
1218
+ <li><strong>Sign up.</strong> Create a free account at <a href="https://cloud.langfuse.com" target="_blank">cloud.langfuse.com</a> (EU region) or <a href="https://us.cloud.langfuse.com" target="_blank">us.cloud.langfuse.com</a> (US region).</li>
1219
+ <li><strong>Create an organization and a project.</strong> Langfuse walks you through this on first login. Traces are scoped to a project.</li>
1220
+ <li><strong>Create API keys.</strong> In the project, open Settings &rarr; API Keys &rarr; <strong>Create new API keys</strong>. Copy the public key (<code>pk-lf-...</code>) and secret key (<code>sk-lf-...</code>) &mdash; the secret is shown only once.</li>
1221
+ <li><strong>Note your host.</strong> It's <code>https://cloud.langfuse.com</code> (EU) or <code>https://us.cloud.langfuse.com</code> (US). You'll use this as the base URL.</li>
1222
+ </ol>
1223
+
1224
+ <p><strong>Option B &mdash; Self-hosted (local)</strong></p>
1225
+ <p>Langfuse ships a Docker Compose stack that runs the whole thing on your machine. With <a href="https://docs.docker.com/get-docker/" target="_blank">Docker</a> installed:</p>
1226
+ <pre><code>git clone https://github.com/langfuse/langfuse.git
1227
+ cd langfuse
1228
+ docker compose up</code></pre>
1229
+ <ol class="doc-steps">
1230
+ <li><strong>Open the UI.</strong> Once the containers are healthy, go to <code>http://localhost:3000</code>. Create an account &mdash; the first user becomes the owner.</li>
1231
+ <li><strong>Create an organization and a project</strong>, same as cloud.</li>
1232
+ <li><strong>Create API keys</strong> under Settings &rarr; API Keys, and copy both.</li>
1233
+ <li><strong>Your host is</strong> <code>http://localhost:3000</code> &mdash; use that as the base URL.</li>
1234
+ </ol>
1235
+ <div class="doc-callout doc-callout--info">
1236
+ <div class="doc-callout__label">&#8505; Local vs. production self-host</div>
1237
+ <p>The Docker Compose stack is meant for local use and evaluation. For a persistent, production self-host (managed Postgres, ClickHouse, object storage, scaling), follow the <a href="https://langfuse.com/self-hosting" target="_blank">Langfuse self-hosting guide</a>. vibeSpot only needs the host URL and a key pair &mdash; it doesn't care how Langfuse is deployed.</p>
1238
+ </div>
1239
+
1240
+ <h4 id="langfuse-setup">Connect vibeSpot</h4>
1241
+ <p>With your keys and host URL from the step above:</p>
1242
+ <ol class="doc-steps">
1243
+ <li><strong>Add the keys in vibeSpot.</strong> Open Settings &rarr; AI tab &rarr; <strong>Observability</strong>. Paste the public and secret keys. They are stored locally in <code>~/.vibespot/config.json</code> and sent only to your Langfuse instance.</li>
1244
+ <li><strong>Set the base URL.</strong> Leave it blank for EU cloud (<code>https://cloud.langfuse.com</code>). Use <code>https://us.cloud.langfuse.com</code> for US cloud, or <code>http://localhost:3000</code> (or your own URL) for a self-hosted install.</li>
1245
+ <li><strong>Turn it on.</strong> Flip the <strong>Send traces to Langfuse</strong> toggle. Generate a page, then check your Langfuse project &mdash; the trace appears under a session named after your theme.</li>
1246
+ </ol>
1247
+ <div class="doc-callout doc-callout--info">
1248
+ <div class="doc-callout__label">&#8505; Keys alone don't enable it</div>
1249
+ <p>Tracing requires <strong>both</strong> an explicit opt-in (the toggle, <code>langfuseEnabled: true</code>, or <code>LANGFUSE_ENABLED=true</code>) <strong>and</strong> both keys set. A stray <code>LANGFUSE_*</code> variable in your environment never sends traces on its own.</p>
1250
+ </div>
1251
+
1252
+ <h4 id="langfuse-config">Config &amp; environment</h4>
1253
+ <p>Instead of the UI, you can configure tracing in <code>~/.vibespot/config.json</code> or via environment variables:</p>
1254
+ <table>
1255
+ <thead>
1256
+ <tr><th>Config field</th><th>Environment variable</th><th>Description</th></tr>
1257
+ </thead>
1258
+ <tbody>
1259
+ <tr><td><code>langfuseEnabled</code></td><td><code>LANGFUSE_ENABLED</code></td><td>Set to <code>true</code> to send traces. Required &mdash; keys alone don't enable it.</td></tr>
1260
+ <tr><td><code>langfusePublicKey</code></td><td><code>LANGFUSE_PUBLIC_KEY</code></td><td>Langfuse public key (<code>pk-lf-...</code>)</td></tr>
1261
+ <tr><td><code>langfuseSecretKey</code></td><td><code>LANGFUSE_SECRET_KEY</code></td><td>Langfuse secret key (<code>sk-lf-...</code>)</td></tr>
1262
+ <tr><td><code>langfuseBaseUrl</code></td><td><code>LANGFUSE_BASE_URL</code></td><td>Ingestion endpoint (default <code>https://cloud.langfuse.com</code>)</td></tr>
1263
+ </tbody>
1264
+ </table>
1265
+
1266
+ <h4 id="langfuse-privacy">What's sent, and what isn't</h4>
1267
+ <ul>
1268
+ <li><strong>Only API engines produce traces.</strong> Anthropic, OpenAI, Gemini, and Langdock report token usage. CLI engines (Claude Code, Gemini CLI, Codex CLI) don't, so they generate no traces or cost.</li>
1269
+ <li><strong>Prompts and outputs are truncated</strong> before sending, so a single trace never ships hundreds of kilobytes of content.</li>
1270
+ <li><strong>It never blocks generation.</strong> All network and serialization errors are swallowed &mdash; a Langfuse outage slows nothing and fails nothing. When tracing is off, there are no network calls at all.</li>
1271
+ </ul>
1272
+ </div>
1273
+
1174
1274
  <!-- ============================================================
1175
1275
  Section 7: Deploying to HubSpot
1176
1276
  ============================================================ -->
@@ -1288,7 +1388,7 @@ testimonial carousel, and a minimal footer with social links.</code></pre>
1288
1388
  <div class="doc-section" id="zip-download">
1289
1389
  <h2 id="zip-download-heading">ZIP Download <a href="#zip-download" class="doc-anchor">#</a></h2>
1290
1390
  <p>Export your theme as a ZIP archive for offline use, sharing, or manual upload to HubSpot.</p>
1291
- <p>Click the <strong>Download ZIP</strong> button on the dashboard toolbar (next to the theme name) to generate and download a <code>.zip</code> file containing all theme files: modules, templates, shared CSS/JS, and assets. The ZIP file is named after the theme (e.g., <code>my-saas-landing.zip</code>).</p>
1391
+ <p>Click the <strong>Download</strong> button in the editor topbar (next to <strong>Deploy</strong>) to generate and download a <code>.zip</code> file containing all theme files: modules, templates, shared CSS/JS, and assets. The archive is HubSpot-ready — import it directly into Design Manager. The ZIP file is named after the theme (e.g., <code>my-saas-landing.zip</code>).</p>
1292
1392
  <div class="doc-callout doc-callout--tip">
1293
1393
  <div class="doc-callout__label">&#10024; When to use ZIP download</div>
1294
1394
  <p>ZIP download is useful when you want to share the theme with a colleague who does not have vibeSpot, back up the theme independently of git, or upload manually through HubSpot's Design Manager.</p>
@@ -1584,6 +1684,7 @@ docker cp vibespot:/home/vibespot/vibespot-themes ./backup-themes</code></pre>
1584
1684
  <li><strong>API keys section</strong> &mdash; Input fields for Anthropic, OpenAI, and Google AI API keys. Keys are displayed masked (only last 4 characters visible) after saving.</li>
1585
1685
  <li><strong>Claude OAuth</strong> &mdash; A section to paste the OAuth token generated by <code>claude setup-token</code>. Shows the token status (valid/expired).</li>
1586
1686
  <li><strong>CLI tools</strong> &mdash; Toggle switches for Claude Code, Gemini CLI, and Codex CLI. CLI tools must be toggled <strong>on</strong> before they appear as selectable engines in the Engine section above. This lazy-detection approach means disabled tools add zero startup overhead. Once toggled on, vibeSpot checks if the CLI is installed and authenticated. If not installed, an install button appears. If installed but not authenticated, an auth button appears.</li>
1687
+ <li><strong>Observability section</strong> &mdash; Opt-in <a href="#langfuse">Langfuse tracing</a>. Paste your public and secret keys, set a base URL if you self-host, and flip the toggle to send a trace for every model call. Off by default. See <a href="#observability">Observability &amp; Cost</a>.</li>
1587
1688
  </ul>
1588
1689
 
1589
1690
  <div class="doc-callout doc-callout--tip">
package/ui/index.html CHANGED
@@ -161,6 +161,10 @@
161
161
  <button class="topbar__icon-btn topbar__mode topbar__mode--editor hidden" id="btn-email-preview" type="button" title="Email client preview (Gmail, Outlook, Apple Mail)" aria-label="Email client preview">
162
162
  <svg class="icon icon--md" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><polyline points="22 4 12 13 2 4"/></svg>
163
163
  </button>
164
+ <button class="btn btn--secondary topbar__mode topbar__mode--editor" id="btn-download" type="button" title="Download theme as a HubSpot-ready .zip" disabled>
165
+ <svg class="icon icon--sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
166
+ Download
167
+ </button>
164
168
  <button class="btn btn--primary topbar__mode topbar__mode--editor" id="btn-upload" type="button" title="Deploy theme to HubSpot">
165
169
  <svg class="icon icon--sm" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>
166
170
  Deploy