@luckydraw/cumulus 0.27.18 → 0.27.19
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/cli/cumulus.js +0 -0
- package/dist/gateway/adapters/webchat.d.ts +1 -3
- package/dist/gateway/adapters/webchat.d.ts.map +1 -1
- package/dist/gateway/adapters/webchat.js +7 -150
- package/dist/gateway/adapters/webchat.js.map +1 -1
- package/dist/gateway/config.d.ts +7 -0
- package/dist/gateway/config.d.ts.map +1 -1
- package/dist/gateway/config.js +13 -0
- package/dist/gateway/config.js.map +1 -1
- package/dist/gateway/daemon.js +26 -8
- package/dist/gateway/daemon.js.map +1 -1
- package/dist/gateway/gateway-agents-mcp.js +49 -0
- package/dist/gateway/gateway-agents-mcp.js.map +1 -1
- package/dist/gateway/push.d.ts +66 -0
- package/dist/gateway/push.d.ts.map +1 -0
- package/dist/gateway/push.js +131 -0
- package/dist/gateway/push.js.map +1 -0
- package/dist/gateway/server.d.ts +3 -9
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/gateway/server.js +112 -243
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/static/sw.js +73 -0
- package/dist/gateway/static/widget.js +126 -755
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +0 -8
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -61
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/content-detector.d.ts.map +1 -1
- package/dist/lib/content-detector.js +2 -9
- package/dist/lib/content-detector.js.map +1 -1
- package/dist/lib/gateway.d.ts +2 -14
- package/dist/lib/gateway.d.ts.map +1 -1
- package/dist/lib/gateway.js +103 -234
- package/dist/lib/gateway.js.map +1 -1
- package/dist/lib/summaries.d.ts.map +1 -1
- package/dist/lib/summaries.js +2 -9
- package/dist/lib/summaries.js.map +1 -1
- package/dist/mcp/index.js +0 -0
- package/dist/mcp/tool-handler.d.ts.map +1 -1
- package/dist/mcp/tool-handler.js +3 -10
- package/dist/mcp/tool-handler.js.map +1 -1
- package/dist/tui/hooks/useClaudeProcess.d.ts.map +1 -1
- package/dist/tui/hooks/useClaudeProcess.js +23 -18
- package/dist/tui/hooks/useClaudeProcess.js.map +1 -1
- package/package.json +3 -1
- package/dist/gateway/device-mcp.d.ts +0 -21
- package/dist/gateway/device-mcp.d.ts.map +0 -1
- package/dist/gateway/device-mcp.js +0 -165
- package/dist/gateway/device-mcp.js.map +0 -1
- package/dist/lib/executor.d.ts +0 -168
- package/dist/lib/executor.d.ts.map +0 -1
- package/dist/lib/executor.js +0 -284
- package/dist/lib/executor.js.map +0 -1
- package/dist/lib/projects.d.ts.map +0 -1
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Cumulus Web Chat Widget — self-contained, no external dependencies.
|
|
3
3
|
* Embeddable via <script src="/widget.js" data-api-key="..."></script>
|
|
4
4
|
* or usable standalone at /chat.
|
|
5
|
-
* @version 0.27.15
|
|
6
5
|
*
|
|
7
6
|
* < 80KB unminified.
|
|
8
7
|
*/
|
|
@@ -155,38 +154,6 @@
|
|
|
155
154
|
' word-wrap: break-word;',
|
|
156
155
|
'}',
|
|
157
156
|
|
|
158
|
-
/* ── Timestamps ── */
|
|
159
|
-
'.cumulus-msg-time {',
|
|
160
|
-
' font-size: 0.75em; color: #555; margin-top: 0.3em; padding: 0 0.3em;',
|
|
161
|
-
'}',
|
|
162
|
-
'.cumulus-msg-row:has(.user) .cumulus-msg-time { align-self: flex-end; }',
|
|
163
|
-
'.cumulus-msg-row:has(.assistant) .cumulus-msg-time { align-self: flex-start; }',
|
|
164
|
-
|
|
165
|
-
/* ── Agent messages ── */
|
|
166
|
-
'.cumulus-msg.agent {',
|
|
167
|
-
' align-self: flex-start;',
|
|
168
|
-
' background: transparent;',
|
|
169
|
-
' color: #e0e0e0;',
|
|
170
|
-
' padding: 0.4em 0 0.4em 0.75em;',
|
|
171
|
-
' width: 100%;',
|
|
172
|
-
' word-wrap: break-word;',
|
|
173
|
-
' border-left: 2px solid var(--agent-color, #9966cc);',
|
|
174
|
-
'}',
|
|
175
|
-
'.cumulus-agent-header {',
|
|
176
|
-
' display: flex; align-items: center; gap: 0.4em;',
|
|
177
|
-
' margin-bottom: 0.3em; font-size: 0.82em;',
|
|
178
|
-
'}',
|
|
179
|
-
'.cumulus-agent-name {',
|
|
180
|
-
' font-family: "SF Mono", "Fira Code", Consolas, monospace;',
|
|
181
|
-
' font-weight: 600; color: var(--agent-color, #9966cc);',
|
|
182
|
-
'}',
|
|
183
|
-
'.cumulus-agent-name::before { content: "["; opacity: 0.5; }',
|
|
184
|
-
'.cumulus-agent-name::after { content: "]"; opacity: 0.5; }',
|
|
185
|
-
'.cumulus-agent-context {',
|
|
186
|
-
' font-size: 0.9em; color: #666;',
|
|
187
|
-
' font-family: "SF Mono", "Fira Code", Consolas, monospace;',
|
|
188
|
-
'}',
|
|
189
|
-
|
|
190
157
|
/* ── Markdown rendered inside assistant messages ── */
|
|
191
158
|
'.cumulus-msg.assistant p { margin: 0.4em 0; }',
|
|
192
159
|
'.cumulus-msg.assistant p:first-child { margin-top: 0; }',
|
|
@@ -718,97 +685,6 @@
|
|
|
718
685
|
' border-radius: 3px; font-family: inherit; white-space: nowrap;',
|
|
719
686
|
'}',
|
|
720
687
|
'.cumulus-panel-action-btn:hover { color: #ddd; border-color: #555; }',
|
|
721
|
-
'.cumulus-panel-action-btn.active { color: #e0e0e0; border-color: #0066cc; background: rgba(0,102,204,0.12); }',
|
|
722
|
-
|
|
723
|
-
/* ── Context menu (right-click on thread) ── */
|
|
724
|
-
'.cumulus-context-menu {',
|
|
725
|
-
' position: fixed; z-index: 300; background: #2a2a2a; border: 1px solid #444;',
|
|
726
|
-
' border-radius: 6px; padding: 4px 0; min-width: 140px;',
|
|
727
|
-
' box-shadow: 0 4px 12px rgba(0,0,0,0.5); font-size: 13px;',
|
|
728
|
-
'}',
|
|
729
|
-
'.cumulus-context-menu-item {',
|
|
730
|
-
' padding: 6px 14px; color: #ccc; cursor: pointer; display: block;',
|
|
731
|
-
' width: 100%; border: none; background: none; text-align: left;',
|
|
732
|
-
' font-family: inherit; font-size: inherit;',
|
|
733
|
-
'}',
|
|
734
|
-
'.cumulus-context-menu-item:hover { background: #3a3a3a; color: #fff; }',
|
|
735
|
-
'.cumulus-context-menu-item.danger { color: #ef4444; }',
|
|
736
|
-
'.cumulus-context-menu-item.danger:hover { background: rgba(239,68,68,0.15); color: #ff6b6b; }',
|
|
737
|
-
|
|
738
|
-
/* ── Unread dot (glowing) ── */
|
|
739
|
-
'.cumulus-thread-unread {',
|
|
740
|
-
' width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;',
|
|
741
|
-
' background: #3b82f6;',
|
|
742
|
-
' box-shadow: 0 0 4px #3b82f6, 0 0 8px rgba(59,130,246,0.4);',
|
|
743
|
-
' animation: cumulus-unread-pulse 2s ease-in-out infinite;',
|
|
744
|
-
'}',
|
|
745
|
-
'@keyframes cumulus-unread-pulse {',
|
|
746
|
-
' 0%, 100% { box-shadow: 0 0 4px #3b82f6, 0 0 8px rgba(59,130,246,0.4); }',
|
|
747
|
-
' 50% { box-shadow: 0 0 6px #3b82f6, 0 0 14px rgba(59,130,246,0.6); }',
|
|
748
|
-
'}',
|
|
749
|
-
|
|
750
|
-
/* ── Message checkbox (selection mode) ── */
|
|
751
|
-
'.cumulus-msg-checkbox {',
|
|
752
|
-
' display: none; flex-shrink: 0; align-self: flex-start; margin-top: 0.4em;',
|
|
753
|
-
' width: 16px; height: 16px; cursor: pointer; accent-color: #0066cc;',
|
|
754
|
-
'}',
|
|
755
|
-
'.cumulus-selection-mode .cumulus-msg-checkbox { display: block; }',
|
|
756
|
-
'.cumulus-selection-mode .cumulus-msg-row {',
|
|
757
|
-
' flex-direction: row; align-items: flex-start; gap: 8px;',
|
|
758
|
-
'}',
|
|
759
|
-
'.cumulus-selection-mode .cumulus-msg-row > *:not(.cumulus-msg-checkbox) { flex: 1; min-width: 0; }',
|
|
760
|
-
|
|
761
|
-
/* ── Selection action bar (floats at bottom of messages area) ── */
|
|
762
|
-
'.cumulus-selection-bar {',
|
|
763
|
-
' display: flex; align-items: center; gap: 8px;',
|
|
764
|
-
' padding: 8px 12px;',
|
|
765
|
-
' background: #2d2d2d; border-top: 1px solid #3a3a3a;',
|
|
766
|
-
' flex-shrink: 0;',
|
|
767
|
-
'}',
|
|
768
|
-
'.cumulus-selection-count { font-size: 13px; color: #aaa; flex: 1; }',
|
|
769
|
-
'.cumulus-selection-select-all-btn {',
|
|
770
|
-
' background: none; border: 1px solid #555; color: #ccc;',
|
|
771
|
-
' padding: 4px 10px; border-radius: 4px; font-size: 12px;',
|
|
772
|
-
' cursor: pointer; font-family: inherit;',
|
|
773
|
-
'}',
|
|
774
|
-
'.cumulus-selection-select-all-btn:hover { border-color: #888; color: #e0e0e0; }',
|
|
775
|
-
'.cumulus-selection-delete-btn {',
|
|
776
|
-
' background: #8b2222; border: none; color: white;',
|
|
777
|
-
' padding: 4px 12px; border-radius: 4px; font-size: 12px;',
|
|
778
|
-
' cursor: pointer; font-family: inherit; font-weight: 600;',
|
|
779
|
-
'}',
|
|
780
|
-
'.cumulus-selection-delete-btn:hover:not(:disabled) { background: #a33; }',
|
|
781
|
-
'.cumulus-selection-delete-btn:disabled { background: #3a2a2a; color: #666; cursor: not-allowed; }',
|
|
782
|
-
|
|
783
|
-
/* ── Confirm dialog overlay ── */
|
|
784
|
-
'.cumulus-confirm-dialog {',
|
|
785
|
-
' position: absolute; top: 0; left: 0; right: 0; bottom: 0;',
|
|
786
|
-
' background: rgba(0,0,0,0.6); z-index: 20;',
|
|
787
|
-
' display: flex; align-items: center; justify-content: center;',
|
|
788
|
-
'}',
|
|
789
|
-
'.cumulus-confirm-dialog-box {',
|
|
790
|
-
' background: #2d2d2d; border: 1px solid #4a4a4a; border-radius: 8px;',
|
|
791
|
-
' padding: 1.5em; max-width: 320px; width: 90%;',
|
|
792
|
-
' display: flex; flex-direction: column; gap: 1em; text-align: center;',
|
|
793
|
-
' box-shadow: 0 8px 32px rgba(0,0,0,0.5);',
|
|
794
|
-
'}',
|
|
795
|
-
'.cumulus-confirm-dialog-title { font-weight: 600; font-size: 15px; color: #e0e0e0; }',
|
|
796
|
-
'.cumulus-confirm-dialog-text { font-size: 13px; color: #aaa; }',
|
|
797
|
-
'.cumulus-confirm-dialog-warn { font-size: 12px; color: #f59e0b; }',
|
|
798
|
-
'.cumulus-confirm-dialog-actions { display: flex; gap: 8px; justify-content: center; }',
|
|
799
|
-
'.cumulus-confirm-dialog-cancel {',
|
|
800
|
-
' padding: 0.4em 1.2em; border-radius: 4px; cursor: pointer;',
|
|
801
|
-
' font-size: 13px; border: 1px solid #3a3a3a; background: #2a2a2a; color: #ccc;',
|
|
802
|
-
' font-family: inherit;',
|
|
803
|
-
'}',
|
|
804
|
-
'.cumulus-confirm-dialog-cancel:hover { background: #3a3a3a; }',
|
|
805
|
-
'.cumulus-confirm-dialog-confirm {',
|
|
806
|
-
' padding: 0.4em 1.2em; border-radius: 4px; cursor: pointer;',
|
|
807
|
-
' font-size: 13px; border: none; background: #8b2222; color: white;',
|
|
808
|
-
' font-family: inherit; font-weight: 600;',
|
|
809
|
-
'}',
|
|
810
|
-
'.cumulus-confirm-dialog-confirm:hover { background: #a33; }',
|
|
811
|
-
'.cumulus-confirm-dialog-confirm:disabled { background: #3a2a2a; color: #666; cursor: not-allowed; }',
|
|
812
688
|
|
|
813
689
|
/* ── Overlay (covers the thread panel) ── */
|
|
814
690
|
'.cumulus-overlay {',
|
|
@@ -1044,67 +920,6 @@
|
|
|
1044
920
|
// else, then reinsert code blocks. This prevents markdown patterns inside
|
|
1045
921
|
// code from being processed.
|
|
1046
922
|
|
|
1047
|
-
// ── Agent message detection + timestamps ──────────────────────────────────
|
|
1048
|
-
var AGENT_MSG_RE = /^\[([^\]]+)\s*\u2192\s*([^\]]+)\]:\s*/; // [sender → recipient]:
|
|
1049
|
-
var AGENT_COLORS = ['#9966cc', '#2aa198', '#e69500', '#d33682', '#85c025', '#ff6b6b'];
|
|
1050
|
-
|
|
1051
|
-
function getAgentColor(name) {
|
|
1052
|
-
var hash = 0;
|
|
1053
|
-
for (var i = 0; i < name.length; i++) hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
|
|
1054
|
-
return AGENT_COLORS[Math.abs(hash) % AGENT_COLORS.length];
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
function parseAgentMessage(content) {
|
|
1058
|
-
var match = content.match(AGENT_MSG_RE);
|
|
1059
|
-
if (!match) return null;
|
|
1060
|
-
var body = content.slice(match[0].length).replace(/\n\n\(Reply using send_to_agent\([^)]*\)[^)]*\)\s*$/, '').trim();
|
|
1061
|
-
// Also strip CC/broadcast reply hints
|
|
1062
|
-
body = body.replace(/\n\n\(You are CC'd on this message[^)]*\)\s*$/, '').trim();
|
|
1063
|
-
body = body.replace(/\n\n\(Review the above messages[^)]*\)\s*$/, '').trim();
|
|
1064
|
-
return { sender: match[1].trim(), recipient: match[2].trim(), body: body };
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
function formatTime(timestamp) {
|
|
1068
|
-
if (!timestamp) return null;
|
|
1069
|
-
var d = new Date(timestamp);
|
|
1070
|
-
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
function appendTimestamp(parent, timestamp) {
|
|
1074
|
-
var time = formatTime(timestamp);
|
|
1075
|
-
if (time) {
|
|
1076
|
-
var timeEl = document.createElement('div');
|
|
1077
|
-
timeEl.className = 'cumulus-msg-time';
|
|
1078
|
-
timeEl.textContent = time;
|
|
1079
|
-
parent.appendChild(timeEl);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
function buildAgentMsgEl(agent) {
|
|
1084
|
-
var el = document.createElement('div');
|
|
1085
|
-
el.className = 'cumulus-msg agent';
|
|
1086
|
-
el.style.setProperty('--agent-color', getAgentColor(agent.sender));
|
|
1087
|
-
|
|
1088
|
-
var header = document.createElement('div');
|
|
1089
|
-
header.className = 'cumulus-agent-header';
|
|
1090
|
-
var nameEl = document.createElement('span');
|
|
1091
|
-
nameEl.className = 'cumulus-agent-name';
|
|
1092
|
-
nameEl.textContent = agent.sender;
|
|
1093
|
-
header.appendChild(nameEl);
|
|
1094
|
-
var ctx = document.createElement('span');
|
|
1095
|
-
ctx.className = 'cumulus-agent-context';
|
|
1096
|
-
ctx.textContent = '\u2192 ' + agent.recipient;
|
|
1097
|
-
header.appendChild(ctx);
|
|
1098
|
-
el.appendChild(header);
|
|
1099
|
-
|
|
1100
|
-
var body = document.createElement('div');
|
|
1101
|
-
body.innerHTML = renderMarkdown(agent.body);
|
|
1102
|
-
el.appendChild(body);
|
|
1103
|
-
return el;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
// ── Markdown ──────────────────────────────────────────────────────────────
|
|
1107
|
-
|
|
1108
923
|
function renderMarkdown(text) {
|
|
1109
924
|
// Phase 1: Extract fenced code blocks — replace with unique tokens
|
|
1110
925
|
var codeBlocks = [];
|
|
@@ -1520,8 +1335,6 @@
|
|
|
1520
1335
|
var connectionStatus = 'disconnected';
|
|
1521
1336
|
var authenticated = false;
|
|
1522
1337
|
var pendingAttachments = [];
|
|
1523
|
-
var selectionMode = false;
|
|
1524
|
-
var selectedIds = {};
|
|
1525
1338
|
|
|
1526
1339
|
// ── Panel ──
|
|
1527
1340
|
var panel = document.createElement('div');
|
|
@@ -1538,9 +1351,6 @@
|
|
|
1538
1351
|
'<span class="cumulus-status-dot" data-testid="webchat-status-dot"></span>' +
|
|
1539
1352
|
'<span data-testid="webchat-status-text">Disconnected</span>' +
|
|
1540
1353
|
'</span>' +
|
|
1541
|
-
'<div class="cumulus-panel-actions">' +
|
|
1542
|
-
'<button class="cumulus-panel-action-btn" data-testid="webchat-select-btn" title="Select messages to delete">Select</button>' +
|
|
1543
|
-
'</div>' +
|
|
1544
1354
|
'<button class="cumulus-close-btn" data-testid="webchat-close">×</button>';
|
|
1545
1355
|
panel.appendChild(header);
|
|
1546
1356
|
|
|
@@ -1639,9 +1449,7 @@
|
|
|
1639
1449
|
|
|
1640
1450
|
// ── Rendering ──
|
|
1641
1451
|
function scrollToBottom() {
|
|
1642
|
-
|
|
1643
|
-
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
1644
|
-
});
|
|
1452
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
1645
1453
|
}
|
|
1646
1454
|
|
|
1647
1455
|
function isWideUserMessage(content) {
|
|
@@ -1710,51 +1518,20 @@
|
|
|
1710
1518
|
|
|
1711
1519
|
function renderMessages() {
|
|
1712
1520
|
messagesEl.innerHTML = '';
|
|
1713
|
-
// Apply selection mode class
|
|
1714
|
-
if (selectionMode) {
|
|
1715
|
-
messagesEl.classList.add('cumulus-selection-mode');
|
|
1716
|
-
} else {
|
|
1717
|
-
messagesEl.classList.remove('cumulus-selection-mode');
|
|
1718
|
-
}
|
|
1719
1521
|
if (messages.length === 0 && !streaming) {
|
|
1720
1522
|
messagesEl.innerHTML =
|
|
1721
1523
|
'<div class="cumulus-empty">Send a message to start chatting</div>';
|
|
1722
|
-
updateEmbeddedSelectionBar();
|
|
1723
1524
|
return;
|
|
1724
1525
|
}
|
|
1725
1526
|
for (var i = 0; i < messages.length; i++) {
|
|
1726
1527
|
var msg = messages[i];
|
|
1727
1528
|
var row = document.createElement('div');
|
|
1728
1529
|
row.className = 'cumulus-msg-row';
|
|
1729
|
-
// Add checkbox in selection mode
|
|
1730
|
-
if (selectionMode && msg.id) {
|
|
1731
|
-
var cb = document.createElement('input');
|
|
1732
|
-
cb.type = 'checkbox';
|
|
1733
|
-
cb.className = 'cumulus-msg-checkbox';
|
|
1734
|
-
cb.checked = !!selectedIds[msg.id];
|
|
1735
|
-
(function (msgId) {
|
|
1736
|
-
cb.addEventListener('change', function () {
|
|
1737
|
-
if (cb.checked) {
|
|
1738
|
-
selectedIds[msgId] = true;
|
|
1739
|
-
} else {
|
|
1740
|
-
delete selectedIds[msgId];
|
|
1741
|
-
}
|
|
1742
|
-
updateEmbeddedSelectionBar();
|
|
1743
|
-
});
|
|
1744
|
-
})(msg.id);
|
|
1745
|
-
row.appendChild(cb);
|
|
1746
|
-
}
|
|
1747
1530
|
if (msg.role === 'user') {
|
|
1748
|
-
|
|
1749
|
-
if (agent) {
|
|
1750
|
-
row.appendChild(buildAgentMsgEl(agent));
|
|
1751
|
-
} else {
|
|
1752
|
-
row.appendChild(buildUserMsgEl(msg));
|
|
1753
|
-
}
|
|
1531
|
+
row.appendChild(buildUserMsgEl(msg));
|
|
1754
1532
|
} else {
|
|
1755
1533
|
row.appendChild(buildAssistantMsgEl(msg.content, false));
|
|
1756
1534
|
}
|
|
1757
|
-
appendTimestamp(row, msg.timestamp);
|
|
1758
1535
|
messagesEl.appendChild(row);
|
|
1759
1536
|
}
|
|
1760
1537
|
if (streaming) {
|
|
@@ -1764,109 +1541,6 @@
|
|
|
1764
1541
|
messagesEl.appendChild(row);
|
|
1765
1542
|
}
|
|
1766
1543
|
scrollToBottom();
|
|
1767
|
-
updateEmbeddedSelectionBar();
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
function updateEmbeddedSelectionBar() {
|
|
1771
|
-
var existingBar = panel.querySelector('.cumulus-selection-bar');
|
|
1772
|
-
if (existingBar) existingBar.remove();
|
|
1773
|
-
if (!selectionMode) return;
|
|
1774
|
-
|
|
1775
|
-
var selectedCount = Object.keys(selectedIds).length;
|
|
1776
|
-
var selectableCount = messages.filter(function (m) { return !!m.id; }).length;
|
|
1777
|
-
|
|
1778
|
-
var bar = document.createElement('div');
|
|
1779
|
-
bar.className = 'cumulus-selection-bar';
|
|
1780
|
-
|
|
1781
|
-
var countEl = document.createElement('span');
|
|
1782
|
-
countEl.className = 'cumulus-selection-count';
|
|
1783
|
-
countEl.textContent = selectedCount + ' selected';
|
|
1784
|
-
bar.appendChild(countEl);
|
|
1785
|
-
|
|
1786
|
-
var selectAllBtn = document.createElement('button');
|
|
1787
|
-
selectAllBtn.className = 'cumulus-selection-select-all-btn';
|
|
1788
|
-
selectAllBtn.textContent = selectedCount === selectableCount && selectableCount > 0 ? 'Deselect All' : 'Select All';
|
|
1789
|
-
selectAllBtn.addEventListener('click', function () {
|
|
1790
|
-
if (selectedCount === selectableCount && selectableCount > 0) {
|
|
1791
|
-
selectedIds = {};
|
|
1792
|
-
} else {
|
|
1793
|
-
messages.forEach(function (m) {
|
|
1794
|
-
if (m.id) selectedIds[m.id] = true;
|
|
1795
|
-
});
|
|
1796
|
-
}
|
|
1797
|
-
renderMessages();
|
|
1798
|
-
});
|
|
1799
|
-
bar.appendChild(selectAllBtn);
|
|
1800
|
-
|
|
1801
|
-
var deleteBtn = document.createElement('button');
|
|
1802
|
-
deleteBtn.className = 'cumulus-selection-delete-btn';
|
|
1803
|
-
deleteBtn.textContent = 'Delete';
|
|
1804
|
-
deleteBtn.disabled = selectedCount === 0;
|
|
1805
|
-
deleteBtn.addEventListener('click', function () {
|
|
1806
|
-
if (selectedCount === 0) return;
|
|
1807
|
-
showEmbeddedDeleteMessagesConfirm(Object.keys(selectedIds));
|
|
1808
|
-
});
|
|
1809
|
-
bar.appendChild(deleteBtn);
|
|
1810
|
-
|
|
1811
|
-
var inputAreaEl = panel.querySelector('.cumulus-input-area');
|
|
1812
|
-
if (inputAreaEl) {
|
|
1813
|
-
panel.insertBefore(bar, inputAreaEl);
|
|
1814
|
-
} else {
|
|
1815
|
-
panel.appendChild(bar);
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
function showEmbeddedDeleteMessagesConfirm(ids) {
|
|
1820
|
-
var existing = panel.querySelector('.cumulus-confirm-dialog');
|
|
1821
|
-
if (existing) existing.remove();
|
|
1822
|
-
|
|
1823
|
-
var dialog = document.createElement('div');
|
|
1824
|
-
dialog.className = 'cumulus-confirm-dialog';
|
|
1825
|
-
|
|
1826
|
-
var box = document.createElement('div');
|
|
1827
|
-
box.className = 'cumulus-confirm-dialog-box';
|
|
1828
|
-
|
|
1829
|
-
var title = document.createElement('div');
|
|
1830
|
-
title.className = 'cumulus-confirm-dialog-title';
|
|
1831
|
-
title.textContent = 'Delete Messages';
|
|
1832
|
-
box.appendChild(title);
|
|
1833
|
-
|
|
1834
|
-
var text = document.createElement('div');
|
|
1835
|
-
text.className = 'cumulus-confirm-dialog-text';
|
|
1836
|
-
text.textContent = ids.length + ' message' + (ids.length === 1 ? '' : 's') + ' will be permanently deleted.';
|
|
1837
|
-
box.appendChild(text);
|
|
1838
|
-
|
|
1839
|
-
var warn = document.createElement('div');
|
|
1840
|
-
warn.className = 'cumulus-confirm-dialog-warn';
|
|
1841
|
-
warn.textContent = 'This cannot be undone.';
|
|
1842
|
-
box.appendChild(warn);
|
|
1843
|
-
|
|
1844
|
-
var actions = document.createElement('div');
|
|
1845
|
-
actions.className = 'cumulus-confirm-dialog-actions';
|
|
1846
|
-
|
|
1847
|
-
var cancelBtn = document.createElement('button');
|
|
1848
|
-
cancelBtn.className = 'cumulus-confirm-dialog-cancel';
|
|
1849
|
-
cancelBtn.textContent = 'Cancel';
|
|
1850
|
-
cancelBtn.addEventListener('click', function () { dialog.remove(); });
|
|
1851
|
-
actions.appendChild(cancelBtn);
|
|
1852
|
-
|
|
1853
|
-
var confirmBtn = document.createElement('button');
|
|
1854
|
-
confirmBtn.className = 'cumulus-confirm-dialog-confirm';
|
|
1855
|
-
confirmBtn.setAttribute('data-testid', 'webchat-delete-messages-confirm');
|
|
1856
|
-
confirmBtn.textContent = 'Delete';
|
|
1857
|
-
confirmBtn.addEventListener('click', function () {
|
|
1858
|
-
confirmBtn.disabled = true;
|
|
1859
|
-
confirmBtn.textContent = 'Deleting\u2026';
|
|
1860
|
-
if (connection) {
|
|
1861
|
-
connection.send({ type: 'delete_messages', threadName: sessionId, messageIds: ids });
|
|
1862
|
-
}
|
|
1863
|
-
dialog.remove();
|
|
1864
|
-
});
|
|
1865
|
-
actions.appendChild(confirmBtn);
|
|
1866
|
-
|
|
1867
|
-
box.appendChild(actions);
|
|
1868
|
-
dialog.appendChild(box);
|
|
1869
|
-
panel.appendChild(dialog);
|
|
1870
1544
|
}
|
|
1871
1545
|
|
|
1872
1546
|
function updateSendBtn() {
|
|
@@ -1963,7 +1637,7 @@
|
|
|
1963
1637
|
case 'history':
|
|
1964
1638
|
if (data.messages && data.messages.length > 0) {
|
|
1965
1639
|
messages = data.messages.map(function (m) {
|
|
1966
|
-
return {
|
|
1640
|
+
return { role: m.role, content: m.content };
|
|
1967
1641
|
});
|
|
1968
1642
|
renderMessages();
|
|
1969
1643
|
}
|
|
@@ -2019,30 +1693,6 @@
|
|
|
2019
1693
|
updateSendBtn();
|
|
2020
1694
|
renderMessages();
|
|
2021
1695
|
break;
|
|
2022
|
-
case 'new_messages':
|
|
2023
|
-
// Agent inject completed — append new messages and re-render
|
|
2024
|
-
if (data.messages && data.messages.length > 0) {
|
|
2025
|
-
for (var nm = 0; nm < data.messages.length; nm++) {
|
|
2026
|
-
messages.push({ role: data.messages[nm].role, content: data.messages[nm].content });
|
|
2027
|
-
}
|
|
2028
|
-
renderMessages();
|
|
2029
|
-
}
|
|
2030
|
-
break;
|
|
2031
|
-
case 'messages_deleted':
|
|
2032
|
-
// Server confirmed deletion — reload history and exit selection mode
|
|
2033
|
-
selectionMode = false;
|
|
2034
|
-
selectedIds = {};
|
|
2035
|
-
var embSelectBtn = panel.querySelector('[data-testid="webchat-select-btn"]');
|
|
2036
|
-
if (embSelectBtn) {
|
|
2037
|
-
embSelectBtn.textContent = 'Select';
|
|
2038
|
-
embSelectBtn.classList.remove('active');
|
|
2039
|
-
}
|
|
2040
|
-
messages = [];
|
|
2041
|
-
// Re-request history
|
|
2042
|
-
if (connection) {
|
|
2043
|
-
connection.send({ type: 'history', threadName: sessionId, limit: 200 });
|
|
2044
|
-
}
|
|
2045
|
-
break;
|
|
2046
1696
|
}
|
|
2047
1697
|
}
|
|
2048
1698
|
|
|
@@ -2158,22 +1808,6 @@
|
|
|
2158
1808
|
});
|
|
2159
1809
|
}
|
|
2160
1810
|
|
|
2161
|
-
// Select button for embedded mode
|
|
2162
|
-
var embSelectBtn = panel.querySelector('[data-testid="webchat-select-btn"]');
|
|
2163
|
-
if (embSelectBtn) {
|
|
2164
|
-
embSelectBtn.addEventListener('click', function () {
|
|
2165
|
-
selectionMode = !selectionMode;
|
|
2166
|
-
selectedIds = {};
|
|
2167
|
-
embSelectBtn.textContent = selectionMode ? 'Done' : 'Select';
|
|
2168
|
-
if (selectionMode) {
|
|
2169
|
-
embSelectBtn.classList.add('active');
|
|
2170
|
-
} else {
|
|
2171
|
-
embSelectBtn.classList.remove('active');
|
|
2172
|
-
}
|
|
2173
|
-
renderMessages();
|
|
2174
|
-
});
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
1811
|
// Embedded mode: no auth panel handling needed (API key from attribute)
|
|
2178
1812
|
function startConnection() {
|
|
2179
1813
|
if (connection) {
|
|
@@ -2217,9 +1851,6 @@
|
|
|
2217
1851
|
// Thread list from server: [{ name, messageCount, lastActivity }]
|
|
2218
1852
|
var allThreads = [];
|
|
2219
1853
|
|
|
2220
|
-
// Unread threads: threadName -> true
|
|
2221
|
-
var unreadThreads = {};
|
|
2222
|
-
|
|
2223
1854
|
// Currently visible panel names (ordered, max 3)
|
|
2224
1855
|
var visibleThreads = [];
|
|
2225
1856
|
|
|
@@ -2237,8 +1868,6 @@
|
|
|
2237
1868
|
interjecting: false,
|
|
2238
1869
|
pendingAttachments: [],
|
|
2239
1870
|
historyLoaded: false,
|
|
2240
|
-
selectionMode: false,
|
|
2241
|
-
selectedIds: {},
|
|
2242
1871
|
};
|
|
2243
1872
|
}
|
|
2244
1873
|
return threadStates[threadName];
|
|
@@ -2503,9 +2132,7 @@
|
|
|
2503
2132
|
item.setAttribute('data-thread-name', name);
|
|
2504
2133
|
|
|
2505
2134
|
var dot = document.createElement('span');
|
|
2506
|
-
dot.className =
|
|
2507
|
-
? 'cumulus-thread-unread'
|
|
2508
|
-
: 'cumulus-thread-dot ' + (isActive ? 'active' : 'inactive');
|
|
2135
|
+
dot.className = 'cumulus-thread-dot ' + (isActive ? 'active' : 'inactive');
|
|
2509
2136
|
item.appendChild(dot);
|
|
2510
2137
|
|
|
2511
2138
|
var nameEl = document.createElement('span');
|
|
@@ -2528,13 +2155,6 @@
|
|
|
2528
2155
|
item.appendChild(countEl);
|
|
2529
2156
|
}
|
|
2530
2157
|
|
|
2531
|
-
// Right-click context menu
|
|
2532
|
-
item.addEventListener('contextmenu', function (e) {
|
|
2533
|
-
e.preventDefault();
|
|
2534
|
-
e.stopPropagation();
|
|
2535
|
-
showThreadContextMenu(name, e.clientX, e.clientY);
|
|
2536
|
-
});
|
|
2537
|
-
|
|
2538
2158
|
item.addEventListener('click', function (e) {
|
|
2539
2159
|
var multiSelect = e.metaKey || e.ctrlKey;
|
|
2540
2160
|
if (multiSelect) {
|
|
@@ -2547,118 +2167,8 @@
|
|
|
2547
2167
|
return item;
|
|
2548
2168
|
}
|
|
2549
2169
|
|
|
2550
|
-
// ── Thread context menu (right-click) ──
|
|
2551
|
-
function dismissContextMenu() {
|
|
2552
|
-
var existing = document.querySelector('.cumulus-context-menu');
|
|
2553
|
-
if (existing) existing.remove();
|
|
2554
|
-
document.removeEventListener('click', dismissContextMenu);
|
|
2555
|
-
document.removeEventListener('contextmenu', dismissContextMenu);
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
function showThreadContextMenu(threadName, x, y) {
|
|
2559
|
-
dismissContextMenu();
|
|
2560
|
-
|
|
2561
|
-
var menu = document.createElement('div');
|
|
2562
|
-
menu.className = 'cumulus-context-menu';
|
|
2563
|
-
menu.style.left = x + 'px';
|
|
2564
|
-
menu.style.top = y + 'px';
|
|
2565
|
-
|
|
2566
|
-
var deleteItem = document.createElement('button');
|
|
2567
|
-
deleteItem.className = 'cumulus-context-menu-item danger';
|
|
2568
|
-
deleteItem.textContent = 'Delete thread';
|
|
2569
|
-
deleteItem.setAttribute('data-testid', 'webchat-thread-delete');
|
|
2570
|
-
deleteItem.addEventListener('click', function () {
|
|
2571
|
-
dismissContextMenu();
|
|
2572
|
-
showThreadDeleteConfirm(threadName);
|
|
2573
|
-
});
|
|
2574
|
-
menu.appendChild(deleteItem);
|
|
2575
|
-
|
|
2576
|
-
document.body.appendChild(menu);
|
|
2577
|
-
|
|
2578
|
-
// Clamp to viewport
|
|
2579
|
-
var rect = menu.getBoundingClientRect();
|
|
2580
|
-
if (rect.right > window.innerWidth) menu.style.left = (window.innerWidth - rect.width - 4) + 'px';
|
|
2581
|
-
if (rect.bottom > window.innerHeight) menu.style.top = (window.innerHeight - rect.height - 4) + 'px';
|
|
2582
|
-
|
|
2583
|
-
// Dismiss on next click or right-click anywhere
|
|
2584
|
-
setTimeout(function () {
|
|
2585
|
-
document.addEventListener('click', dismissContextMenu);
|
|
2586
|
-
document.addEventListener('contextmenu', dismissContextMenu);
|
|
2587
|
-
}, 0);
|
|
2588
|
-
}
|
|
2589
|
-
|
|
2590
|
-
// ── Thread delete confirmation ──
|
|
2591
|
-
function showThreadDeleteConfirm(threadName) {
|
|
2592
|
-
// Remove any existing confirm dialogs
|
|
2593
|
-
var existing = document.querySelector('.cumulus-confirm-dialog[data-context="thread-delete"]');
|
|
2594
|
-
if (existing) {
|
|
2595
|
-
existing.remove();
|
|
2596
|
-
return;
|
|
2597
|
-
}
|
|
2598
|
-
|
|
2599
|
-
// Build inline confirm dialog attached to the sidebar scroll area
|
|
2600
|
-
var dialog = document.createElement('div');
|
|
2601
|
-
dialog.className = 'cumulus-confirm-dialog';
|
|
2602
|
-
dialog.setAttribute('data-context', 'thread-delete');
|
|
2603
|
-
dialog.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.6); z-index: 200; display: flex; align-items: center; justify-content: center;';
|
|
2604
|
-
|
|
2605
|
-
var box = document.createElement('div');
|
|
2606
|
-
box.className = 'cumulus-confirm-dialog-box';
|
|
2607
|
-
|
|
2608
|
-
var title = document.createElement('div');
|
|
2609
|
-
title.className = 'cumulus-confirm-dialog-title';
|
|
2610
|
-
title.textContent = 'Delete Thread';
|
|
2611
|
-
box.appendChild(title);
|
|
2612
|
-
|
|
2613
|
-
var text = document.createElement('div');
|
|
2614
|
-
text.className = 'cumulus-confirm-dialog-text';
|
|
2615
|
-
text.textContent = 'Delete "' + threadName + '"?';
|
|
2616
|
-
box.appendChild(text);
|
|
2617
|
-
|
|
2618
|
-
var warn = document.createElement('div');
|
|
2619
|
-
warn.className = 'cumulus-confirm-dialog-warn';
|
|
2620
|
-
warn.textContent = 'All messages and history will be permanently removed.';
|
|
2621
|
-
box.appendChild(warn);
|
|
2622
|
-
|
|
2623
|
-
var actions = document.createElement('div');
|
|
2624
|
-
actions.className = 'cumulus-confirm-dialog-actions';
|
|
2625
|
-
|
|
2626
|
-
var cancelBtn = document.createElement('button');
|
|
2627
|
-
cancelBtn.className = 'cumulus-confirm-dialog-cancel';
|
|
2628
|
-
cancelBtn.textContent = 'Cancel';
|
|
2629
|
-
cancelBtn.addEventListener('click', function () {
|
|
2630
|
-
dialog.remove();
|
|
2631
|
-
});
|
|
2632
|
-
actions.appendChild(cancelBtn);
|
|
2633
|
-
|
|
2634
|
-
var confirmBtn = document.createElement('button');
|
|
2635
|
-
confirmBtn.className = 'cumulus-confirm-dialog-confirm';
|
|
2636
|
-
confirmBtn.setAttribute('data-testid', 'webchat-thread-delete-confirm');
|
|
2637
|
-
confirmBtn.textContent = 'Delete';
|
|
2638
|
-
confirmBtn.addEventListener('click', function () {
|
|
2639
|
-
confirmBtn.disabled = true;
|
|
2640
|
-
confirmBtn.textContent = 'Deleting\u2026';
|
|
2641
|
-
if (connection) {
|
|
2642
|
-
connection.send({ type: 'delete_thread', threadName: threadName });
|
|
2643
|
-
}
|
|
2644
|
-
dialog.remove();
|
|
2645
|
-
});
|
|
2646
|
-
actions.appendChild(confirmBtn);
|
|
2647
|
-
|
|
2648
|
-
box.appendChild(actions);
|
|
2649
|
-
dialog.appendChild(box);
|
|
2650
|
-
|
|
2651
|
-
// Dismiss on backdrop click
|
|
2652
|
-
dialog.addEventListener('click', function (e) {
|
|
2653
|
-
if (e.target === dialog) dialog.remove();
|
|
2654
|
-
});
|
|
2655
|
-
|
|
2656
|
-
document.body.appendChild(dialog);
|
|
2657
|
-
}
|
|
2658
|
-
|
|
2659
2170
|
// ── Panel management ──
|
|
2660
2171
|
function soloThread(name) {
|
|
2661
|
-
delete unreadThreads[name];
|
|
2662
2172
|
visibleThreads = [name];
|
|
2663
2173
|
renderSidebar();
|
|
2664
2174
|
renderContentArea();
|
|
@@ -2667,7 +2177,6 @@
|
|
|
2667
2177
|
}
|
|
2668
2178
|
|
|
2669
2179
|
function togglePanelThread(name) {
|
|
2670
|
-
delete unreadThreads[name];
|
|
2671
2180
|
// On mobile, always solo (no side-by-side)
|
|
2672
2181
|
if (isMobile()) {
|
|
2673
2182
|
soloThread(name);
|
|
@@ -2798,16 +2307,6 @@
|
|
|
2798
2307
|
});
|
|
2799
2308
|
actions.appendChild(revertBtn);
|
|
2800
2309
|
|
|
2801
|
-
var selectBtn = document.createElement('button');
|
|
2802
|
-
selectBtn.className = 'cumulus-panel-action-btn';
|
|
2803
|
-
selectBtn.setAttribute('data-testid', 'webchat-select-btn');
|
|
2804
|
-
selectBtn.setAttribute('title', 'Select messages to delete');
|
|
2805
|
-
selectBtn.textContent = 'Select';
|
|
2806
|
-
selectBtn.addEventListener('click', function () {
|
|
2807
|
-
toggleSelectionMode();
|
|
2808
|
-
});
|
|
2809
|
-
actions.appendChild(selectBtn);
|
|
2810
|
-
|
|
2811
2310
|
panelHeader.appendChild(actions);
|
|
2812
2311
|
|
|
2813
2312
|
var closeBtn = document.createElement('button');
|
|
@@ -2876,11 +2375,7 @@
|
|
|
2876
2375
|
|
|
2877
2376
|
// ── Panel-local render functions ──
|
|
2878
2377
|
function scrollToBottom() {
|
|
2879
|
-
|
|
2880
|
-
requestAnimationFrame(function () {
|
|
2881
|
-
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
2882
|
-
});
|
|
2883
|
-
});
|
|
2378
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
2884
2379
|
}
|
|
2885
2380
|
|
|
2886
2381
|
function isWideUserMessage(content) {
|
|
@@ -2949,51 +2444,20 @@
|
|
|
2949
2444
|
|
|
2950
2445
|
function renderPanelMessages() {
|
|
2951
2446
|
messagesEl.innerHTML = '';
|
|
2952
|
-
// Apply selection mode class to messages container
|
|
2953
|
-
if (state.selectionMode) {
|
|
2954
|
-
messagesEl.classList.add('cumulus-selection-mode');
|
|
2955
|
-
} else {
|
|
2956
|
-
messagesEl.classList.remove('cumulus-selection-mode');
|
|
2957
|
-
}
|
|
2958
2447
|
if (state.messages.length === 0 && !state.streaming) {
|
|
2959
2448
|
messagesEl.innerHTML =
|
|
2960
2449
|
'<div class="cumulus-empty">Send a message to start chatting</div>';
|
|
2961
|
-
updateSelectionBar();
|
|
2962
2450
|
return;
|
|
2963
2451
|
}
|
|
2964
2452
|
for (var i = 0; i < state.messages.length; i++) {
|
|
2965
2453
|
var msg = state.messages[i];
|
|
2966
2454
|
var row = document.createElement('div');
|
|
2967
2455
|
row.className = 'cumulus-msg-row';
|
|
2968
|
-
// Add checkbox if in selection mode and message has an id
|
|
2969
|
-
if (state.selectionMode && msg.id) {
|
|
2970
|
-
var cb = document.createElement('input');
|
|
2971
|
-
cb.type = 'checkbox';
|
|
2972
|
-
cb.className = 'cumulus-msg-checkbox';
|
|
2973
|
-
cb.checked = !!state.selectedIds[msg.id];
|
|
2974
|
-
(function (msgId) {
|
|
2975
|
-
cb.addEventListener('change', function () {
|
|
2976
|
-
if (cb.checked) {
|
|
2977
|
-
state.selectedIds[msgId] = true;
|
|
2978
|
-
} else {
|
|
2979
|
-
delete state.selectedIds[msgId];
|
|
2980
|
-
}
|
|
2981
|
-
updateSelectionBar();
|
|
2982
|
-
});
|
|
2983
|
-
})(msg.id);
|
|
2984
|
-
row.appendChild(cb);
|
|
2985
|
-
}
|
|
2986
2456
|
if (msg.role === 'user') {
|
|
2987
|
-
|
|
2988
|
-
if (agent) {
|
|
2989
|
-
row.appendChild(buildAgentMsgEl(agent));
|
|
2990
|
-
} else {
|
|
2991
|
-
row.appendChild(buildUserMsgEl(msg));
|
|
2992
|
-
}
|
|
2457
|
+
row.appendChild(buildUserMsgEl(msg));
|
|
2993
2458
|
} else {
|
|
2994
2459
|
row.appendChild(buildAssistantMsgEl(msg.content, false));
|
|
2995
2460
|
}
|
|
2996
|
-
appendTimestamp(row, msg.timestamp);
|
|
2997
2461
|
messagesEl.appendChild(row);
|
|
2998
2462
|
}
|
|
2999
2463
|
if (state.streaming) {
|
|
@@ -3003,128 +2467,6 @@
|
|
|
3003
2467
|
messagesEl.appendChild(row);
|
|
3004
2468
|
}
|
|
3005
2469
|
scrollToBottom();
|
|
3006
|
-
updateSelectionBar();
|
|
3007
|
-
}
|
|
3008
|
-
|
|
3009
|
-
function updateSelectionBar() {
|
|
3010
|
-
// Remove existing bar
|
|
3011
|
-
var existingBar = panel.querySelector('.cumulus-selection-bar');
|
|
3012
|
-
if (existingBar) existingBar.remove();
|
|
3013
|
-
if (!state.selectionMode) return;
|
|
3014
|
-
|
|
3015
|
-
var selectedCount = Object.keys(state.selectedIds).length;
|
|
3016
|
-
var selectableCount = state.messages.filter(function (m) { return !!m.id; }).length;
|
|
3017
|
-
|
|
3018
|
-
var bar = document.createElement('div');
|
|
3019
|
-
bar.className = 'cumulus-selection-bar';
|
|
3020
|
-
|
|
3021
|
-
var countEl = document.createElement('span');
|
|
3022
|
-
countEl.className = 'cumulus-selection-count';
|
|
3023
|
-
countEl.textContent = selectedCount + ' selected';
|
|
3024
|
-
bar.appendChild(countEl);
|
|
3025
|
-
|
|
3026
|
-
var selectAllBtn = document.createElement('button');
|
|
3027
|
-
selectAllBtn.className = 'cumulus-selection-select-all-btn';
|
|
3028
|
-
selectAllBtn.textContent = selectedCount === selectableCount && selectableCount > 0 ? 'Deselect All' : 'Select All';
|
|
3029
|
-
selectAllBtn.addEventListener('click', function () {
|
|
3030
|
-
if (selectedCount === selectableCount && selectableCount > 0) {
|
|
3031
|
-
// Deselect all
|
|
3032
|
-
state.selectedIds = {};
|
|
3033
|
-
} else {
|
|
3034
|
-
// Select all with IDs
|
|
3035
|
-
state.messages.forEach(function (m) {
|
|
3036
|
-
if (m.id) state.selectedIds[m.id] = true;
|
|
3037
|
-
});
|
|
3038
|
-
}
|
|
3039
|
-
renderPanelMessages();
|
|
3040
|
-
});
|
|
3041
|
-
bar.appendChild(selectAllBtn);
|
|
3042
|
-
|
|
3043
|
-
var deleteBtn = document.createElement('button');
|
|
3044
|
-
deleteBtn.className = 'cumulus-selection-delete-btn';
|
|
3045
|
-
deleteBtn.textContent = 'Delete';
|
|
3046
|
-
deleteBtn.disabled = selectedCount === 0;
|
|
3047
|
-
deleteBtn.addEventListener('click', function () {
|
|
3048
|
-
if (selectedCount === 0) return;
|
|
3049
|
-
showDeleteMessagesConfirm(threadName, panel, Object.keys(state.selectedIds));
|
|
3050
|
-
});
|
|
3051
|
-
bar.appendChild(deleteBtn);
|
|
3052
|
-
|
|
3053
|
-
// Insert before input area
|
|
3054
|
-
var inputAreaEl = panel.querySelector('.cumulus-input-area');
|
|
3055
|
-
if (inputAreaEl) {
|
|
3056
|
-
panel.insertBefore(bar, inputAreaEl);
|
|
3057
|
-
} else {
|
|
3058
|
-
panel.appendChild(bar);
|
|
3059
|
-
}
|
|
3060
|
-
}
|
|
3061
|
-
|
|
3062
|
-
function toggleSelectionMode() {
|
|
3063
|
-
state.selectionMode = !state.selectionMode;
|
|
3064
|
-
state.selectedIds = {};
|
|
3065
|
-
selectBtn.textContent = state.selectionMode ? 'Done' : 'Select';
|
|
3066
|
-
if (state.selectionMode) {
|
|
3067
|
-
selectBtn.classList.add('active');
|
|
3068
|
-
} else {
|
|
3069
|
-
selectBtn.classList.remove('active');
|
|
3070
|
-
}
|
|
3071
|
-
renderPanelMessages();
|
|
3072
|
-
}
|
|
3073
|
-
|
|
3074
|
-
function showDeleteMessagesConfirm(tName, panelEl, ids) {
|
|
3075
|
-
// Remove any existing confirm dialog
|
|
3076
|
-
var existing = panelEl.querySelector('.cumulus-confirm-dialog');
|
|
3077
|
-
if (existing) existing.remove();
|
|
3078
|
-
|
|
3079
|
-
var dialog = document.createElement('div');
|
|
3080
|
-
dialog.className = 'cumulus-confirm-dialog';
|
|
3081
|
-
|
|
3082
|
-
var box = document.createElement('div');
|
|
3083
|
-
box.className = 'cumulus-confirm-dialog-box';
|
|
3084
|
-
|
|
3085
|
-
var title = document.createElement('div');
|
|
3086
|
-
title.className = 'cumulus-confirm-dialog-title';
|
|
3087
|
-
title.textContent = 'Delete Messages';
|
|
3088
|
-
box.appendChild(title);
|
|
3089
|
-
|
|
3090
|
-
var text = document.createElement('div');
|
|
3091
|
-
text.className = 'cumulus-confirm-dialog-text';
|
|
3092
|
-
text.textContent = ids.length + ' message' + (ids.length === 1 ? '' : 's') + ' will be permanently deleted.';
|
|
3093
|
-
box.appendChild(text);
|
|
3094
|
-
|
|
3095
|
-
var warn = document.createElement('div');
|
|
3096
|
-
warn.className = 'cumulus-confirm-dialog-warn';
|
|
3097
|
-
warn.textContent = 'This cannot be undone.';
|
|
3098
|
-
box.appendChild(warn);
|
|
3099
|
-
|
|
3100
|
-
var actions = document.createElement('div');
|
|
3101
|
-
actions.className = 'cumulus-confirm-dialog-actions';
|
|
3102
|
-
|
|
3103
|
-
var cancelBtn = document.createElement('button');
|
|
3104
|
-
cancelBtn.className = 'cumulus-confirm-dialog-cancel';
|
|
3105
|
-
cancelBtn.textContent = 'Cancel';
|
|
3106
|
-
cancelBtn.addEventListener('click', function () {
|
|
3107
|
-
dialog.remove();
|
|
3108
|
-
});
|
|
3109
|
-
actions.appendChild(cancelBtn);
|
|
3110
|
-
|
|
3111
|
-
var confirmBtn = document.createElement('button');
|
|
3112
|
-
confirmBtn.className = 'cumulus-confirm-dialog-confirm';
|
|
3113
|
-
confirmBtn.setAttribute('data-testid', 'webchat-delete-messages-confirm');
|
|
3114
|
-
confirmBtn.textContent = 'Delete';
|
|
3115
|
-
confirmBtn.addEventListener('click', function () {
|
|
3116
|
-
confirmBtn.disabled = true;
|
|
3117
|
-
confirmBtn.textContent = 'Deleting\u2026';
|
|
3118
|
-
if (connection) {
|
|
3119
|
-
connection.send({ type: 'delete_messages', threadName: tName, messageIds: ids });
|
|
3120
|
-
}
|
|
3121
|
-
dialog.remove();
|
|
3122
|
-
});
|
|
3123
|
-
actions.appendChild(confirmBtn);
|
|
3124
|
-
|
|
3125
|
-
box.appendChild(actions);
|
|
3126
|
-
dialog.appendChild(box);
|
|
3127
|
-
panelEl.appendChild(dialog);
|
|
3128
2470
|
}
|
|
3129
2471
|
|
|
3130
2472
|
function updatePanelSendBtn() {
|
|
@@ -3215,9 +2557,6 @@
|
|
|
3215
2557
|
state._renderMessages = renderPanelMessages;
|
|
3216
2558
|
state._updateSendBtn = updatePanelSendBtn;
|
|
3217
2559
|
|
|
3218
|
-
// Initial render (messages may already be loaded from a previous view)
|
|
3219
|
-
renderPanelMessages();
|
|
3220
|
-
|
|
3221
2560
|
// ── Send message for this panel ──
|
|
3222
2561
|
function sendPanelMessage() {
|
|
3223
2562
|
var text = inputEl.value.trim();
|
|
@@ -3410,12 +2749,14 @@
|
|
|
3410
2749
|
var filePath = addInput.value.trim();
|
|
3411
2750
|
if (!filePath) return;
|
|
3412
2751
|
connection &&
|
|
3413
|
-
connection.send(
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
2752
|
+
connection.send(
|
|
2753
|
+
JSON.stringify({
|
|
2754
|
+
type: 'include_add',
|
|
2755
|
+
threadName: threadName,
|
|
2756
|
+
filePath: filePath,
|
|
2757
|
+
scope: currentScope,
|
|
2758
|
+
})
|
|
2759
|
+
);
|
|
3419
2760
|
addInput.value = '';
|
|
3420
2761
|
});
|
|
3421
2762
|
|
|
@@ -3439,7 +2780,7 @@
|
|
|
3439
2780
|
|
|
3440
2781
|
// Request the list
|
|
3441
2782
|
connection &&
|
|
3442
|
-
connection.send({ type: 'include_list', threadName: threadName });
|
|
2783
|
+
connection.send(JSON.stringify({ type: 'include_list', threadName: threadName }));
|
|
3443
2784
|
}
|
|
3444
2785
|
|
|
3445
2786
|
function renderIncludeList(panel, threadName, files) {
|
|
@@ -3476,11 +2817,13 @@
|
|
|
3476
2817
|
removeBtn.setAttribute('title', 'Remove');
|
|
3477
2818
|
removeBtn.addEventListener('click', function () {
|
|
3478
2819
|
connection &&
|
|
3479
|
-
connection.send(
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
2820
|
+
connection.send(
|
|
2821
|
+
JSON.stringify({
|
|
2822
|
+
type: 'include_remove',
|
|
2823
|
+
threadName: threadName,
|
|
2824
|
+
filePath: f.path,
|
|
2825
|
+
})
|
|
2826
|
+
);
|
|
3484
2827
|
});
|
|
3485
2828
|
item.appendChild(removeBtn);
|
|
3486
2829
|
|
|
@@ -3526,7 +2869,7 @@
|
|
|
3526
2869
|
|
|
3527
2870
|
// Request the turn list
|
|
3528
2871
|
connection &&
|
|
3529
|
-
connection.send({ type: 'revert_list', threadName: threadName });
|
|
2872
|
+
connection.send(JSON.stringify({ type: 'revert_list', threadName: threadName }));
|
|
3530
2873
|
}
|
|
3531
2874
|
|
|
3532
2875
|
function renderRevertList(panel, threadName, turns) {
|
|
@@ -3606,7 +2949,7 @@
|
|
|
3606
2949
|
cancelBtn.addEventListener('click', function () {
|
|
3607
2950
|
// Re-request list
|
|
3608
2951
|
connection &&
|
|
3609
|
-
connection.send({ type: 'revert_list', threadName: threadName });
|
|
2952
|
+
connection.send(JSON.stringify({ type: 'revert_list', threadName: threadName }));
|
|
3610
2953
|
});
|
|
3611
2954
|
actions.appendChild(cancelBtn);
|
|
3612
2955
|
|
|
@@ -3618,11 +2961,13 @@
|
|
|
3618
2961
|
revertBtn.disabled = true;
|
|
3619
2962
|
revertBtn.textContent = 'Reverting\u2026';
|
|
3620
2963
|
connection &&
|
|
3621
|
-
connection.send(
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
2964
|
+
connection.send(
|
|
2965
|
+
JSON.stringify({
|
|
2966
|
+
type: 'revert_execute',
|
|
2967
|
+
threadName: threadName,
|
|
2968
|
+
targetMessageId: turn.userMessageId,
|
|
2969
|
+
})
|
|
2970
|
+
);
|
|
3626
2971
|
});
|
|
3627
2972
|
actions.appendChild(revertBtn);
|
|
3628
2973
|
|
|
@@ -3639,14 +2984,98 @@
|
|
|
3639
2984
|
return h + ':' + (m < 10 ? '0' : '') + m + ' ' + ampm;
|
|
3640
2985
|
}
|
|
3641
2986
|
|
|
2987
|
+
// ── Push notification subscription ──
|
|
2988
|
+
function registerPushNotifications() {
|
|
2989
|
+
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
|
|
2990
|
+
console.log('[Cumulus] Push notifications not supported');
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
navigator.serviceWorker
|
|
2995
|
+
.register('/sw.js')
|
|
2996
|
+
.then(function (registration) {
|
|
2997
|
+
console.log('[Cumulus] Service worker registered');
|
|
2998
|
+
|
|
2999
|
+
// Check existing subscription
|
|
3000
|
+
return registration.pushManager.getSubscription().then(function (existing) {
|
|
3001
|
+
if (existing) {
|
|
3002
|
+
// Already subscribed — send to server in case it's new/different
|
|
3003
|
+
sendPushSubscription(existing);
|
|
3004
|
+
return;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
// Get VAPID key from server
|
|
3008
|
+
var loc = window.location;
|
|
3009
|
+
var apiUrl = loc.protocol + '//' + loc.host;
|
|
3010
|
+
fetch(apiUrl + '/api/push/vapid-key')
|
|
3011
|
+
.then(function (r) {
|
|
3012
|
+
return r.json();
|
|
3013
|
+
})
|
|
3014
|
+
.then(function (data) {
|
|
3015
|
+
if (!data.publicKey) {
|
|
3016
|
+
console.log('[Cumulus] Push not configured on server');
|
|
3017
|
+
return;
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
// Request permission and subscribe
|
|
3021
|
+
return registration.pushManager
|
|
3022
|
+
.subscribe({
|
|
3023
|
+
userVisibleOnly: true,
|
|
3024
|
+
applicationServerKey: urlBase64ToUint8Array(data.publicKey),
|
|
3025
|
+
})
|
|
3026
|
+
.then(function (subscription) {
|
|
3027
|
+
console.log('[Cumulus] Push subscription created');
|
|
3028
|
+
sendPushSubscription(subscription);
|
|
3029
|
+
});
|
|
3030
|
+
})
|
|
3031
|
+
.catch(function (err) {
|
|
3032
|
+
console.warn('[Cumulus] Push subscription failed:', err);
|
|
3033
|
+
});
|
|
3034
|
+
});
|
|
3035
|
+
})
|
|
3036
|
+
.catch(function (err) {
|
|
3037
|
+
console.warn('[Cumulus] Service worker registration failed:', err);
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
function sendPushSubscription(subscription) {
|
|
3042
|
+
var loc = window.location;
|
|
3043
|
+
var apiUrl = loc.protocol + '//' + loc.host;
|
|
3044
|
+
var raw = subscription.toJSON();
|
|
3045
|
+
|
|
3046
|
+
fetch(apiUrl + '/api/push/subscribe', {
|
|
3047
|
+
method: 'POST',
|
|
3048
|
+
headers: {
|
|
3049
|
+
'Content-Type': 'application/json',
|
|
3050
|
+
'X-API-Key': activeApiKey,
|
|
3051
|
+
},
|
|
3052
|
+
body: JSON.stringify({
|
|
3053
|
+
endpoint: raw.endpoint,
|
|
3054
|
+
keys: raw.keys,
|
|
3055
|
+
label: navigator.userAgent.indexOf('iPhone') !== -1 ? 'iPhone' : 'Browser',
|
|
3056
|
+
}),
|
|
3057
|
+
}).catch(function (err) {
|
|
3058
|
+
console.warn('[Cumulus] Failed to send push subscription:', err);
|
|
3059
|
+
});
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
function urlBase64ToUint8Array(base64String) {
|
|
3063
|
+
var padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
|
3064
|
+
var base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
|
3065
|
+
var rawData = atob(base64);
|
|
3066
|
+
var outputArray = new Uint8Array(rawData.length);
|
|
3067
|
+
for (var i = 0; i < rawData.length; ++i) {
|
|
3068
|
+
outputArray[i] = rawData.charCodeAt(i);
|
|
3069
|
+
}
|
|
3070
|
+
return outputArray;
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3642
3073
|
// ── Message router ──
|
|
3643
3074
|
function handleServerMessage(data) {
|
|
3644
|
-
if (data.type !== 'token') {
|
|
3645
|
-
console.log('[CumulusChat] WS recv:', data.type, data.threadName || '', data);
|
|
3646
|
-
}
|
|
3647
3075
|
switch (data.type) {
|
|
3648
3076
|
case 'auth_ok':
|
|
3649
3077
|
showAppView();
|
|
3078
|
+
registerPushNotifications();
|
|
3650
3079
|
break;
|
|
3651
3080
|
|
|
3652
3081
|
case 'auth_error':
|
|
@@ -3688,50 +3117,12 @@
|
|
|
3688
3117
|
}
|
|
3689
3118
|
break;
|
|
3690
3119
|
|
|
3691
|
-
case 'thread_deleted':
|
|
3692
|
-
// Server confirms thread deleted; remove from sidebar and panels
|
|
3693
|
-
if (data.threadName) {
|
|
3694
|
-
allThreads = allThreads.filter(function (t) {
|
|
3695
|
-
return t.name !== data.threadName;
|
|
3696
|
-
});
|
|
3697
|
-
delete threadStates[data.threadName];
|
|
3698
|
-
removeThreadFromView(data.threadName);
|
|
3699
|
-
renderSidebar();
|
|
3700
|
-
}
|
|
3701
|
-
break;
|
|
3702
|
-
|
|
3703
|
-
case 'messages_deleted':
|
|
3704
|
-
// Server confirms messages deleted; reload history for that thread
|
|
3705
|
-
if (data.threadName) {
|
|
3706
|
-
var dState = getThreadState(data.threadName);
|
|
3707
|
-
dState.messages = [];
|
|
3708
|
-
dState.historyLoaded = false;
|
|
3709
|
-
dState.selectionMode = false;
|
|
3710
|
-
dState.selectedIds = {};
|
|
3711
|
-
// Exit selection mode on visible panel
|
|
3712
|
-
var dPanel = document.querySelector('[data-thread-panel="' + data.threadName + '"]');
|
|
3713
|
-
if (dPanel) {
|
|
3714
|
-
var dMsgs = dPanel.querySelector('.cumulus-messages');
|
|
3715
|
-
if (dMsgs) dMsgs.classList.remove('cumulus-selection-mode');
|
|
3716
|
-
var dBar = dPanel.querySelector('.cumulus-selection-bar');
|
|
3717
|
-
if (dBar) dBar.remove();
|
|
3718
|
-
var dSelectBtn = dPanel.querySelector('[data-testid="webchat-select-btn"]');
|
|
3719
|
-
if (dSelectBtn) {
|
|
3720
|
-
dSelectBtn.textContent = 'Select';
|
|
3721
|
-
dSelectBtn.classList.remove('active');
|
|
3722
|
-
}
|
|
3723
|
-
}
|
|
3724
|
-
connection &&
|
|
3725
|
-
connection.send({ type: 'history', threadName: data.threadName, limit: 200 });
|
|
3726
|
-
}
|
|
3727
|
-
break;
|
|
3728
|
-
|
|
3729
3120
|
case 'history':
|
|
3730
3121
|
if (data.threadName) {
|
|
3731
3122
|
var state = getThreadState(data.threadName);
|
|
3732
3123
|
if (data.messages && data.messages.length > 0) {
|
|
3733
3124
|
state.messages = data.messages.map(function (m) {
|
|
3734
|
-
return { id: m.id, role: m.role, content: m.content
|
|
3125
|
+
return { id: m.id, role: m.role, content: m.content };
|
|
3735
3126
|
});
|
|
3736
3127
|
}
|
|
3737
3128
|
refreshThreadPanel(data.threadName);
|
|
@@ -3810,22 +3201,6 @@
|
|
|
3810
3201
|
}
|
|
3811
3202
|
break;
|
|
3812
3203
|
|
|
3813
|
-
case 'new_messages':
|
|
3814
|
-
// Agent inject completed — append new messages to the thread and re-render
|
|
3815
|
-
if (data.threadName && data.messages && data.messages.length > 0) {
|
|
3816
|
-
var state = getThreadState(data.threadName);
|
|
3817
|
-
for (var nm = 0; nm < data.messages.length; nm++) {
|
|
3818
|
-
state.messages.push({
|
|
3819
|
-
id: data.messages[nm].id,
|
|
3820
|
-
role: data.messages[nm].role,
|
|
3821
|
-
content: data.messages[nm].content,
|
|
3822
|
-
});
|
|
3823
|
-
}
|
|
3824
|
-
updateThreadActivity(data.threadName);
|
|
3825
|
-
refreshThreadPanel(data.threadName);
|
|
3826
|
-
}
|
|
3827
|
-
break;
|
|
3828
|
-
|
|
3829
3204
|
// ── Include/Revert responses ──
|
|
3830
3205
|
case 'include_list':
|
|
3831
3206
|
if (data.threadName && data.files) {
|
|
@@ -3858,11 +3233,13 @@
|
|
|
3858
3233
|
tState.historyLoaded = false;
|
|
3859
3234
|
// Re-request history
|
|
3860
3235
|
connection &&
|
|
3861
|
-
connection.send(
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3236
|
+
connection.send(
|
|
3237
|
+
JSON.stringify({
|
|
3238
|
+
type: 'history',
|
|
3239
|
+
threadName: data.threadName,
|
|
3240
|
+
limit: 200,
|
|
3241
|
+
})
|
|
3242
|
+
);
|
|
3866
3243
|
if (overlay) overlay.remove();
|
|
3867
3244
|
} else {
|
|
3868
3245
|
// Show error in overlay
|
|
@@ -3886,10 +3263,6 @@
|
|
|
3886
3263
|
break;
|
|
3887
3264
|
}
|
|
3888
3265
|
}
|
|
3889
|
-
// Mark unread if thread is not currently visible
|
|
3890
|
-
if (visibleThreads.indexOf(threadName) === -1) {
|
|
3891
|
-
unreadThreads[threadName] = true;
|
|
3892
|
-
}
|
|
3893
3266
|
// Re-render sidebar to reflect new sort order / move thread up
|
|
3894
3267
|
renderSidebar();
|
|
3895
3268
|
}
|
|
@@ -4042,7 +3415,5 @@
|
|
|
4042
3415
|
}
|
|
4043
3416
|
|
|
4044
3417
|
window.CumulusChat = widget;
|
|
4045
|
-
window.CumulusChat.version = '0.27.15';
|
|
4046
|
-
console.log('[CumulusChat] Widget loaded, version ' + window.CumulusChat.version);
|
|
4047
3418
|
}
|
|
4048
3419
|
})();
|