@luckydraw/cumulus 0.27.17 → 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 +125 -759
- 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];
|
|
@@ -2519,13 +2148,6 @@
|
|
|
2519
2148
|
item.appendChild(folderEl);
|
|
2520
2149
|
}
|
|
2521
2150
|
|
|
2522
|
-
// Unread indicator
|
|
2523
|
-
if (unreadThreads[name]) {
|
|
2524
|
-
var unreadDot = document.createElement('span');
|
|
2525
|
-
unreadDot.className = 'cumulus-thread-unread';
|
|
2526
|
-
item.appendChild(unreadDot);
|
|
2527
|
-
}
|
|
2528
|
-
|
|
2529
2151
|
if (messageCount !== undefined && messageCount !== null) {
|
|
2530
2152
|
var countEl = document.createElement('span');
|
|
2531
2153
|
countEl.className = 'cumulus-thread-count';
|
|
@@ -2533,13 +2155,6 @@
|
|
|
2533
2155
|
item.appendChild(countEl);
|
|
2534
2156
|
}
|
|
2535
2157
|
|
|
2536
|
-
// Right-click context menu
|
|
2537
|
-
item.addEventListener('contextmenu', function (e) {
|
|
2538
|
-
e.preventDefault();
|
|
2539
|
-
e.stopPropagation();
|
|
2540
|
-
showThreadContextMenu(name, e.clientX, e.clientY);
|
|
2541
|
-
});
|
|
2542
|
-
|
|
2543
2158
|
item.addEventListener('click', function (e) {
|
|
2544
2159
|
var multiSelect = e.metaKey || e.ctrlKey;
|
|
2545
2160
|
if (multiSelect) {
|
|
@@ -2552,118 +2167,8 @@
|
|
|
2552
2167
|
return item;
|
|
2553
2168
|
}
|
|
2554
2169
|
|
|
2555
|
-
// ── Thread context menu (right-click) ──
|
|
2556
|
-
function dismissContextMenu() {
|
|
2557
|
-
var existing = document.querySelector('.cumulus-context-menu');
|
|
2558
|
-
if (existing) existing.remove();
|
|
2559
|
-
document.removeEventListener('click', dismissContextMenu);
|
|
2560
|
-
document.removeEventListener('contextmenu', dismissContextMenu);
|
|
2561
|
-
}
|
|
2562
|
-
|
|
2563
|
-
function showThreadContextMenu(threadName, x, y) {
|
|
2564
|
-
dismissContextMenu();
|
|
2565
|
-
|
|
2566
|
-
var menu = document.createElement('div');
|
|
2567
|
-
menu.className = 'cumulus-context-menu';
|
|
2568
|
-
menu.style.left = x + 'px';
|
|
2569
|
-
menu.style.top = y + 'px';
|
|
2570
|
-
|
|
2571
|
-
var deleteItem = document.createElement('button');
|
|
2572
|
-
deleteItem.className = 'cumulus-context-menu-item danger';
|
|
2573
|
-
deleteItem.textContent = 'Delete thread';
|
|
2574
|
-
deleteItem.setAttribute('data-testid', 'webchat-thread-delete');
|
|
2575
|
-
deleteItem.addEventListener('click', function () {
|
|
2576
|
-
dismissContextMenu();
|
|
2577
|
-
showThreadDeleteConfirm(threadName);
|
|
2578
|
-
});
|
|
2579
|
-
menu.appendChild(deleteItem);
|
|
2580
|
-
|
|
2581
|
-
document.body.appendChild(menu);
|
|
2582
|
-
|
|
2583
|
-
// Clamp to viewport
|
|
2584
|
-
var rect = menu.getBoundingClientRect();
|
|
2585
|
-
if (rect.right > window.innerWidth) menu.style.left = (window.innerWidth - rect.width - 4) + 'px';
|
|
2586
|
-
if (rect.bottom > window.innerHeight) menu.style.top = (window.innerHeight - rect.height - 4) + 'px';
|
|
2587
|
-
|
|
2588
|
-
// Dismiss on next click or right-click anywhere
|
|
2589
|
-
setTimeout(function () {
|
|
2590
|
-
document.addEventListener('click', dismissContextMenu);
|
|
2591
|
-
document.addEventListener('contextmenu', dismissContextMenu);
|
|
2592
|
-
}, 0);
|
|
2593
|
-
}
|
|
2594
|
-
|
|
2595
|
-
// ── Thread delete confirmation ──
|
|
2596
|
-
function showThreadDeleteConfirm(threadName) {
|
|
2597
|
-
// Remove any existing confirm dialogs
|
|
2598
|
-
var existing = document.querySelector('.cumulus-confirm-dialog[data-context="thread-delete"]');
|
|
2599
|
-
if (existing) {
|
|
2600
|
-
existing.remove();
|
|
2601
|
-
return;
|
|
2602
|
-
}
|
|
2603
|
-
|
|
2604
|
-
// Build inline confirm dialog attached to the sidebar scroll area
|
|
2605
|
-
var dialog = document.createElement('div');
|
|
2606
|
-
dialog.className = 'cumulus-confirm-dialog';
|
|
2607
|
-
dialog.setAttribute('data-context', 'thread-delete');
|
|
2608
|
-
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;';
|
|
2609
|
-
|
|
2610
|
-
var box = document.createElement('div');
|
|
2611
|
-
box.className = 'cumulus-confirm-dialog-box';
|
|
2612
|
-
|
|
2613
|
-
var title = document.createElement('div');
|
|
2614
|
-
title.className = 'cumulus-confirm-dialog-title';
|
|
2615
|
-
title.textContent = 'Delete Thread';
|
|
2616
|
-
box.appendChild(title);
|
|
2617
|
-
|
|
2618
|
-
var text = document.createElement('div');
|
|
2619
|
-
text.className = 'cumulus-confirm-dialog-text';
|
|
2620
|
-
text.textContent = 'Delete "' + threadName + '"?';
|
|
2621
|
-
box.appendChild(text);
|
|
2622
|
-
|
|
2623
|
-
var warn = document.createElement('div');
|
|
2624
|
-
warn.className = 'cumulus-confirm-dialog-warn';
|
|
2625
|
-
warn.textContent = 'All messages and history will be permanently removed.';
|
|
2626
|
-
box.appendChild(warn);
|
|
2627
|
-
|
|
2628
|
-
var actions = document.createElement('div');
|
|
2629
|
-
actions.className = 'cumulus-confirm-dialog-actions';
|
|
2630
|
-
|
|
2631
|
-
var cancelBtn = document.createElement('button');
|
|
2632
|
-
cancelBtn.className = 'cumulus-confirm-dialog-cancel';
|
|
2633
|
-
cancelBtn.textContent = 'Cancel';
|
|
2634
|
-
cancelBtn.addEventListener('click', function () {
|
|
2635
|
-
dialog.remove();
|
|
2636
|
-
});
|
|
2637
|
-
actions.appendChild(cancelBtn);
|
|
2638
|
-
|
|
2639
|
-
var confirmBtn = document.createElement('button');
|
|
2640
|
-
confirmBtn.className = 'cumulus-confirm-dialog-confirm';
|
|
2641
|
-
confirmBtn.setAttribute('data-testid', 'webchat-thread-delete-confirm');
|
|
2642
|
-
confirmBtn.textContent = 'Delete';
|
|
2643
|
-
confirmBtn.addEventListener('click', function () {
|
|
2644
|
-
confirmBtn.disabled = true;
|
|
2645
|
-
confirmBtn.textContent = 'Deleting\u2026';
|
|
2646
|
-
if (connection) {
|
|
2647
|
-
connection.send({ type: 'delete_thread', threadName: threadName });
|
|
2648
|
-
}
|
|
2649
|
-
dialog.remove();
|
|
2650
|
-
});
|
|
2651
|
-
actions.appendChild(confirmBtn);
|
|
2652
|
-
|
|
2653
|
-
box.appendChild(actions);
|
|
2654
|
-
dialog.appendChild(box);
|
|
2655
|
-
|
|
2656
|
-
// Dismiss on backdrop click
|
|
2657
|
-
dialog.addEventListener('click', function (e) {
|
|
2658
|
-
if (e.target === dialog) dialog.remove();
|
|
2659
|
-
});
|
|
2660
|
-
|
|
2661
|
-
document.body.appendChild(dialog);
|
|
2662
|
-
}
|
|
2663
|
-
|
|
2664
2170
|
// ── Panel management ──
|
|
2665
2171
|
function soloThread(name) {
|
|
2666
|
-
delete unreadThreads[name];
|
|
2667
2172
|
visibleThreads = [name];
|
|
2668
2173
|
renderSidebar();
|
|
2669
2174
|
renderContentArea();
|
|
@@ -2672,7 +2177,6 @@
|
|
|
2672
2177
|
}
|
|
2673
2178
|
|
|
2674
2179
|
function togglePanelThread(name) {
|
|
2675
|
-
delete unreadThreads[name];
|
|
2676
2180
|
// On mobile, always solo (no side-by-side)
|
|
2677
2181
|
if (isMobile()) {
|
|
2678
2182
|
soloThread(name);
|
|
@@ -2803,16 +2307,6 @@
|
|
|
2803
2307
|
});
|
|
2804
2308
|
actions.appendChild(revertBtn);
|
|
2805
2309
|
|
|
2806
|
-
var selectBtn = document.createElement('button');
|
|
2807
|
-
selectBtn.className = 'cumulus-panel-action-btn';
|
|
2808
|
-
selectBtn.setAttribute('data-testid', 'webchat-select-btn');
|
|
2809
|
-
selectBtn.setAttribute('title', 'Select messages to delete');
|
|
2810
|
-
selectBtn.textContent = 'Select';
|
|
2811
|
-
selectBtn.addEventListener('click', function () {
|
|
2812
|
-
toggleSelectionMode();
|
|
2813
|
-
});
|
|
2814
|
-
actions.appendChild(selectBtn);
|
|
2815
|
-
|
|
2816
2310
|
panelHeader.appendChild(actions);
|
|
2817
2311
|
|
|
2818
2312
|
var closeBtn = document.createElement('button');
|
|
@@ -2881,11 +2375,7 @@
|
|
|
2881
2375
|
|
|
2882
2376
|
// ── Panel-local render functions ──
|
|
2883
2377
|
function scrollToBottom() {
|
|
2884
|
-
|
|
2885
|
-
requestAnimationFrame(function () {
|
|
2886
|
-
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
2887
|
-
});
|
|
2888
|
-
});
|
|
2378
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
2889
2379
|
}
|
|
2890
2380
|
|
|
2891
2381
|
function isWideUserMessage(content) {
|
|
@@ -2954,51 +2444,20 @@
|
|
|
2954
2444
|
|
|
2955
2445
|
function renderPanelMessages() {
|
|
2956
2446
|
messagesEl.innerHTML = '';
|
|
2957
|
-
// Apply selection mode class to messages container
|
|
2958
|
-
if (state.selectionMode) {
|
|
2959
|
-
messagesEl.classList.add('cumulus-selection-mode');
|
|
2960
|
-
} else {
|
|
2961
|
-
messagesEl.classList.remove('cumulus-selection-mode');
|
|
2962
|
-
}
|
|
2963
2447
|
if (state.messages.length === 0 && !state.streaming) {
|
|
2964
2448
|
messagesEl.innerHTML =
|
|
2965
2449
|
'<div class="cumulus-empty">Send a message to start chatting</div>';
|
|
2966
|
-
updateSelectionBar();
|
|
2967
2450
|
return;
|
|
2968
2451
|
}
|
|
2969
2452
|
for (var i = 0; i < state.messages.length; i++) {
|
|
2970
2453
|
var msg = state.messages[i];
|
|
2971
2454
|
var row = document.createElement('div');
|
|
2972
2455
|
row.className = 'cumulus-msg-row';
|
|
2973
|
-
// Add checkbox if in selection mode and message has an id
|
|
2974
|
-
if (state.selectionMode && msg.id) {
|
|
2975
|
-
var cb = document.createElement('input');
|
|
2976
|
-
cb.type = 'checkbox';
|
|
2977
|
-
cb.className = 'cumulus-msg-checkbox';
|
|
2978
|
-
cb.checked = !!state.selectedIds[msg.id];
|
|
2979
|
-
(function (msgId) {
|
|
2980
|
-
cb.addEventListener('change', function () {
|
|
2981
|
-
if (cb.checked) {
|
|
2982
|
-
state.selectedIds[msgId] = true;
|
|
2983
|
-
} else {
|
|
2984
|
-
delete state.selectedIds[msgId];
|
|
2985
|
-
}
|
|
2986
|
-
updateSelectionBar();
|
|
2987
|
-
});
|
|
2988
|
-
})(msg.id);
|
|
2989
|
-
row.appendChild(cb);
|
|
2990
|
-
}
|
|
2991
2456
|
if (msg.role === 'user') {
|
|
2992
|
-
|
|
2993
|
-
if (agent) {
|
|
2994
|
-
row.appendChild(buildAgentMsgEl(agent));
|
|
2995
|
-
} else {
|
|
2996
|
-
row.appendChild(buildUserMsgEl(msg));
|
|
2997
|
-
}
|
|
2457
|
+
row.appendChild(buildUserMsgEl(msg));
|
|
2998
2458
|
} else {
|
|
2999
2459
|
row.appendChild(buildAssistantMsgEl(msg.content, false));
|
|
3000
2460
|
}
|
|
3001
|
-
appendTimestamp(row, msg.timestamp);
|
|
3002
2461
|
messagesEl.appendChild(row);
|
|
3003
2462
|
}
|
|
3004
2463
|
if (state.streaming) {
|
|
@@ -3008,128 +2467,6 @@
|
|
|
3008
2467
|
messagesEl.appendChild(row);
|
|
3009
2468
|
}
|
|
3010
2469
|
scrollToBottom();
|
|
3011
|
-
updateSelectionBar();
|
|
3012
|
-
}
|
|
3013
|
-
|
|
3014
|
-
function updateSelectionBar() {
|
|
3015
|
-
// Remove existing bar
|
|
3016
|
-
var existingBar = panel.querySelector('.cumulus-selection-bar');
|
|
3017
|
-
if (existingBar) existingBar.remove();
|
|
3018
|
-
if (!state.selectionMode) return;
|
|
3019
|
-
|
|
3020
|
-
var selectedCount = Object.keys(state.selectedIds).length;
|
|
3021
|
-
var selectableCount = state.messages.filter(function (m) { return !!m.id; }).length;
|
|
3022
|
-
|
|
3023
|
-
var bar = document.createElement('div');
|
|
3024
|
-
bar.className = 'cumulus-selection-bar';
|
|
3025
|
-
|
|
3026
|
-
var countEl = document.createElement('span');
|
|
3027
|
-
countEl.className = 'cumulus-selection-count';
|
|
3028
|
-
countEl.textContent = selectedCount + ' selected';
|
|
3029
|
-
bar.appendChild(countEl);
|
|
3030
|
-
|
|
3031
|
-
var selectAllBtn = document.createElement('button');
|
|
3032
|
-
selectAllBtn.className = 'cumulus-selection-select-all-btn';
|
|
3033
|
-
selectAllBtn.textContent = selectedCount === selectableCount && selectableCount > 0 ? 'Deselect All' : 'Select All';
|
|
3034
|
-
selectAllBtn.addEventListener('click', function () {
|
|
3035
|
-
if (selectedCount === selectableCount && selectableCount > 0) {
|
|
3036
|
-
// Deselect all
|
|
3037
|
-
state.selectedIds = {};
|
|
3038
|
-
} else {
|
|
3039
|
-
// Select all with IDs
|
|
3040
|
-
state.messages.forEach(function (m) {
|
|
3041
|
-
if (m.id) state.selectedIds[m.id] = true;
|
|
3042
|
-
});
|
|
3043
|
-
}
|
|
3044
|
-
renderPanelMessages();
|
|
3045
|
-
});
|
|
3046
|
-
bar.appendChild(selectAllBtn);
|
|
3047
|
-
|
|
3048
|
-
var deleteBtn = document.createElement('button');
|
|
3049
|
-
deleteBtn.className = 'cumulus-selection-delete-btn';
|
|
3050
|
-
deleteBtn.textContent = 'Delete';
|
|
3051
|
-
deleteBtn.disabled = selectedCount === 0;
|
|
3052
|
-
deleteBtn.addEventListener('click', function () {
|
|
3053
|
-
if (selectedCount === 0) return;
|
|
3054
|
-
showDeleteMessagesConfirm(threadName, panel, Object.keys(state.selectedIds));
|
|
3055
|
-
});
|
|
3056
|
-
bar.appendChild(deleteBtn);
|
|
3057
|
-
|
|
3058
|
-
// Insert before input area
|
|
3059
|
-
var inputAreaEl = panel.querySelector('.cumulus-input-area');
|
|
3060
|
-
if (inputAreaEl) {
|
|
3061
|
-
panel.insertBefore(bar, inputAreaEl);
|
|
3062
|
-
} else {
|
|
3063
|
-
panel.appendChild(bar);
|
|
3064
|
-
}
|
|
3065
|
-
}
|
|
3066
|
-
|
|
3067
|
-
function toggleSelectionMode() {
|
|
3068
|
-
state.selectionMode = !state.selectionMode;
|
|
3069
|
-
state.selectedIds = {};
|
|
3070
|
-
selectBtn.textContent = state.selectionMode ? 'Done' : 'Select';
|
|
3071
|
-
if (state.selectionMode) {
|
|
3072
|
-
selectBtn.classList.add('active');
|
|
3073
|
-
} else {
|
|
3074
|
-
selectBtn.classList.remove('active');
|
|
3075
|
-
}
|
|
3076
|
-
renderPanelMessages();
|
|
3077
|
-
}
|
|
3078
|
-
|
|
3079
|
-
function showDeleteMessagesConfirm(tName, panelEl, ids) {
|
|
3080
|
-
// Remove any existing confirm dialog
|
|
3081
|
-
var existing = panelEl.querySelector('.cumulus-confirm-dialog');
|
|
3082
|
-
if (existing) existing.remove();
|
|
3083
|
-
|
|
3084
|
-
var dialog = document.createElement('div');
|
|
3085
|
-
dialog.className = 'cumulus-confirm-dialog';
|
|
3086
|
-
|
|
3087
|
-
var box = document.createElement('div');
|
|
3088
|
-
box.className = 'cumulus-confirm-dialog-box';
|
|
3089
|
-
|
|
3090
|
-
var title = document.createElement('div');
|
|
3091
|
-
title.className = 'cumulus-confirm-dialog-title';
|
|
3092
|
-
title.textContent = 'Delete Messages';
|
|
3093
|
-
box.appendChild(title);
|
|
3094
|
-
|
|
3095
|
-
var text = document.createElement('div');
|
|
3096
|
-
text.className = 'cumulus-confirm-dialog-text';
|
|
3097
|
-
text.textContent = ids.length + ' message' + (ids.length === 1 ? '' : 's') + ' will be permanently deleted.';
|
|
3098
|
-
box.appendChild(text);
|
|
3099
|
-
|
|
3100
|
-
var warn = document.createElement('div');
|
|
3101
|
-
warn.className = 'cumulus-confirm-dialog-warn';
|
|
3102
|
-
warn.textContent = 'This cannot be undone.';
|
|
3103
|
-
box.appendChild(warn);
|
|
3104
|
-
|
|
3105
|
-
var actions = document.createElement('div');
|
|
3106
|
-
actions.className = 'cumulus-confirm-dialog-actions';
|
|
3107
|
-
|
|
3108
|
-
var cancelBtn = document.createElement('button');
|
|
3109
|
-
cancelBtn.className = 'cumulus-confirm-dialog-cancel';
|
|
3110
|
-
cancelBtn.textContent = 'Cancel';
|
|
3111
|
-
cancelBtn.addEventListener('click', function () {
|
|
3112
|
-
dialog.remove();
|
|
3113
|
-
});
|
|
3114
|
-
actions.appendChild(cancelBtn);
|
|
3115
|
-
|
|
3116
|
-
var confirmBtn = document.createElement('button');
|
|
3117
|
-
confirmBtn.className = 'cumulus-confirm-dialog-confirm';
|
|
3118
|
-
confirmBtn.setAttribute('data-testid', 'webchat-delete-messages-confirm');
|
|
3119
|
-
confirmBtn.textContent = 'Delete';
|
|
3120
|
-
confirmBtn.addEventListener('click', function () {
|
|
3121
|
-
confirmBtn.disabled = true;
|
|
3122
|
-
confirmBtn.textContent = 'Deleting\u2026';
|
|
3123
|
-
if (connection) {
|
|
3124
|
-
connection.send({ type: 'delete_messages', threadName: tName, messageIds: ids });
|
|
3125
|
-
}
|
|
3126
|
-
dialog.remove();
|
|
3127
|
-
});
|
|
3128
|
-
actions.appendChild(confirmBtn);
|
|
3129
|
-
|
|
3130
|
-
box.appendChild(actions);
|
|
3131
|
-
dialog.appendChild(box);
|
|
3132
|
-
panelEl.appendChild(dialog);
|
|
3133
2470
|
}
|
|
3134
2471
|
|
|
3135
2472
|
function updatePanelSendBtn() {
|
|
@@ -3220,9 +2557,6 @@
|
|
|
3220
2557
|
state._renderMessages = renderPanelMessages;
|
|
3221
2558
|
state._updateSendBtn = updatePanelSendBtn;
|
|
3222
2559
|
|
|
3223
|
-
// Initial render (messages may already be loaded from a previous view)
|
|
3224
|
-
renderPanelMessages();
|
|
3225
|
-
|
|
3226
2560
|
// ── Send message for this panel ──
|
|
3227
2561
|
function sendPanelMessage() {
|
|
3228
2562
|
var text = inputEl.value.trim();
|
|
@@ -3415,12 +2749,14 @@
|
|
|
3415
2749
|
var filePath = addInput.value.trim();
|
|
3416
2750
|
if (!filePath) return;
|
|
3417
2751
|
connection &&
|
|
3418
|
-
connection.send(
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
2752
|
+
connection.send(
|
|
2753
|
+
JSON.stringify({
|
|
2754
|
+
type: 'include_add',
|
|
2755
|
+
threadName: threadName,
|
|
2756
|
+
filePath: filePath,
|
|
2757
|
+
scope: currentScope,
|
|
2758
|
+
})
|
|
2759
|
+
);
|
|
3424
2760
|
addInput.value = '';
|
|
3425
2761
|
});
|
|
3426
2762
|
|
|
@@ -3444,7 +2780,7 @@
|
|
|
3444
2780
|
|
|
3445
2781
|
// Request the list
|
|
3446
2782
|
connection &&
|
|
3447
|
-
connection.send({ type: 'include_list', threadName: threadName });
|
|
2783
|
+
connection.send(JSON.stringify({ type: 'include_list', threadName: threadName }));
|
|
3448
2784
|
}
|
|
3449
2785
|
|
|
3450
2786
|
function renderIncludeList(panel, threadName, files) {
|
|
@@ -3481,11 +2817,13 @@
|
|
|
3481
2817
|
removeBtn.setAttribute('title', 'Remove');
|
|
3482
2818
|
removeBtn.addEventListener('click', function () {
|
|
3483
2819
|
connection &&
|
|
3484
|
-
connection.send(
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
2820
|
+
connection.send(
|
|
2821
|
+
JSON.stringify({
|
|
2822
|
+
type: 'include_remove',
|
|
2823
|
+
threadName: threadName,
|
|
2824
|
+
filePath: f.path,
|
|
2825
|
+
})
|
|
2826
|
+
);
|
|
3489
2827
|
});
|
|
3490
2828
|
item.appendChild(removeBtn);
|
|
3491
2829
|
|
|
@@ -3531,7 +2869,7 @@
|
|
|
3531
2869
|
|
|
3532
2870
|
// Request the turn list
|
|
3533
2871
|
connection &&
|
|
3534
|
-
connection.send({ type: 'revert_list', threadName: threadName });
|
|
2872
|
+
connection.send(JSON.stringify({ type: 'revert_list', threadName: threadName }));
|
|
3535
2873
|
}
|
|
3536
2874
|
|
|
3537
2875
|
function renderRevertList(panel, threadName, turns) {
|
|
@@ -3611,7 +2949,7 @@
|
|
|
3611
2949
|
cancelBtn.addEventListener('click', function () {
|
|
3612
2950
|
// Re-request list
|
|
3613
2951
|
connection &&
|
|
3614
|
-
connection.send({ type: 'revert_list', threadName: threadName });
|
|
2952
|
+
connection.send(JSON.stringify({ type: 'revert_list', threadName: threadName }));
|
|
3615
2953
|
});
|
|
3616
2954
|
actions.appendChild(cancelBtn);
|
|
3617
2955
|
|
|
@@ -3623,11 +2961,13 @@
|
|
|
3623
2961
|
revertBtn.disabled = true;
|
|
3624
2962
|
revertBtn.textContent = 'Reverting\u2026';
|
|
3625
2963
|
connection &&
|
|
3626
|
-
connection.send(
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
2964
|
+
connection.send(
|
|
2965
|
+
JSON.stringify({
|
|
2966
|
+
type: 'revert_execute',
|
|
2967
|
+
threadName: threadName,
|
|
2968
|
+
targetMessageId: turn.userMessageId,
|
|
2969
|
+
})
|
|
2970
|
+
);
|
|
3631
2971
|
});
|
|
3632
2972
|
actions.appendChild(revertBtn);
|
|
3633
2973
|
|
|
@@ -3644,14 +2984,98 @@
|
|
|
3644
2984
|
return h + ':' + (m < 10 ? '0' : '') + m + ' ' + ampm;
|
|
3645
2985
|
}
|
|
3646
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
|
+
|
|
3647
3073
|
// ── Message router ──
|
|
3648
3074
|
function handleServerMessage(data) {
|
|
3649
|
-
if (data.type !== 'token') {
|
|
3650
|
-
console.log('[CumulusChat] WS recv:', data.type, data.threadName || '', data);
|
|
3651
|
-
}
|
|
3652
3075
|
switch (data.type) {
|
|
3653
3076
|
case 'auth_ok':
|
|
3654
3077
|
showAppView();
|
|
3078
|
+
registerPushNotifications();
|
|
3655
3079
|
break;
|
|
3656
3080
|
|
|
3657
3081
|
case 'auth_error':
|
|
@@ -3693,50 +3117,12 @@
|
|
|
3693
3117
|
}
|
|
3694
3118
|
break;
|
|
3695
3119
|
|
|
3696
|
-
case 'thread_deleted':
|
|
3697
|
-
// Server confirms thread deleted; remove from sidebar and panels
|
|
3698
|
-
if (data.threadName) {
|
|
3699
|
-
allThreads = allThreads.filter(function (t) {
|
|
3700
|
-
return t.name !== data.threadName;
|
|
3701
|
-
});
|
|
3702
|
-
delete threadStates[data.threadName];
|
|
3703
|
-
removeThreadFromView(data.threadName);
|
|
3704
|
-
renderSidebar();
|
|
3705
|
-
}
|
|
3706
|
-
break;
|
|
3707
|
-
|
|
3708
|
-
case 'messages_deleted':
|
|
3709
|
-
// Server confirms messages deleted; reload history for that thread
|
|
3710
|
-
if (data.threadName) {
|
|
3711
|
-
var dState = getThreadState(data.threadName);
|
|
3712
|
-
dState.messages = [];
|
|
3713
|
-
dState.historyLoaded = false;
|
|
3714
|
-
dState.selectionMode = false;
|
|
3715
|
-
dState.selectedIds = {};
|
|
3716
|
-
// Exit selection mode on visible panel
|
|
3717
|
-
var dPanel = document.querySelector('[data-thread-panel="' + data.threadName + '"]');
|
|
3718
|
-
if (dPanel) {
|
|
3719
|
-
var dMsgs = dPanel.querySelector('.cumulus-messages');
|
|
3720
|
-
if (dMsgs) dMsgs.classList.remove('cumulus-selection-mode');
|
|
3721
|
-
var dBar = dPanel.querySelector('.cumulus-selection-bar');
|
|
3722
|
-
if (dBar) dBar.remove();
|
|
3723
|
-
var dSelectBtn = dPanel.querySelector('[data-testid="webchat-select-btn"]');
|
|
3724
|
-
if (dSelectBtn) {
|
|
3725
|
-
dSelectBtn.textContent = 'Select';
|
|
3726
|
-
dSelectBtn.classList.remove('active');
|
|
3727
|
-
}
|
|
3728
|
-
}
|
|
3729
|
-
connection &&
|
|
3730
|
-
connection.send({ type: 'history', threadName: data.threadName, limit: 200 });
|
|
3731
|
-
}
|
|
3732
|
-
break;
|
|
3733
|
-
|
|
3734
3120
|
case 'history':
|
|
3735
3121
|
if (data.threadName) {
|
|
3736
3122
|
var state = getThreadState(data.threadName);
|
|
3737
3123
|
if (data.messages && data.messages.length > 0) {
|
|
3738
3124
|
state.messages = data.messages.map(function (m) {
|
|
3739
|
-
return { id: m.id, role: m.role, content: m.content
|
|
3125
|
+
return { id: m.id, role: m.role, content: m.content };
|
|
3740
3126
|
});
|
|
3741
3127
|
}
|
|
3742
3128
|
refreshThreadPanel(data.threadName);
|
|
@@ -3815,22 +3201,6 @@
|
|
|
3815
3201
|
}
|
|
3816
3202
|
break;
|
|
3817
3203
|
|
|
3818
|
-
case 'new_messages':
|
|
3819
|
-
// Agent inject completed — append new messages to the thread and re-render
|
|
3820
|
-
if (data.threadName && data.messages && data.messages.length > 0) {
|
|
3821
|
-
var state = getThreadState(data.threadName);
|
|
3822
|
-
for (var nm = 0; nm < data.messages.length; nm++) {
|
|
3823
|
-
state.messages.push({
|
|
3824
|
-
id: data.messages[nm].id,
|
|
3825
|
-
role: data.messages[nm].role,
|
|
3826
|
-
content: data.messages[nm].content,
|
|
3827
|
-
});
|
|
3828
|
-
}
|
|
3829
|
-
updateThreadActivity(data.threadName);
|
|
3830
|
-
refreshThreadPanel(data.threadName);
|
|
3831
|
-
}
|
|
3832
|
-
break;
|
|
3833
|
-
|
|
3834
3204
|
// ── Include/Revert responses ──
|
|
3835
3205
|
case 'include_list':
|
|
3836
3206
|
if (data.threadName && data.files) {
|
|
@@ -3863,11 +3233,13 @@
|
|
|
3863
3233
|
tState.historyLoaded = false;
|
|
3864
3234
|
// Re-request history
|
|
3865
3235
|
connection &&
|
|
3866
|
-
connection.send(
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3236
|
+
connection.send(
|
|
3237
|
+
JSON.stringify({
|
|
3238
|
+
type: 'history',
|
|
3239
|
+
threadName: data.threadName,
|
|
3240
|
+
limit: 200,
|
|
3241
|
+
})
|
|
3242
|
+
);
|
|
3871
3243
|
if (overlay) overlay.remove();
|
|
3872
3244
|
} else {
|
|
3873
3245
|
// Show error in overlay
|
|
@@ -3891,10 +3263,6 @@
|
|
|
3891
3263
|
break;
|
|
3892
3264
|
}
|
|
3893
3265
|
}
|
|
3894
|
-
// Mark unread if thread is not currently visible
|
|
3895
|
-
if (visibleThreads.indexOf(threadName) === -1) {
|
|
3896
|
-
unreadThreads[threadName] = true;
|
|
3897
|
-
}
|
|
3898
3266
|
// Re-render sidebar to reflect new sort order / move thread up
|
|
3899
3267
|
renderSidebar();
|
|
3900
3268
|
}
|
|
@@ -4047,7 +3415,5 @@
|
|
|
4047
3415
|
}
|
|
4048
3416
|
|
|
4049
3417
|
window.CumulusChat = widget;
|
|
4050
|
-
window.CumulusChat.version = '0.27.15';
|
|
4051
|
-
console.log('[CumulusChat] Widget loaded, version ' + window.CumulusChat.version);
|
|
4052
3418
|
}
|
|
4053
3419
|
})();
|