vibespot 1.3.1 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -241
- package/assets/readme/00-hero-banner.png +0 -0
- package/assets/readme/00-hero-banner.svg +59 -0
- package/assets/readme/01-vibe-coding-hero.png +0 -0
- package/assets/readme/02-plan-mode.png +0 -0
- package/assets/readme/03-figma-import.png +0 -0
- package/assets/readme/04-multi-page-sites.png +0 -0
- package/assets/readme/05-inline-wysiwyg.png +0 -0
- package/assets/readme/06-hubspot-upload.png +0 -0
- package/dist/index.js +388 -388
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
- package/ui/dashboard.js +4 -3
- package/ui/docs/index.html +144 -4
- package/ui/docs/screenshots/module-overview-slideout.png +0 -0
- package/ui/docs/screenshots.zip +0 -0
- package/ui/index.html +26 -21
- package/ui/settings.js +90 -18
- package/ui/docs/screenshots/asset-type-cards.png +0 -0
- package/ui/docs/screenshots/deploy-progress.png +0 -0
- package/ui/docs/screenshots/email-client-preview.png +0 -0
- package/ui/docs/screenshots/pipeline-progress.png +0 -0
- package/ui/docs/screenshots/project-overview-table.png +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibespot",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "AI-powered HubSpot CMS landing page builder — vibe coding & React converter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,10 +19,14 @@
|
|
|
19
19
|
"build": "tsup",
|
|
20
20
|
"test": "vitest run",
|
|
21
21
|
"test:watch": "vitest",
|
|
22
|
-
"prepublishOnly": "npm run build"
|
|
22
|
+
"prepublishOnly": "npm run build",
|
|
23
|
+
"contact-monitor": "tsx scripts/contact-monitor.ts",
|
|
24
|
+
"docker:publish": "scripts/docker-publish.sh",
|
|
25
|
+
"docker:publish:multi": "scripts/docker-publish.sh --multi-arch",
|
|
26
|
+
"docker:smoke": "scripts/docker-publish.sh --smoke --dry-run"
|
|
23
27
|
},
|
|
24
28
|
"dependencies": {
|
|
25
|
-
"@anthropic-ai/sdk": "^0.
|
|
29
|
+
"@anthropic-ai/sdk": "^0.96.0",
|
|
26
30
|
"@clack/prompts": "^1.3.0",
|
|
27
31
|
"@codemirror/lang-css": "^6.3.1",
|
|
28
32
|
"@codemirror/lang-html": "^6.4.11",
|
package/ui/dashboard.js
CHANGED
|
@@ -1292,15 +1292,16 @@ if (humanifyCheckbox) {
|
|
|
1292
1292
|
// ---------------------------------------------------------------------------
|
|
1293
1293
|
|
|
1294
1294
|
function switchWorkspaceTab(tabName) {
|
|
1295
|
+
if (tabName === "settings") {
|
|
1296
|
+
if (typeof openSettings === "function") openSettings();
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1295
1299
|
document.querySelectorAll(".workspace-tab").forEach((btn) => {
|
|
1296
1300
|
btn.classList.toggle("active", btn.dataset.wsTab === tabName);
|
|
1297
1301
|
});
|
|
1298
1302
|
document.querySelectorAll(".workspace-panel").forEach((panel) => {
|
|
1299
1303
|
panel.classList.toggle("active", panel.dataset.wsPanel === tabName);
|
|
1300
1304
|
});
|
|
1301
|
-
if (tabName === "settings" && typeof refreshSettings === "function") {
|
|
1302
|
-
refreshSettings();
|
|
1303
|
-
}
|
|
1304
1305
|
if (tabName === "library") {
|
|
1305
1306
|
refreshDashboard();
|
|
1306
1307
|
}
|
package/ui/docs/index.html
CHANGED
|
@@ -112,6 +112,12 @@
|
|
|
112
112
|
<a class="doc-nav__link doc-nav__link--sub" href="#auto-fix">Auto-Fix</a>
|
|
113
113
|
<a class="doc-nav__link doc-nav__link--sub" href="#creating-page-hubspot">Creating a Page</a>
|
|
114
114
|
<a class="doc-nav__link" href="#zip-download">ZIP Download</a>
|
|
115
|
+
<a class="doc-nav__link" href="#docker-deployment">Docker Deployment</a>
|
|
116
|
+
<a class="doc-nav__link doc-nav__link--sub" href="#docker-quick-start">Quick Start</a>
|
|
117
|
+
<a class="doc-nav__link doc-nav__link--sub" href="#docker-https">HTTPS with Caddy</a>
|
|
118
|
+
<a class="doc-nav__link doc-nav__link--sub" href="#docker-env-vars">Environment Variables</a>
|
|
119
|
+
<a class="doc-nav__link doc-nav__link--sub" href="#docker-persistence">Persistence</a>
|
|
120
|
+
<a class="doc-nav__link doc-nav__link--sub" href="#docker-reverse-proxy">Reverse Proxy & k8s</a>
|
|
115
121
|
<a class="doc-nav__link" href="#marketplace">Marketplace</a>
|
|
116
122
|
<a class="doc-nav__link" href="#version-history">Version History</a>
|
|
117
123
|
</div>
|
|
@@ -195,7 +201,7 @@ vibespot</code></pre>
|
|
|
195
201
|
<div class="doc-feature">
|
|
196
202
|
<div class="doc-feature__icon">🎨</div>
|
|
197
203
|
<div class="doc-feature__title">Multi-Engine AI</div>
|
|
198
|
-
<div class="doc-feature__desc">Works with Anthropic, OpenAI, Gemini, Claude Code, Gemini CLI, and Codex CLI.</div>
|
|
204
|
+
<div class="doc-feature__desc">Works with Anthropic, OpenAI, Gemini, Langdock, Claude Code, Gemini CLI, and Codex CLI.</div>
|
|
199
205
|
</div>
|
|
200
206
|
<div class="doc-feature">
|
|
201
207
|
<div class="doc-feature__icon">🕒</div>
|
|
@@ -213,7 +219,7 @@ vibespot</code></pre>
|
|
|
213
219
|
<p>vibeSpot stores its configuration at <code>~/.vibespot/config.json</code>. You can configure everything through the Settings panel in the web UI, or by editing the config file directly.</p>
|
|
214
220
|
|
|
215
221
|
<h3 id="ai-engines">AI Engines</h3>
|
|
216
|
-
<p>vibeSpot supports
|
|
222
|
+
<p>vibeSpot supports eight AI engines. You only need one to get started. The table below compares them:</p>
|
|
217
223
|
|
|
218
224
|
<table>
|
|
219
225
|
<thead>
|
|
@@ -225,6 +231,7 @@ vibespot</code></pre>
|
|
|
225
231
|
<tr><td>Claude OAuth</td><td>API</td><td>Run <code>claude setup-token</code>, paste token</td><td>Included in Claude subscription</td><td>Subscribers without API budget</td></tr>
|
|
226
232
|
<tr><td>OpenAI API</td><td>API</td><td>Add <code>OPENAI_API_KEY</code></td><td>Pay-per-token</td><td>GPT-5.5 users, existing OpenAI budget</td></tr>
|
|
227
233
|
<tr><td>Gemini API</td><td>API</td><td>Add <code>GEMINI_API_KEY</code></td><td>Free tier available</td><td>Cost-conscious users, free quota</td></tr>
|
|
234
|
+
<tr><td>Langdock</td><td>API</td><td>Add <code>LANGDOCK_API_KEY</code></td><td>Pay-per-token (via Langdock)</td><td>EU data residency, GDPR compliance</td></tr>
|
|
228
235
|
<tr><td>Gemini CLI</td><td>CLI</td><td>Install <code>gemini</code> CLI, authenticate</td><td>Free (with Google account)</td><td>Free option without API keys</td></tr>
|
|
229
236
|
<tr><td>Codex CLI</td><td>CLI</td><td>Install <code>codex</code> CLI, authenticate</td><td>Included in OpenAI subscription</td><td>OpenAI subscribers</td></tr>
|
|
230
237
|
</tbody>
|
|
@@ -237,6 +244,7 @@ vibespot</code></pre>
|
|
|
237
244
|
<button class="doc-tabs__tab" data-tab="tab-claude-oauth">Claude OAuth</button>
|
|
238
245
|
<button class="doc-tabs__tab" data-tab="tab-openai">OpenAI API</button>
|
|
239
246
|
<button class="doc-tabs__tab" data-tab="tab-gemini-api">Gemini API</button>
|
|
247
|
+
<button class="doc-tabs__tab" data-tab="tab-langdock">Langdock</button>
|
|
240
248
|
<button class="doc-tabs__tab" data-tab="tab-gemini-cli">Gemini CLI</button>
|
|
241
249
|
<button class="doc-tabs__tab" data-tab="tab-codex">Codex CLI</button>
|
|
242
250
|
</div>
|
|
@@ -284,6 +292,18 @@ vibespot</code></pre>
|
|
|
284
292
|
<li>Select <strong>Gemini API</strong> as the engine.</li>
|
|
285
293
|
</ol>
|
|
286
294
|
</div>
|
|
295
|
+
<div class="doc-tabs__panel" id="tab-langdock">
|
|
296
|
+
<p>Langdock is an EU-hosted AI gateway based in Frankfurt. It routes Claude requests through an Anthropic-compatible endpoint, so all Anthropic features (prompt caching, structured output, extended thinking) work unchanged. Langdock provides a single GDPR-native DPA covering OpenAI, Anthropic, Mistral, and Google models.</p>
|
|
297
|
+
<ol class="doc-steps">
|
|
298
|
+
<li>Sign up at <a href="https://langdock.com" target="_blank">langdock.com</a> and generate an API key.</li>
|
|
299
|
+
<li>In vibeSpot Settings → AI tab, paste the key into the Langdock API Key field. Or set the environment variable: <code>export LANGDOCK_API_KEY=...</code></li>
|
|
300
|
+
<li>Select <strong>Langdock</strong> as the engine. The default model is <code>claude-sonnet-4-20250514</code>. All Claude models are available through the gateway.</li>
|
|
301
|
+
</ol>
|
|
302
|
+
<div class="doc-callout doc-callout--info">
|
|
303
|
+
<div class="doc-callout__label">ℹ Self-Hosted Deployments</div>
|
|
304
|
+
<p>For private-cloud or self-hosted Langdock installations, set <code>LANGDOCK_BASE_URL</code> to override the default endpoint (<code>https://api.langdock.com/anthropic</code>). You can also set this in the config file as <code>langdockBaseUrl</code>.</p>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
287
307
|
<div class="doc-tabs__panel" id="tab-gemini-cli">
|
|
288
308
|
<p>The Gemini CLI runs as a local subprocess, similar to Claude Code.</p>
|
|
289
309
|
<ol class="doc-steps">
|
|
@@ -325,10 +345,13 @@ vibespot</code></pre>
|
|
|
325
345
|
<tr><th>Field</th><th>Type</th><th>Description</th></tr>
|
|
326
346
|
</thead>
|
|
327
347
|
<tbody>
|
|
328
|
-
<tr><td><code>aiEngine</code></td><td>string</td><td>Active AI engine: <code>"anthropic-api"</code>, <code>"claude-code"</code>, <code>"claude-oauth"</code>, <code>"openai-api"</code>, <code>"gemini-api"</code>, <code>"gemini-cli"</code>, <code>"codex-cli"</code></td></tr>
|
|
348
|
+
<tr><td><code>aiEngine</code></td><td>string</td><td>Active AI engine: <code>"anthropic-api"</code>, <code>"claude-code"</code>, <code>"claude-oauth"</code>, <code>"openai-api"</code>, <code>"gemini-api"</code>, <code>"langdock-api"</code>, <code>"gemini-cli"</code>, <code>"codex-cli"</code></td></tr>
|
|
329
349
|
<tr><td><code>anthropicApiKey</code></td><td>string</td><td>Anthropic API key (starts with <code>sk-ant-</code>)</td></tr>
|
|
330
350
|
<tr><td><code>openaiApiKey</code></td><td>string</td><td>OpenAI API key (starts with <code>sk-</code>)</td></tr>
|
|
331
351
|
<tr><td><code>geminiApiKey</code></td><td>string</td><td>Google AI / Gemini API key</td></tr>
|
|
352
|
+
<tr><td><code>langdockApiKey</code></td><td>string</td><td>Langdock API key for the EU gateway</td></tr>
|
|
353
|
+
<tr><td><code>langdockApiModel</code></td><td>string</td><td>Langdock model override (default: <code>claude-sonnet-4-20250514</code>)</td></tr>
|
|
354
|
+
<tr><td><code>langdockBaseUrl</code></td><td>string</td><td>Override Langdock endpoint for self-hosted/private-cloud deployments (default: <code>https://api.langdock.com/anthropic</code>)</td></tr>
|
|
332
355
|
<tr><td><code>claudeCodeModel</code></td><td>string</td><td>Model override for Claude Code CLI</td></tr>
|
|
333
356
|
<tr><td><code>anthropicApiModel</code></td><td>string</td><td>Anthropic API model (default: <code>claude-sonnet-4-20250514</code>)</td></tr>
|
|
334
357
|
<tr><td><code>openaiApiModel</code></td><td>string</td><td>OpenAI API model (default: <code>gpt-5.5</code>)</td></tr>
|
|
@@ -342,7 +365,7 @@ vibespot</code></pre>
|
|
|
342
365
|
</table>
|
|
343
366
|
|
|
344
367
|
<h3 id="env-vars">Environment Variables</h3>
|
|
345
|
-
<p>API keys can
|
|
368
|
+
<p>API keys and server settings can be set as environment variables. The config file takes precedence — environment variables are used as fallbacks when no key is set in the config. In Docker deployments, env vars are the primary configuration method (see <a href="#docker-deployment">Docker Deployment</a>).</p>
|
|
346
369
|
<table>
|
|
347
370
|
<thead>
|
|
348
371
|
<tr><th>Variable</th><th>Description</th></tr>
|
|
@@ -352,6 +375,14 @@ vibespot</code></pre>
|
|
|
352
375
|
<tr><td><code>OPENAI_API_KEY</code></td><td>OpenAI API key for GPT models</td></tr>
|
|
353
376
|
<tr><td><code>GEMINI_API_KEY</code></td><td>Google AI API key for Gemini models</td></tr>
|
|
354
377
|
<tr><td><code>GOOGLE_AI_API_KEY</code></td><td>Alternative name for the Gemini API key (same effect as <code>GEMINI_API_KEY</code>)</td></tr>
|
|
378
|
+
<tr><td><code>LANGDOCK_API_KEY</code></td><td>Langdock EU gateway key</td></tr>
|
|
379
|
+
<tr><td><code>LANGDOCK_BASE_URL</code></td><td>Override Langdock endpoint for self-hosted deployments</td></tr>
|
|
380
|
+
<tr><td><code>HUBSPOT_PERSONAL_ACCESS_KEY</code></td><td>HubSpot PAK — enables theme upload without configuring through the UI</td></tr>
|
|
381
|
+
<tr><td><code>FIGMA_TOKEN</code></td><td>Figma personal access token for design import</td></tr>
|
|
382
|
+
<tr><td><code>VIBESPOT_AI_ENGINE</code></td><td>Default engine: <code>anthropic-api</code>, <code>openai-api</code>, <code>gemini-api</code>, <code>langdock-api</code></td></tr>
|
|
383
|
+
<tr><td><code>VIBESPOT_AGENTIC_MODE</code></td><td>Set <code>true</code> to enable the multi-stage agentic pipeline</td></tr>
|
|
384
|
+
<tr><td><code>VIBESPOT_PORT</code></td><td>Override the HTTP server port (default: <code>4200</code>)</td></tr>
|
|
385
|
+
<tr><td><code>VIBESPOT_NO_OPEN</code></td><td>Set <code>1</code> to suppress auto-opening the browser on startup</td></tr>
|
|
355
386
|
</tbody>
|
|
356
387
|
</table>
|
|
357
388
|
</div>
|
|
@@ -1264,6 +1295,115 @@ testimonial carousel, and a minimal footer with social links.</code></pre>
|
|
|
1264
1295
|
</div>
|
|
1265
1296
|
</div>
|
|
1266
1297
|
|
|
1298
|
+
<!-- ============================================================
|
|
1299
|
+
Section: Docker Deployment
|
|
1300
|
+
============================================================ -->
|
|
1301
|
+
<div class="doc-section" id="docker-deployment">
|
|
1302
|
+
<h2 id="docker-deployment-heading">Docker Deployment <a href="#docker-deployment" class="doc-anchor">#</a></h2>
|
|
1303
|
+
<p>Run vibeSpot as a containerised service for your team. The Docker image bundles the server, UI, and all dependencies — just add an AI API key. The image is published to the GitHub Container Registry and is <strong>public</strong>, so no login or repository checkout is required to pull it.</p>
|
|
1304
|
+
|
|
1305
|
+
<pre><code>docker pull ghcr.io/borismichel/vibespot:latest</code></pre>
|
|
1306
|
+
<p>Tags: <code>latest</code> (most recent release), <code>1.5.0</code> / <code>1.5</code> (specific version), <code>main</code> (latest commit, may be unstable). Pin a version for production.</p>
|
|
1307
|
+
|
|
1308
|
+
<h3 id="docker-quick-start">Quick Start (LAN / VPN) <a href="#docker-quick-start" class="doc-anchor">#</a></h3>
|
|
1309
|
+
<p>Run the public image directly — no repository or compose file needed:</p>
|
|
1310
|
+
<pre><code>docker run -d --name vibespot \
|
|
1311
|
+
-p 4200:4200 \
|
|
1312
|
+
-e VIBESPOT_AI_ENGINE=anthropic-api \
|
|
1313
|
+
-e VIBESPOT_AGENTIC_MODE=true \
|
|
1314
|
+
-e ANTHROPIC_API_KEY=sk-ant-... \
|
|
1315
|
+
-v vibespot-config:/home/vibespot/.vibespot \
|
|
1316
|
+
-v vibespot-themes:/home/vibespot/vibespot-themes \
|
|
1317
|
+
ghcr.io/borismichel/vibespot:latest</code></pre>
|
|
1318
|
+
<p>Open <code>http://<host-ip>:4200</code> in a browser. Swap the engine and key for whichever provider you use. The two volumes keep config and generated themes across restarts.</p>
|
|
1319
|
+
|
|
1320
|
+
<h3 id="docker-https">HTTPS with Caddy <a href="#docker-https" class="doc-anchor">#</a></h3>
|
|
1321
|
+
<p>For public or semi-public deployments, put a <a href="https://caddyserver.com/" target="_blank">Caddy</a> reverse proxy in front to auto-provision a Let’s Encrypt TLS certificate. Save a <code>docker-compose.yml</code> and <code>Caddyfile</code> in a directory, then run <code>docker compose up -d</code>.</p>
|
|
1322
|
+
<pre><code># docker-compose.yml
|
|
1323
|
+
services:
|
|
1324
|
+
vibespot:
|
|
1325
|
+
image: ghcr.io/borismichel/vibespot:latest
|
|
1326
|
+
restart: unless-stopped
|
|
1327
|
+
environment:
|
|
1328
|
+
VIBESPOT_AI_ENGINE: anthropic-api
|
|
1329
|
+
VIBESPOT_AGENTIC_MODE: "true"
|
|
1330
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
1331
|
+
volumes:
|
|
1332
|
+
- vibespot-config:/home/vibespot/.vibespot
|
|
1333
|
+
- vibespot-themes:/home/vibespot/vibespot-themes
|
|
1334
|
+
expose: ["4200"]
|
|
1335
|
+
caddy:
|
|
1336
|
+
image: caddy:2-alpine
|
|
1337
|
+
restart: unless-stopped
|
|
1338
|
+
ports: ["80:80", "443:443"]
|
|
1339
|
+
volumes:
|
|
1340
|
+
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
1341
|
+
- caddy-data:/data
|
|
1342
|
+
depends_on: [vibespot]
|
|
1343
|
+
volumes:
|
|
1344
|
+
vibespot-config:
|
|
1345
|
+
vibespot-themes:
|
|
1346
|
+
caddy-data:</code></pre>
|
|
1347
|
+
<pre><code># Caddyfile (set your real domain)
|
|
1348
|
+
vibespot.example.com {
|
|
1349
|
+
@websockets {
|
|
1350
|
+
header Connection *Upgrade*
|
|
1351
|
+
header Upgrade websocket
|
|
1352
|
+
}
|
|
1353
|
+
reverse_proxy @websockets vibespot:4200
|
|
1354
|
+
reverse_proxy vibespot:4200
|
|
1355
|
+
}</code></pre>
|
|
1356
|
+
<p>Caddy binds ports 80 and 443. Point your DNS A record at the host, and HTTPS works automatically. The <code>@websockets</code> rule is required — the chat and generation pipeline run over a persistent WebSocket.</p>
|
|
1357
|
+
|
|
1358
|
+
<h3 id="docker-env-vars">Environment Variables <a href="#docker-env-vars" class="doc-anchor">#</a></h3>
|
|
1359
|
+
<p>The Docker image reads all configuration from environment variables. The <code>.env.example</code> file documents every option.</p>
|
|
1360
|
+
|
|
1361
|
+
<table>
|
|
1362
|
+
<thead>
|
|
1363
|
+
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
|
|
1364
|
+
</thead>
|
|
1365
|
+
<tbody>
|
|
1366
|
+
<tr><td><code>VIBESPOT_PORT</code></td><td><code>4200</code></td><td>Port the server listens on inside the container</td></tr>
|
|
1367
|
+
<tr><td><code>VIBESPOT_NO_OPEN</code></td><td><code>1</code></td><td>Suppress auto-open browser (set automatically in Docker)</td></tr>
|
|
1368
|
+
<tr><td><code>VIBESPOT_AI_ENGINE</code></td><td>—</td><td>Default engine: <code>anthropic-api</code>, <code>openai-api</code>, <code>gemini-api</code>, <code>langdock-api</code></td></tr>
|
|
1369
|
+
<tr><td><code>VIBESPOT_AGENTIC_MODE</code></td><td>—</td><td>Set <code>true</code> to enable the multi-stage agentic pipeline</td></tr>
|
|
1370
|
+
<tr><td><code>ANTHROPIC_API_KEY</code></td><td>—</td><td>Anthropic Claude API key</td></tr>
|
|
1371
|
+
<tr><td><code>OPENAI_API_KEY</code></td><td>—</td><td>OpenAI API key</td></tr>
|
|
1372
|
+
<tr><td><code>GEMINI_API_KEY</code></td><td>—</td><td>Google Gemini API key</td></tr>
|
|
1373
|
+
<tr><td><code>LANGDOCK_API_KEY</code></td><td>—</td><td>Langdock EU gateway key</td></tr>
|
|
1374
|
+
<tr><td><code>HUBSPOT_PERSONAL_ACCESS_KEY</code></td><td>—</td><td>HubSpot PAK for theme uploads</td></tr>
|
|
1375
|
+
<tr><td><code>FIGMA_TOKEN</code></td><td>—</td><td>Figma personal access token for design import</td></tr>
|
|
1376
|
+
</tbody>
|
|
1377
|
+
</table>
|
|
1378
|
+
|
|
1379
|
+
<h3 id="docker-persistence">Persistence <a href="#docker-persistence" class="doc-anchor">#</a></h3>
|
|
1380
|
+
<p>Two named Docker volumes keep data across container restarts:</p>
|
|
1381
|
+
<table>
|
|
1382
|
+
<thead>
|
|
1383
|
+
<tr><th>Volume</th><th>Container path</th><th>Contents</th></tr>
|
|
1384
|
+
</thead>
|
|
1385
|
+
<tbody>
|
|
1386
|
+
<tr><td><code>vibespot-config</code></td><td><code>/home/vibespot/.vibespot</code></td><td>config.json, session data</td></tr>
|
|
1387
|
+
<tr><td><code>vibespot-themes</code></td><td><code>/home/vibespot/vibespot-themes</code></td><td>Generated HubSpot themes</td></tr>
|
|
1388
|
+
</tbody>
|
|
1389
|
+
</table>
|
|
1390
|
+
<p>Mount the themes volume at exactly <code>/home/vibespot/vibespot-themes</code> — that is where the app writes generated themes. Without it, themes are lost when the container is recreated. To back up:</p>
|
|
1391
|
+
<pre><code>docker cp vibespot:/home/vibespot/.vibespot ./backup-config
|
|
1392
|
+
docker cp vibespot:/home/vibespot/vibespot-themes ./backup-themes</code></pre>
|
|
1393
|
+
|
|
1394
|
+
<h3 id="docker-reverse-proxy">Reverse Proxy & Kubernetes <a href="#docker-reverse-proxy" class="doc-anchor">#</a></h3>
|
|
1395
|
+
<p>If you already have a reverse proxy (nginx, Traefik, k8s Ingress), skip the Caddy profile and point your proxy at port 4200. Key requirements:</p>
|
|
1396
|
+
<ul>
|
|
1397
|
+
<li><strong>WebSocket upgrade</strong> — the chat, pipeline progress, and upload UI all use a persistent WebSocket connection.</li>
|
|
1398
|
+
<li><strong>Timeout > 120s</strong> — agentic AI generation can run for several minutes. Set read/send timeouts to at least 300s.</li>
|
|
1399
|
+
<li><strong>No buffering</strong> — for streaming AI responses, disable proxy buffering.</li>
|
|
1400
|
+
</ul>
|
|
1401
|
+
<div class="doc-callout doc-callout--tip">
|
|
1402
|
+
<div class="doc-callout__label">⚠️ Single instance & auth</div>
|
|
1403
|
+
<p>vibeSpot keeps active sessions in memory — run a single instance (no horizontal scaling without sticky sessions). It runs as a non-root user and has <strong>no built-in authentication</strong>. For internet-facing deployments, put an authenticating proxy (OAuth2 Proxy, Authelia, Cloudflare Access) in front. Persistence is filesystem-only on the named volumes — there is no database to run.</p>
|
|
1404
|
+
</div>
|
|
1405
|
+
</div>
|
|
1406
|
+
|
|
1267
1407
|
<!-- ============================================================
|
|
1268
1408
|
Section: HubSpot Marketplace publication path
|
|
1269
1409
|
============================================================ -->
|
|
Binary file
|
|
Binary file
|
package/ui/index.html
CHANGED
|
@@ -909,28 +909,8 @@
|
|
|
909
909
|
</div>
|
|
910
910
|
</section>
|
|
911
911
|
|
|
912
|
-
<!-- ================ SETTINGS
|
|
912
|
+
<!-- ================ SETTINGS (now uses global overlay) ================ -->
|
|
913
913
|
<section class="workspace-panel workspace-panel--settings" id="ws-panel-settings" data-ws-panel="settings" role="tabpanel" aria-labelledby="ws-tab-settings">
|
|
914
|
-
<div class="dashboard__container">
|
|
915
|
-
|
|
916
|
-
<header class="settings__header">
|
|
917
|
-
<h2 class="settings__title">Settings</h2>
|
|
918
|
-
</header>
|
|
919
|
-
<nav class="settings__tabs" id="settings-tabs" role="tablist" aria-label="Settings categories">
|
|
920
|
-
<button class="settings__tab active" data-tab="ai" type="button" role="tab" aria-selected="true">AI</button>
|
|
921
|
-
<button class="settings__tab" data-tab="hubspot" type="button" role="tab" aria-selected="false">HubSpot</button>
|
|
922
|
-
<button class="settings__tab" data-tab="figma" type="button" role="tab" aria-selected="false">Figma</button>
|
|
923
|
-
<button class="settings__tab" data-tab="github" type="button" role="tab" aria-selected="false">GitHub</button>
|
|
924
|
-
<button class="settings__tab" data-tab="vibespot" type="button" role="tab" aria-selected="false">vibeSpot</button>
|
|
925
|
-
</nav>
|
|
926
|
-
<div class="settings__body" id="settings-body" role="tabpanel">
|
|
927
|
-
<div class="settings__loading">
|
|
928
|
-
<div class="settings__spinner-lg" aria-hidden="true"></div>
|
|
929
|
-
<span>Loading environment...</span>
|
|
930
|
-
</div>
|
|
931
|
-
</div>
|
|
932
|
-
|
|
933
|
-
</div>
|
|
934
914
|
</section>
|
|
935
915
|
|
|
936
916
|
</div><!-- /.dashboard__body -->
|
|
@@ -981,6 +961,31 @@
|
|
|
981
961
|
|
|
982
962
|
</div><!-- /.app-body -->
|
|
983
963
|
|
|
964
|
+
<!-- ============================================================ -->
|
|
965
|
+
<!-- SETTINGS OVERLAY — global modal, works from any screen -->
|
|
966
|
+
<!-- ============================================================ -->
|
|
967
|
+
<div class="settings-overlay hidden" id="settings-overlay">
|
|
968
|
+
<div class="settings-panel">
|
|
969
|
+
<header class="settings__header">
|
|
970
|
+
<h2 class="settings__title">Settings</h2>
|
|
971
|
+
<button class="settings__close" id="settings-close" type="button" aria-label="Close settings">×</button>
|
|
972
|
+
</header>
|
|
973
|
+
<nav class="settings__tabs" id="settings-tabs" role="tablist" aria-label="Settings categories">
|
|
974
|
+
<button class="settings__tab active" data-tab="ai" type="button" role="tab" aria-selected="true">AI</button>
|
|
975
|
+
<button class="settings__tab" data-tab="hubspot" type="button" role="tab" aria-selected="false">HubSpot</button>
|
|
976
|
+
<button class="settings__tab" data-tab="figma" type="button" role="tab" aria-selected="false">Figma</button>
|
|
977
|
+
<button class="settings__tab" data-tab="github" type="button" role="tab" aria-selected="false">GitHub</button>
|
|
978
|
+
<button class="settings__tab" data-tab="vibespot" type="button" role="tab" aria-selected="false">vibeSpot</button>
|
|
979
|
+
</nav>
|
|
980
|
+
<div class="settings__body" id="settings-body" role="tabpanel">
|
|
981
|
+
<div class="settings__loading">
|
|
982
|
+
<div class="settings__spinner-lg" aria-hidden="true"></div>
|
|
983
|
+
<span>Loading environment...</span>
|
|
984
|
+
</div>
|
|
985
|
+
</div>
|
|
986
|
+
</div>
|
|
987
|
+
</div>
|
|
988
|
+
|
|
984
989
|
<script src="/vendor/marked.umd.js"></script>
|
|
985
990
|
<script src="/vendor/codemirror-bundle.global.js"></script>
|
|
986
991
|
<script src="/icons.js"></script>
|
package/ui/settings.js
CHANGED
|
@@ -18,14 +18,13 @@ const ENGINE_LABELS = {
|
|
|
18
18
|
"gemini-cli": "Gemini CLI",
|
|
19
19
|
"gemini-api": "Gemini API",
|
|
20
20
|
"codex-cli": "OpenAI Codex",
|
|
21
|
+
"langdock-api": "Langdock",
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
24
25
|
// Open / Close
|
|
25
26
|
// ---------------------------------------------------------------------------
|
|
26
27
|
|
|
27
|
-
let _prevWorkspaceTab = "pages";
|
|
28
|
-
|
|
29
28
|
function openSettings(tab) {
|
|
30
29
|
if (typeof closeMenu === "function") closeMenu();
|
|
31
30
|
if (tab) {
|
|
@@ -34,23 +33,13 @@ function openSettings(tab) {
|
|
|
34
33
|
tabs.forEach((t) => t.classList.toggle("active", t.dataset.tab === tab));
|
|
35
34
|
}
|
|
36
35
|
const overlay = document.getElementById("settings-overlay");
|
|
37
|
-
if (overlay)
|
|
38
|
-
overlay.classList.remove("hidden");
|
|
39
|
-
} else if (typeof switchWorkspaceTab === "function") {
|
|
40
|
-
const activeWs = document.querySelector(".workspace-tab.active");
|
|
41
|
-
if (activeWs && activeWs.dataset.wsTab !== "settings") _prevWorkspaceTab = activeWs.dataset.wsTab;
|
|
42
|
-
switchWorkspaceTab("settings");
|
|
43
|
-
}
|
|
36
|
+
if (overlay) overlay.classList.remove("hidden");
|
|
44
37
|
refreshSettings();
|
|
45
38
|
}
|
|
46
39
|
|
|
47
40
|
function closeSettings() {
|
|
48
41
|
const overlay = document.getElementById("settings-overlay");
|
|
49
|
-
if (overlay)
|
|
50
|
-
overlay.classList.add("hidden");
|
|
51
|
-
} else if (typeof switchWorkspaceTab === "function") {
|
|
52
|
-
switchWorkspaceTab(_prevWorkspaceTab || "pages");
|
|
53
|
-
}
|
|
42
|
+
if (overlay) overlay.classList.add("hidden");
|
|
54
43
|
Object.keys(activePolls).forEach((id) => {
|
|
55
44
|
clearInterval(activePolls[id]);
|
|
56
45
|
delete activePolls[id];
|
|
@@ -153,6 +142,7 @@ function renderAITab(body, data) {
|
|
|
153
142
|
{ id: "gemini-cli", label: "Gemini CLI" },
|
|
154
143
|
{ id: "gemini-api", label: "Gemini API" },
|
|
155
144
|
{ id: "codex-cli", label: "Codex CLI" },
|
|
145
|
+
{ id: "langdock-api", label: "Langdock" },
|
|
156
146
|
];
|
|
157
147
|
|
|
158
148
|
for (const eng of allEngines) {
|
|
@@ -166,8 +156,43 @@ function renderAITab(body, data) {
|
|
|
166
156
|
}
|
|
167
157
|
section.appendChild(selectEl);
|
|
168
158
|
|
|
169
|
-
//
|
|
159
|
+
// Langdock provider selector — shown only when Langdock is the active engine
|
|
170
160
|
const activeEngine = config.aiEngine || (env.availableEngines.length > 0 ? env.availableEngines[0] : null);
|
|
161
|
+
const langdockProvider = config.langdockProvider || "anthropic";
|
|
162
|
+
|
|
163
|
+
if (activeEngine === "langdock-api") {
|
|
164
|
+
const providerRow = el("div", "settings__model-row");
|
|
165
|
+
const providerLabel = el("span", "settings__card-label");
|
|
166
|
+
providerLabel.textContent = "Provider";
|
|
167
|
+
providerRow.appendChild(providerLabel);
|
|
168
|
+
|
|
169
|
+
const providerSelect = el("select", "settings__model-select");
|
|
170
|
+
const providers = [
|
|
171
|
+
{ id: "anthropic", label: "Anthropic (Claude)" },
|
|
172
|
+
{ id: "openai", label: "OpenAI (GPT)" },
|
|
173
|
+
{ id: "google", label: "Google (Gemini)" },
|
|
174
|
+
{ id: "mistral", label: "Mistral" },
|
|
175
|
+
];
|
|
176
|
+
for (const p of providers) {
|
|
177
|
+
const opt = document.createElement("option");
|
|
178
|
+
opt.value = p.id;
|
|
179
|
+
opt.textContent = p.label;
|
|
180
|
+
if (p.id === langdockProvider) opt.selected = true;
|
|
181
|
+
providerSelect.appendChild(opt);
|
|
182
|
+
}
|
|
183
|
+
providerSelect.addEventListener("change", async () => {
|
|
184
|
+
await fetch("/api/settings", {
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers: { "Content-Type": "application/json" },
|
|
187
|
+
body: JSON.stringify({ langdockProvider: providerSelect.value }),
|
|
188
|
+
});
|
|
189
|
+
refreshSettings();
|
|
190
|
+
});
|
|
191
|
+
providerRow.appendChild(providerSelect);
|
|
192
|
+
section.appendChild(providerRow);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Model selector
|
|
171
196
|
if (activeEngine) {
|
|
172
197
|
const modelRow = el("div", "settings__model-row");
|
|
173
198
|
const modelLabel = el("span", "settings__card-label");
|
|
@@ -271,6 +296,7 @@ function renderAITab(body, data) {
|
|
|
271
296
|
{ key: "anthropic", name: "Anthropic", placeholder: "sk-ant-api03-..." },
|
|
272
297
|
{ key: "openai", name: "OpenAI", placeholder: "sk-..." },
|
|
273
298
|
{ key: "gemini", name: "Google AI", placeholder: "AIza..." },
|
|
299
|
+
{ key: "langdock", name: "Langdock", placeholder: "ld-..." },
|
|
274
300
|
];
|
|
275
301
|
|
|
276
302
|
for (const prov of providers) {
|
|
@@ -442,7 +468,10 @@ function renderAICapabilitiesSection(activeEngine, config) {
|
|
|
442
468
|
section.appendChild(desc("Advanced model features. Some are configurable directly; some auto-engage based on the active engine."));
|
|
443
469
|
|
|
444
470
|
// Engine classification — different engines have different feature surfaces.
|
|
445
|
-
|
|
471
|
+
// Langdock inherits capabilities from the selected upstream provider.
|
|
472
|
+
const ldProv = (config.langdockProvider || "anthropic");
|
|
473
|
+
const isLangdockAnthropic = activeEngine === "langdock-api" && ldProv === "anthropic";
|
|
474
|
+
const isAnthropicAPI = activeEngine === "anthropic-api" || activeEngine === "claude-oauth" || isLangdockAnthropic;
|
|
446
475
|
const isClaudeCode = activeEngine === "claude-code";
|
|
447
476
|
const isAnthropicAny = isAnthropicAPI || isClaudeCode;
|
|
448
477
|
|
|
@@ -1482,6 +1511,38 @@ function getModelsForEngine(engine) {
|
|
|
1482
1511
|
{ id: "gpt-5.4-nano", label: "GPT-5.4 Nano" },
|
|
1483
1512
|
{ id: "codex-mini-latest", label: "Codex Mini (latest)" },
|
|
1484
1513
|
];
|
|
1514
|
+
case "langdock-api": {
|
|
1515
|
+
const ldProvider = (settingsData && settingsData.config && settingsData.config.langdockProvider) || "anthropic";
|
|
1516
|
+
const ldModels = {
|
|
1517
|
+
anthropic: [
|
|
1518
|
+
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6 (default)" },
|
|
1519
|
+
{ id: "claude-opus-4-7", label: "Claude Opus 4.7" },
|
|
1520
|
+
{ id: "claude-opus-4-6", label: "Claude Opus 4.6" },
|
|
1521
|
+
{ id: "claude-sonnet-4-5", label: "Claude Sonnet 4.5" },
|
|
1522
|
+
{ id: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
|
|
1523
|
+
],
|
|
1524
|
+
openai: [
|
|
1525
|
+
{ id: "gpt-4.1", label: "GPT-4.1 (default)" },
|
|
1526
|
+
{ id: "gpt-4.1-mini", label: "GPT-4.1 Mini" },
|
|
1527
|
+
{ id: "gpt-4.1-nano", label: "GPT-4.1 Nano" },
|
|
1528
|
+
{ id: "gpt-4o", label: "GPT-4o" },
|
|
1529
|
+
{ id: "o3-mini", label: "o3 Mini" },
|
|
1530
|
+
],
|
|
1531
|
+
google: [
|
|
1532
|
+
{ id: "gemini-2.5-pro", label: "Gemini 2.5 Pro (default)" },
|
|
1533
|
+
{ id: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
|
|
1534
|
+
{ id: "gemini-2.0-flash", label: "Gemini 2.0 Flash" },
|
|
1535
|
+
],
|
|
1536
|
+
mistral: [
|
|
1537
|
+
{ id: "mistral-large-latest", label: "Mistral Large (default)" },
|
|
1538
|
+
{ id: "mistral-medium-latest", label: "Mistral Medium" },
|
|
1539
|
+
{ id: "mistral-small-latest", label: "Mistral Small" },
|
|
1540
|
+
{ id: "codestral-latest", label: "Codestral" },
|
|
1541
|
+
{ id: "pixtral-large-latest", label: "Pixtral Large" },
|
|
1542
|
+
],
|
|
1543
|
+
};
|
|
1544
|
+
return ldModels[ldProvider] || ldModels.anthropic;
|
|
1545
|
+
}
|
|
1485
1546
|
default:
|
|
1486
1547
|
return [];
|
|
1487
1548
|
}
|
|
@@ -1496,6 +1557,11 @@ function getCurrentModel(engine, config) {
|
|
|
1496
1557
|
case "codex-cli": return config.codexCliModel || "gpt-5.5";
|
|
1497
1558
|
case "gemini-cli": return config.geminiCliModel || "gemini-2.5-pro";
|
|
1498
1559
|
case "gemini-api": return config.geminiApiModel || "gemini-2.5-pro";
|
|
1560
|
+
case "langdock-api": {
|
|
1561
|
+
if (config.langdockApiModel) return config.langdockApiModel;
|
|
1562
|
+
const defaults = { anthropic: "claude-sonnet-4-6", openai: "gpt-4.1", google: "gemini-2.5-pro", mistral: "mistral-large-latest" };
|
|
1563
|
+
return defaults[config.langdockProvider || "anthropic"] || "claude-sonnet-4-6";
|
|
1564
|
+
}
|
|
1499
1565
|
default: return null;
|
|
1500
1566
|
}
|
|
1501
1567
|
}
|
|
@@ -1558,9 +1624,15 @@ function escSettings(str) {
|
|
|
1558
1624
|
|
|
1559
1625
|
document.getElementById("btn-setup-settings")?.addEventListener("click", () => openSettings());
|
|
1560
1626
|
|
|
1627
|
+
document.getElementById("settings-close")?.addEventListener("click", () => closeSettings());
|
|
1628
|
+
|
|
1629
|
+
document.getElementById("settings-overlay")?.addEventListener("click", (e) => {
|
|
1630
|
+
if (e.target.id === "settings-overlay") closeSettings();
|
|
1631
|
+
});
|
|
1632
|
+
|
|
1561
1633
|
document.addEventListener("keydown", (e) => {
|
|
1562
|
-
const
|
|
1563
|
-
if (e.key === "Escape" &&
|
|
1634
|
+
const overlay = document.getElementById("settings-overlay");
|
|
1635
|
+
if (e.key === "Escape" && overlay && !overlay.classList.contains("hidden")) {
|
|
1564
1636
|
closeSettings();
|
|
1565
1637
|
}
|
|
1566
1638
|
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|