vibespot 0.6.0 → 0.7.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/dist/index.js +242 -6230
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/chat.js +192 -21
- package/ui/dashboard.js +190 -6
- package/ui/dialog.js +2 -3
- package/ui/favicon.ico +0 -0
- package/ui/field-editor.js +1 -0
- package/ui/index.html +16 -9
- package/ui/settings.js +10 -7
- package/ui/setup.js +101 -11
- package/ui/styles.css +111 -24
- package/ui/upload-panel.js +16 -4
package/ui/settings.js
CHANGED
|
@@ -810,6 +810,11 @@ async function authCLI(cli, btn, apiKey) {
|
|
|
810
810
|
// ---------------------------------------------------------------------------
|
|
811
811
|
|
|
812
812
|
function getModelsForEngine(engine) {
|
|
813
|
+
// Use server-provided model catalog if available
|
|
814
|
+
if (settingsData && settingsData.models && settingsData.models[engine]) {
|
|
815
|
+
return settingsData.models[engine];
|
|
816
|
+
}
|
|
817
|
+
// Fallback to hardcoded defaults
|
|
813
818
|
switch (engine) {
|
|
814
819
|
case "claude-code":
|
|
815
820
|
return [
|
|
@@ -819,10 +824,9 @@ function getModelsForEngine(engine) {
|
|
|
819
824
|
];
|
|
820
825
|
case "anthropic-api":
|
|
821
826
|
return [
|
|
822
|
-
{ id: "claude-sonnet-4-
|
|
823
|
-
{ id: "claude-opus-4-
|
|
827
|
+
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6" },
|
|
828
|
+
{ id: "claude-opus-4-6", label: "Claude Opus 4.6" },
|
|
824
829
|
{ id: "claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
|
|
825
|
-
{ id: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5" },
|
|
826
830
|
];
|
|
827
831
|
case "openai-api":
|
|
828
832
|
return [
|
|
@@ -834,9 +838,9 @@ function getModelsForEngine(engine) {
|
|
|
834
838
|
case "gemini-cli":
|
|
835
839
|
case "gemini-api":
|
|
836
840
|
return [
|
|
837
|
-
{ id: "gemini-2.
|
|
841
|
+
{ id: "gemini-2.5-flash", label: "Gemini 2.5 Flash (default)" },
|
|
838
842
|
{ id: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
|
|
839
|
-
{ id: "gemini-2.
|
|
843
|
+
{ id: "gemini-2.0-flash", label: "Gemini 2.0 Flash" },
|
|
840
844
|
];
|
|
841
845
|
case "codex-cli":
|
|
842
846
|
return [
|
|
@@ -852,7 +856,7 @@ function getModelsForEngine(engine) {
|
|
|
852
856
|
function getCurrentModel(engine, config) {
|
|
853
857
|
switch (engine) {
|
|
854
858
|
case "claude-code": return config.claudeCodeModel || "sonnet";
|
|
855
|
-
case "anthropic-api": return config.anthropicApiModel || "claude-sonnet-4-
|
|
859
|
+
case "anthropic-api": return config.anthropicApiModel || "claude-sonnet-4-6";
|
|
856
860
|
case "openai-api": return config.openaiApiModel || "gpt-4o";
|
|
857
861
|
default: return null;
|
|
858
862
|
}
|
|
@@ -910,7 +914,6 @@ function escSettings(str) {
|
|
|
910
914
|
// Event listeners
|
|
911
915
|
// ---------------------------------------------------------------------------
|
|
912
916
|
|
|
913
|
-
document.getElementById("btn-settings").addEventListener("click", openSettings);
|
|
914
917
|
document.getElementById("settings-close").addEventListener("click", closeSettings);
|
|
915
918
|
document.getElementById("settings-overlay").addEventListener("click", (e) => {
|
|
916
919
|
if (e.target.id === "settings-overlay") closeSettings();
|
package/ui/setup.js
CHANGED
|
@@ -225,6 +225,15 @@ function populateProjectRail(info) {
|
|
|
225
225
|
<span class="project-rail__item-meta">${meta}</span>`;
|
|
226
226
|
item.appendChild(infoEl);
|
|
227
227
|
|
|
228
|
+
// Double-click on name to rename
|
|
229
|
+
const nameSpan = infoEl.querySelector(".project-rail__item-name");
|
|
230
|
+
if (nameSpan) {
|
|
231
|
+
nameSpan.addEventListener("dblclick", (e) => {
|
|
232
|
+
e.stopPropagation();
|
|
233
|
+
startInlineRename(nameSpan, p);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
228
237
|
// Delete button (visible when expanded + hover)
|
|
229
238
|
const delBtn = document.createElement("button");
|
|
230
239
|
delBtn.className = "project-rail__item-delete";
|
|
@@ -263,8 +272,12 @@ function populateProjectRail(info) {
|
|
|
263
272
|
railTooltip.classList.remove("project-rail__tooltip--visible");
|
|
264
273
|
});
|
|
265
274
|
|
|
266
|
-
// Click to open
|
|
275
|
+
// Click to open (blocked while AI is generating)
|
|
267
276
|
item.addEventListener("click", () => {
|
|
277
|
+
if (typeof isStreaming !== "undefined" && isStreaming) {
|
|
278
|
+
showError("Cannot switch projects while AI is generating.");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
268
281
|
if (p.sessionId) resumeSession(p.sessionId);
|
|
269
282
|
else openTheme(p.name);
|
|
270
283
|
});
|
|
@@ -287,6 +300,84 @@ document.getElementById("project-rail-add")?.addEventListener("click", () => {
|
|
|
287
300
|
showSetup();
|
|
288
301
|
});
|
|
289
302
|
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
// Inline rename
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
|
|
307
|
+
function startInlineRename(nameSpan, project) {
|
|
308
|
+
if (nameSpan.contentEditable === "true") return; // already editing
|
|
309
|
+
|
|
310
|
+
const oldName = project.name;
|
|
311
|
+
nameSpan.contentEditable = "true";
|
|
312
|
+
nameSpan.classList.add("project-rail__item-name--editing");
|
|
313
|
+
nameSpan.focus();
|
|
314
|
+
|
|
315
|
+
// Select all text
|
|
316
|
+
const range = document.createRange();
|
|
317
|
+
range.selectNodeContents(nameSpan);
|
|
318
|
+
const sel = window.getSelection();
|
|
319
|
+
sel.removeAllRanges();
|
|
320
|
+
sel.addRange(range);
|
|
321
|
+
|
|
322
|
+
function commit() {
|
|
323
|
+
nameSpan.contentEditable = "false";
|
|
324
|
+
nameSpan.classList.remove("project-rail__item-name--editing");
|
|
325
|
+
|
|
326
|
+
const newName = nameSpan.textContent.trim();
|
|
327
|
+
if (!newName || newName === oldName) {
|
|
328
|
+
nameSpan.textContent = oldName;
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
fetch("/api/themes/rename", {
|
|
333
|
+
method: "POST",
|
|
334
|
+
headers: { "Content-Type": "application/json" },
|
|
335
|
+
body: JSON.stringify({ sessionId: project.sessionId, newName }),
|
|
336
|
+
})
|
|
337
|
+
.then((r) => r.json())
|
|
338
|
+
.then((data) => {
|
|
339
|
+
if (data.ok) {
|
|
340
|
+
// Update the in-memory project name + UI
|
|
341
|
+
project.name = data.newName;
|
|
342
|
+
nameSpan.textContent = data.newName;
|
|
343
|
+
const item = nameSpan.closest(".project-rail__item");
|
|
344
|
+
if (item) {
|
|
345
|
+
item.dataset.name = data.newName;
|
|
346
|
+
const bubble = item.querySelector(".project-rail__item-bubble");
|
|
347
|
+
if (bubble) bubble.textContent = data.newName.charAt(0).toUpperCase();
|
|
348
|
+
}
|
|
349
|
+
// Update topbar if this is the active project
|
|
350
|
+
if (currentAppTheme === oldName) {
|
|
351
|
+
currentAppTheme = data.newName;
|
|
352
|
+
const themeNameEl = document.getElementById("theme-name");
|
|
353
|
+
if (themeNameEl) themeNameEl.textContent = data.newName;
|
|
354
|
+
window.location.hash = "#/app/" + encodeURIComponent(data.newName);
|
|
355
|
+
}
|
|
356
|
+
updateRailActive();
|
|
357
|
+
} else {
|
|
358
|
+
nameSpan.textContent = oldName;
|
|
359
|
+
showError(data.error || "Rename failed");
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
.catch(() => {
|
|
363
|
+
nameSpan.textContent = oldName;
|
|
364
|
+
showError("Rename failed");
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
nameSpan.addEventListener("blur", commit, { once: true });
|
|
369
|
+
nameSpan.addEventListener("keydown", (e) => {
|
|
370
|
+
if (e.key === "Enter") {
|
|
371
|
+
e.preventDefault();
|
|
372
|
+
nameSpan.blur();
|
|
373
|
+
}
|
|
374
|
+
if (e.key === "Escape") {
|
|
375
|
+
nameSpan.textContent = oldName;
|
|
376
|
+
nameSpan.blur();
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
290
381
|
// ---------------------------------------------------------------------------
|
|
291
382
|
// Delete project confirmation
|
|
292
383
|
// ---------------------------------------------------------------------------
|
|
@@ -714,20 +805,19 @@ function showSetup() {
|
|
|
714
805
|
initSetup();
|
|
715
806
|
}
|
|
716
807
|
|
|
717
|
-
//
|
|
808
|
+
// App back button → go back to dashboard from chat
|
|
809
|
+
document.getElementById("app-back")?.addEventListener("click", () => {
|
|
810
|
+
if (currentAppTheme && typeof showDashboard === "function") {
|
|
811
|
+
appScreen.classList.add("hidden");
|
|
812
|
+
showDashboard(currentAppTheme);
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// Logo click → go back to setup (from dashboard)
|
|
718
817
|
document.querySelectorAll(".topbar__brand").forEach((el) => {
|
|
719
818
|
el.style.cursor = "pointer";
|
|
720
819
|
el.addEventListener("click", () => {
|
|
721
820
|
const dashEl = document.getElementById("dashboard-screen");
|
|
722
|
-
// From chat → go to dashboard
|
|
723
|
-
if (!appScreen.classList.contains("hidden") && currentAppTheme) {
|
|
724
|
-
if (typeof showDashboard === "function") {
|
|
725
|
-
appScreen.classList.add("hidden");
|
|
726
|
-
showDashboard(currentAppTheme);
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
// From dashboard → go to setup
|
|
731
821
|
if (dashEl && !dashEl.classList.contains("hidden")) {
|
|
732
822
|
showSetup();
|
|
733
823
|
return;
|
package/ui/styles.css
CHANGED
|
@@ -353,6 +353,67 @@ body { display: flex; }
|
|
|
353
353
|
margin: 0 auto;
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
+
.dashboard__theme-heading {
|
|
357
|
+
font-size: 28px;
|
|
358
|
+
font-weight: 700;
|
|
359
|
+
color: var(--text);
|
|
360
|
+
margin: 0 0 24px 0;
|
|
361
|
+
letter-spacing: -0.5px;
|
|
362
|
+
cursor: default;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.dashboard__theme-heading--editing {
|
|
366
|
+
border: 1px solid var(--accent);
|
|
367
|
+
border-radius: var(--radius);
|
|
368
|
+
padding: 2px 8px;
|
|
369
|
+
outline: none;
|
|
370
|
+
cursor: text;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.dashboard__theme-path {
|
|
374
|
+
display: flex;
|
|
375
|
+
align-items: center;
|
|
376
|
+
gap: 8px;
|
|
377
|
+
margin: -16px 0 24px 0;
|
|
378
|
+
color: var(--text-muted);
|
|
379
|
+
font-size: 13px;
|
|
380
|
+
font-family: "SF Mono", "Fira Code", "Fira Mono", monospace;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.dashboard__theme-path-text {
|
|
384
|
+
overflow: hidden;
|
|
385
|
+
text-overflow: ellipsis;
|
|
386
|
+
white-space: nowrap;
|
|
387
|
+
user-select: all;
|
|
388
|
+
cursor: text;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.dashboard__download-btn {
|
|
392
|
+
display: inline-flex;
|
|
393
|
+
align-items: center;
|
|
394
|
+
gap: 4px;
|
|
395
|
+
margin-left: auto;
|
|
396
|
+
padding: 4px 10px;
|
|
397
|
+
background: var(--surface-2);
|
|
398
|
+
color: var(--text-muted);
|
|
399
|
+
border: 1px solid var(--border);
|
|
400
|
+
border-radius: var(--radius);
|
|
401
|
+
font-size: 12px;
|
|
402
|
+
cursor: pointer;
|
|
403
|
+
white-space: nowrap;
|
|
404
|
+
transition: color 0.15s, border-color 0.15s;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.dashboard__download-btn:hover {
|
|
408
|
+
color: var(--text);
|
|
409
|
+
border-color: var(--text-muted);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.dashboard__download-btn:disabled {
|
|
413
|
+
opacity: 0.5;
|
|
414
|
+
cursor: default;
|
|
415
|
+
}
|
|
416
|
+
|
|
356
417
|
.dashboard__section {
|
|
357
418
|
margin-bottom: 36px;
|
|
358
419
|
}
|
|
@@ -475,6 +536,17 @@ body { display: flex; }
|
|
|
475
536
|
white-space: nowrap;
|
|
476
537
|
overflow: hidden;
|
|
477
538
|
text-overflow: ellipsis;
|
|
539
|
+
cursor: default;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.dashboard__template-label--editing {
|
|
543
|
+
background: var(--bg);
|
|
544
|
+
border: 1px solid var(--accent);
|
|
545
|
+
border-radius: 3px;
|
|
546
|
+
padding: 0 4px;
|
|
547
|
+
outline: none;
|
|
548
|
+
overflow: visible;
|
|
549
|
+
cursor: text;
|
|
478
550
|
}
|
|
479
551
|
|
|
480
552
|
.dashboard__template-meta {
|
|
@@ -702,10 +774,6 @@ body { display: flex; }
|
|
|
702
774
|
background: var(--accent-gradient);
|
|
703
775
|
border-radius: 8px;
|
|
704
776
|
color: var(--text-on-accent);
|
|
705
|
-
font-family: var(--font-display);
|
|
706
|
-
font-weight: 700;
|
|
707
|
-
font-size: 16px;
|
|
708
|
-
line-height: 1;
|
|
709
777
|
}
|
|
710
778
|
|
|
711
779
|
.topbar__brand-name {
|
|
@@ -726,6 +794,15 @@ body { display: flex; }
|
|
|
726
794
|
overflow: hidden;
|
|
727
795
|
text-overflow: ellipsis;
|
|
728
796
|
max-width: 180px;
|
|
797
|
+
cursor: default;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
.topbar__project-pill--editing {
|
|
801
|
+
border-color: var(--accent);
|
|
802
|
+
color: var(--text);
|
|
803
|
+
outline: none;
|
|
804
|
+
overflow: visible;
|
|
805
|
+
cursor: text;
|
|
729
806
|
}
|
|
730
807
|
|
|
731
808
|
.topbar__center {
|
|
@@ -1532,22 +1609,6 @@ body { display: flex; }
|
|
|
1532
1609
|
word-wrap: break-word;
|
|
1533
1610
|
}
|
|
1534
1611
|
|
|
1535
|
-
/* Streaming cursor */
|
|
1536
|
-
.chat-msg--streaming .chat-msg__bubble::after {
|
|
1537
|
-
content: "";
|
|
1538
|
-
display: inline-block;
|
|
1539
|
-
width: 6px;
|
|
1540
|
-
height: 14px;
|
|
1541
|
-
background: var(--accent);
|
|
1542
|
-
border-radius: 1px;
|
|
1543
|
-
margin-left: 2px;
|
|
1544
|
-
vertical-align: text-bottom;
|
|
1545
|
-
animation: cursorBlink 0.8s ease infinite;
|
|
1546
|
-
}
|
|
1547
|
-
@keyframes cursorBlink {
|
|
1548
|
-
0%, 100% { opacity: 1; }
|
|
1549
|
-
50% { opacity: 0.2; }
|
|
1550
|
-
}
|
|
1551
1612
|
|
|
1552
1613
|
.chat-msg__bubble p { margin-bottom: 8px; }
|
|
1553
1614
|
.chat-msg__bubble p:last-child { margin-bottom: 0; }
|
|
@@ -2481,6 +2542,20 @@ body { display: flex; }
|
|
|
2481
2542
|
padding: 8px;
|
|
2482
2543
|
}
|
|
2483
2544
|
|
|
2545
|
+
.history__toggle {
|
|
2546
|
+
text-align: center;
|
|
2547
|
+
padding: 8px 16px 4px;
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
.history__toggle-btn {
|
|
2551
|
+
background: none;
|
|
2552
|
+
border: none;
|
|
2553
|
+
color: var(--accent);
|
|
2554
|
+
font-size: 12px;
|
|
2555
|
+
cursor: pointer;
|
|
2556
|
+
text-decoration: underline;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2484
2559
|
.history__loading,
|
|
2485
2560
|
.history__empty {
|
|
2486
2561
|
color: var(--text-dim);
|
|
@@ -2802,17 +2877,18 @@ body { display: flex; }
|
|
|
2802
2877
|
}
|
|
2803
2878
|
|
|
2804
2879
|
.project-rail__footer {
|
|
2805
|
-
display:
|
|
2880
|
+
display: flex;
|
|
2881
|
+
flex-direction: column;
|
|
2882
|
+
gap: 4px;
|
|
2806
2883
|
margin-top: auto;
|
|
2807
2884
|
border-top: 1px solid var(--border);
|
|
2808
2885
|
padding: 8px;
|
|
2809
2886
|
flex-shrink: 0;
|
|
2887
|
+
align-items: center;
|
|
2810
2888
|
}
|
|
2811
2889
|
|
|
2812
2890
|
.project-rail--expanded .project-rail__footer {
|
|
2813
|
-
|
|
2814
|
-
flex-direction: column;
|
|
2815
|
-
gap: 4px;
|
|
2891
|
+
align-items: stretch;
|
|
2816
2892
|
}
|
|
2817
2893
|
|
|
2818
2894
|
.project-rail__settings-btn {
|
|
@@ -2948,6 +3024,17 @@ body { display: flex; }
|
|
|
2948
3024
|
overflow: hidden;
|
|
2949
3025
|
text-overflow: ellipsis;
|
|
2950
3026
|
color: var(--text);
|
|
3027
|
+
cursor: default;
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
.project-rail__item-name--editing {
|
|
3031
|
+
background: var(--bg);
|
|
3032
|
+
border: 1px solid var(--accent);
|
|
3033
|
+
border-radius: 3px;
|
|
3034
|
+
padding: 0 4px;
|
|
3035
|
+
outline: none;
|
|
3036
|
+
overflow: visible;
|
|
3037
|
+
cursor: text;
|
|
2951
3038
|
}
|
|
2952
3039
|
|
|
2953
3040
|
.project-rail__item-meta {
|
package/ui/upload-panel.js
CHANGED
|
@@ -354,11 +354,23 @@ function setUploadState(state, data) {
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
let _logBuffer = "";
|
|
358
|
+
let _logFlushScheduled = false;
|
|
359
|
+
|
|
357
360
|
function appendUploadLog(text) {
|
|
358
|
-
|
|
359
|
-
if (!
|
|
360
|
-
|
|
361
|
-
|
|
361
|
+
_logBuffer += text;
|
|
362
|
+
if (!_logFlushScheduled) {
|
|
363
|
+
_logFlushScheduled = true;
|
|
364
|
+
requestAnimationFrame(() => {
|
|
365
|
+
_logFlushScheduled = false;
|
|
366
|
+
const log = document.getElementById("upload-log");
|
|
367
|
+
if (log) {
|
|
368
|
+
log.textContent += _logBuffer;
|
|
369
|
+
log.scrollTop = log.scrollHeight;
|
|
370
|
+
}
|
|
371
|
+
_logBuffer = "";
|
|
372
|
+
});
|
|
373
|
+
}
|
|
362
374
|
}
|
|
363
375
|
|
|
364
376
|
function fixUploadWithAI() {
|