vibespot 0.7.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 +238 -6787
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/chat.js +40 -3
- 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/upload-panel.js +16 -4
package/package.json
CHANGED
package/ui/chat.js
CHANGED
|
@@ -15,6 +15,8 @@ let streamTimerInterval = null;
|
|
|
15
15
|
let lastStreamStatus = "";
|
|
16
16
|
let currentSessionId = "";
|
|
17
17
|
let currentTemplateId = "";
|
|
18
|
+
let renderScheduled = false;
|
|
19
|
+
let scrollScheduled = false;
|
|
18
20
|
|
|
19
21
|
const messagesEl = document.getElementById("chat-messages");
|
|
20
22
|
const inputEl = document.getElementById("chat-input");
|
|
@@ -47,11 +49,15 @@ function connectWebSocket() {
|
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
ws.onclose = () => {
|
|
52
|
+
stopStreamTimer();
|
|
53
|
+
if (isStreaming) finishStreaming();
|
|
50
54
|
setStatus("Disconnected — reconnecting...");
|
|
51
55
|
setTimeout(connectWebSocket, 2000);
|
|
52
56
|
};
|
|
53
57
|
|
|
54
58
|
ws.onerror = () => {
|
|
59
|
+
stopStreamTimer();
|
|
60
|
+
if (isStreaming) finishStreaming();
|
|
55
61
|
setStatus("Connection error");
|
|
56
62
|
};
|
|
57
63
|
}
|
|
@@ -236,6 +242,16 @@ function handleStreamChunk(text) {
|
|
|
236
242
|
if (!streamingMsgEl) return;
|
|
237
243
|
streamBuffer += text;
|
|
238
244
|
|
|
245
|
+
if (!renderScheduled) {
|
|
246
|
+
renderScheduled = true;
|
|
247
|
+
requestAnimationFrame(flushStreamRender);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function flushStreamRender() {
|
|
252
|
+
renderScheduled = false;
|
|
253
|
+
if (!streamingMsgEl) return;
|
|
254
|
+
|
|
239
255
|
// Hide incomplete code fences (AI is writing module code)
|
|
240
256
|
let display = streamBuffer;
|
|
241
257
|
const fenceCount = (display.match(/```/g) || []).length;
|
|
@@ -410,7 +426,16 @@ function escapeHtml(str) {
|
|
|
410
426
|
}
|
|
411
427
|
|
|
412
428
|
function scrollToBottom() {
|
|
413
|
-
|
|
429
|
+
if (scrollScheduled) return;
|
|
430
|
+
scrollScheduled = true;
|
|
431
|
+
requestAnimationFrame(() => {
|
|
432
|
+
scrollScheduled = false;
|
|
433
|
+
// Only auto-scroll if user is near the bottom (within 150px)
|
|
434
|
+
const gap = messagesEl.scrollHeight - messagesEl.scrollTop - messagesEl.clientHeight;
|
|
435
|
+
if (gap < 150) {
|
|
436
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
437
|
+
}
|
|
438
|
+
});
|
|
414
439
|
}
|
|
415
440
|
|
|
416
441
|
function setStatus(text) {
|
|
@@ -488,7 +513,11 @@ async function refreshHistoryPanel() {
|
|
|
488
513
|
}
|
|
489
514
|
|
|
490
515
|
list.innerHTML = toggleHtml;
|
|
491
|
-
|
|
516
|
+
const HISTORY_LIMIT = 50;
|
|
517
|
+
const commits = data.commits.slice(0, HISTORY_LIMIT);
|
|
518
|
+
const frag = document.createDocumentFragment();
|
|
519
|
+
|
|
520
|
+
for (const commit of commits) {
|
|
492
521
|
const isInitial = commit.message.startsWith("Initial ");
|
|
493
522
|
const isRollback = commit.message.includes("Rollback to:");
|
|
494
523
|
|
|
@@ -507,7 +536,15 @@ async function refreshHistoryPanel() {
|
|
|
507
536
|
<div class="history-item__msg">${escapeHtml(displayMsg)}</div>
|
|
508
537
|
${!isInitial ? `<button class="history-item__rollback" data-hash="${escapeHtml(commit.fullHash)}">Restore</button>` : ""}
|
|
509
538
|
`;
|
|
510
|
-
|
|
539
|
+
frag.appendChild(item);
|
|
540
|
+
}
|
|
541
|
+
list.appendChild(frag);
|
|
542
|
+
|
|
543
|
+
if (data.commits.length > HISTORY_LIMIT) {
|
|
544
|
+
const more = document.createElement("div");
|
|
545
|
+
more.className = "history__show-more";
|
|
546
|
+
more.textContent = `Showing ${HISTORY_LIMIT} of ${data.commits.length} versions`;
|
|
547
|
+
list.appendChild(more);
|
|
511
548
|
}
|
|
512
549
|
|
|
513
550
|
list.querySelectorAll(".history-item__rollback").forEach((btn) => {
|
package/ui/dashboard.js
CHANGED
|
@@ -115,25 +115,20 @@ function renderTemplateList(templates) {
|
|
|
115
115
|
list.appendChild(item);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
//
|
|
119
|
-
list.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
118
|
+
// Event delegation — single listener handles all template actions
|
|
119
|
+
list.onclick = (e) => {
|
|
120
|
+
const openBtn = e.target.closest(".dashboard__template-open");
|
|
121
|
+
if (openBtn) return openTemplate(openBtn.dataset.id);
|
|
122
|
+
const delBtn = e.target.closest(".dashboard__template-delete");
|
|
123
|
+
if (delBtn) return confirmDeleteTemplate(delBtn.dataset.id);
|
|
124
|
+
};
|
|
125
|
+
list.ondblclick = (e) => {
|
|
126
|
+
const labelEl = e.target.closest(".dashboard__template-label");
|
|
127
|
+
if (!labelEl) return;
|
|
128
128
|
const item = labelEl.closest(".dashboard__template-item");
|
|
129
129
|
const templateId = item?.querySelector(".dashboard__template-open")?.dataset.id;
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
labelEl.addEventListener("dblclick", (e) => {
|
|
133
|
-
e.stopPropagation();
|
|
134
|
-
startTemplateRename(labelEl, templateId);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
130
|
+
if (templateId) startTemplateRename(labelEl, templateId);
|
|
131
|
+
};
|
|
137
132
|
}
|
|
138
133
|
|
|
139
134
|
function startTemplateRename(labelEl, templateId) {
|
package/ui/dialog.js
CHANGED
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
// HTML-escape helper (standalone so dialog.js has no load-order dependency)
|
|
7
7
|
if (typeof esc === "undefined") {
|
|
8
8
|
// eslint-disable-next-line no-var
|
|
9
|
+
var _escMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
9
10
|
var esc = function (str) {
|
|
10
|
-
|
|
11
|
-
el.textContent = String(str);
|
|
12
|
-
return el.innerHTML;
|
|
11
|
+
return String(str).replace(/[&<>"']/g, function (c) { return _escMap[c]; });
|
|
13
12
|
};
|
|
14
13
|
}
|
|
15
14
|
|
package/ui/favicon.ico
CHANGED
|
Binary file
|
package/ui/field-editor.js
CHANGED
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() {
|