@luckydraw/cumulus 1.0.23 → 1.0.24

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.0.24
4
+
5
+ Patch release. The `/select` panel is now a compact overlay, matching `/revert`.
6
+
7
+ - **`/select` used to bolt checkboxes onto the full live message bubbles** in the actual conversation view — scrolling through complete rendered content (including blex blocks and code) just to pick messages to delete.
8
+ - **It now opens a dedicated overlay**, styled like the existing `/revert` list: one compact row per message (role badge, one-line preview, timestamp, checkbox), with the same header/close chrome and a footer bar for selection count / Select All / Delete. The live thread underneath stays undisturbed while selecting.
9
+ - Implemented once and shared between the standalone `/chat` panel and the embedded widget, since both already shared the row-rendering and delete-confirm code.
10
+
3
11
  ## v1.0.23
4
12
 
5
13
  Patch release. Search result snippets now show why a match was found, and the model is told to search before claiming something isn't on record.
@@ -1760,18 +1760,7 @@
1760
1760
  ' 50% { box-shadow: 0 0 6px #3b82f6, 0 0 14px rgba(59,130,246,0.6); }',
1761
1761
  '}',
1762
1762
 
1763
- /* ── Message checkbox (selection mode) ── */
1764
- '.cumulus-msg-checkbox {',
1765
- ' display: none; flex-shrink: 0; align-self: flex-start; margin-top: 0.4em;',
1766
- ' width: 16px; height: 16px; cursor: pointer; accent-color: #0066cc;',
1767
- '}',
1768
- '.cumulus-selection-mode .cumulus-msg-checkbox { display: block; }',
1769
- '.cumulus-selection-mode .cumulus-msg-row {',
1770
- ' flex-direction: row; align-items: flex-start; gap: 8px;',
1771
- '}',
1772
- '.cumulus-selection-mode .cumulus-msg-row > *:not(.cumulus-msg-checkbox) { flex: 1; min-width: 0; }',
1773
-
1774
- /* ── Selection action bar (floats at bottom of messages area) ── */
1763
+ /* ── Selection action bar (footer of the select-messages overlay) ── */
1775
1764
  '.cumulus-selection-bar {',
1776
1765
  ' display: flex; align-items: center; gap: 8px;',
1777
1766
  ' padding: 8px 12px;',
@@ -1922,6 +1911,30 @@
1922
1911
  ' padding: 0 5px; flex-shrink: 0;',
1923
1912
  '}',
1924
1913
 
1914
+ /* ── Select-messages overlay rows ── */
1915
+ '.cumulus-select-item {',
1916
+ ' display: flex; align-items: center; gap: 0.6em;',
1917
+ ' padding: 0.5em 0.6em; border-radius: 4px;',
1918
+ ' border: 1px solid #333; margin-bottom: 0.3em; cursor: pointer;',
1919
+ '}',
1920
+ '.cumulus-select-item:hover { border-color: #555; background: #252525; }',
1921
+ '.cumulus-select-checkbox {',
1922
+ ' flex-shrink: 0; width: 16px; height: 16px; cursor: pointer; accent-color: #0066cc;',
1923
+ '}',
1924
+ '.cumulus-select-role {',
1925
+ ' font-size: 0.75em; color: #888; background: #2a2a2a;',
1926
+ ' border: 1px solid #3a3a3a; border-radius: 3px;',
1927
+ ' padding: 1px 6px; flex-shrink: 0; min-width: 4.5em; text-align: center;',
1928
+ ' text-transform: uppercase;',
1929
+ '}',
1930
+ '.cumulus-select-preview {',
1931
+ ' flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;',
1932
+ ' color: #ccc; font-size: 0.9em;',
1933
+ '}',
1934
+ '.cumulus-select-time {',
1935
+ ' font-size: 0.75em; color: #666; flex-shrink: 0;',
1936
+ '}',
1937
+
1925
1938
  /* ── Revert confirm panel ── */
1926
1939
  '.cumulus-revert-confirm {',
1927
1940
  ' padding: 1.5em; display: flex; flex-direction: column;',
@@ -3781,7 +3794,6 @@
3781
3794
  var EMBEDDED_STREAM_TIMEOUT = 120000;
3782
3795
  var authenticated = false;
3783
3796
  var pendingAttachments = [];
3784
- var selectionMode = false;
3785
3797
  var selectedIds = {};
3786
3798
 
3787
3799
  // ── Panel ──
@@ -4000,40 +4012,16 @@
4000
4012
  destroyBlexBlocks(m);
4001
4013
  });
4002
4014
  messagesEl.innerHTML = '';
4003
- // Apply selection mode class
4004
- if (selectionMode) {
4005
- messagesEl.classList.add('cumulus-selection-mode');
4006
- } else {
4007
- messagesEl.classList.remove('cumulus-selection-mode');
4008
- }
4009
4015
  if (messages.length === 0 && !streaming) {
4010
4016
  messagesEl.innerHTML =
4011
4017
  '<div class="cumulus-empty">Send a message to start chatting</div>';
4012
- updateEmbeddedSelectionBar();
4018
+ refreshSelectOverlay(panel);
4013
4019
  return;
4014
4020
  }
4015
4021
  for (var i = 0; i < messages.length; i++) {
4016
4022
  var msg = messages[i];
4017
4023
  var row = document.createElement('div');
4018
4024
  row.className = 'cumulus-msg-row';
4019
- // Add checkbox in selection mode
4020
- if (selectionMode && msg.id) {
4021
- var cb = document.createElement('input');
4022
- cb.type = 'checkbox';
4023
- cb.className = 'cumulus-msg-checkbox';
4024
- cb.checked = !!selectedIds[msg.id];
4025
- (function (msgId) {
4026
- cb.addEventListener('change', function () {
4027
- if (cb.checked) {
4028
- selectedIds[msgId] = true;
4029
- } else {
4030
- delete selectedIds[msgId];
4031
- }
4032
- updateEmbeddedSelectionBar();
4033
- });
4034
- })(msg.id);
4035
- row.appendChild(cb);
4036
- }
4037
4025
  // Suppress thinking-role entries
4038
4026
  if (msg.role === 'thinking') continue;
4039
4027
 
@@ -4059,115 +4047,95 @@
4059
4047
  messagesEl.appendChild(row);
4060
4048
  }
4061
4049
  scrollToBottom();
4062
- updateEmbeddedSelectionBar();
4050
+ refreshSelectOverlay(panel);
4063
4051
  }
4064
4052
 
4065
- function updateEmbeddedSelectionBar() {
4066
- var existingBar = panel.querySelector('.cumulus-selection-bar');
4067
- if (existingBar) existingBar.remove();
4068
- if (!selectionMode) return;
4053
+ function openEmbeddedSelectOverlay() {
4054
+ var existing = panel.querySelector('.cumulus-overlay');
4055
+ if (existing) {
4056
+ existing.remove();
4057
+ return;
4058
+ }
4069
4059
 
4070
- var selectedCount = Object.keys(selectedIds).length;
4071
- var selectableCount = messages.filter(function (m) {
4072
- return !!m.id;
4073
- }).length;
4060
+ selectedIds = {};
4074
4061
 
4075
- var bar = document.createElement('div');
4076
- bar.className = 'cumulus-selection-bar';
4062
+ var overlay = document.createElement('div');
4063
+ overlay.className = 'cumulus-overlay';
4064
+ overlay.setAttribute('data-overlay-kind', 'select');
4077
4065
 
4078
- var countEl = document.createElement('span');
4079
- countEl.className = 'cumulus-selection-count';
4080
- countEl.textContent = selectedCount + ' selected';
4081
- bar.appendChild(countEl);
4082
-
4083
- var selectAllBtn = document.createElement('button');
4084
- selectAllBtn.className = 'cumulus-selection-select-all-btn';
4085
- selectAllBtn.textContent =
4086
- selectedCount === selectableCount && selectableCount > 0 ? 'Deselect All' : 'Select All';
4087
- selectAllBtn.addEventListener('click', function () {
4088
- if (selectedCount === selectableCount && selectableCount > 0) {
4089
- selectedIds = {};
4090
- } else {
4091
- messages.forEach(function (m) {
4092
- if (m.id) selectedIds[m.id] = true;
4093
- });
4094
- }
4095
- renderMessages();
4096
- });
4097
- bar.appendChild(selectAllBtn);
4098
-
4099
- var deleteBtn = document.createElement('button');
4100
- deleteBtn.className = 'cumulus-selection-delete-btn';
4101
- deleteBtn.textContent = 'Delete';
4102
- deleteBtn.disabled = selectedCount === 0;
4103
- deleteBtn.addEventListener('click', function () {
4104
- if (selectedCount === 0) return;
4105
- showEmbeddedDeleteMessagesConfirm(Object.keys(selectedIds));
4066
+ var header = document.createElement('div');
4067
+ header.className = 'cumulus-overlay-header';
4068
+ var title = document.createElement('span');
4069
+ title.className = 'cumulus-overlay-title';
4070
+ title.textContent = 'Select Messages';
4071
+ header.appendChild(title);
4072
+ var closeBtn = document.createElement('button');
4073
+ closeBtn.className = 'cumulus-overlay-close';
4074
+ closeBtn.textContent = '\xD7';
4075
+ closeBtn.addEventListener('click', function () {
4076
+ overlay.remove();
4106
4077
  });
4107
- bar.appendChild(deleteBtn);
4078
+ header.appendChild(closeBtn);
4079
+ overlay.appendChild(header);
4108
4080
 
4109
- var inputAreaEl = panel.querySelector('.cumulus-input-area');
4110
- if (inputAreaEl) {
4111
- panel.insertBefore(bar, inputAreaEl);
4112
- } else {
4113
- panel.appendChild(bar);
4081
+ var body = document.createElement('div');
4082
+ body.className = 'cumulus-overlay-body';
4083
+ overlay.appendChild(body);
4084
+
4085
+ var footer = document.createElement('div');
4086
+ footer.className = 'cumulus-selection-bar';
4087
+ overlay.appendChild(footer);
4088
+
4089
+ function refresh() {
4090
+ renderSelectRows(body, messages, selectedIds, updateFooter);
4091
+ updateFooter();
4092
+ }
4093
+
4094
+ function updateFooter() {
4095
+ footer.innerHTML = '';
4096
+ var selectedCount = Object.keys(selectedIds).length;
4097
+ var selectableCount = messages.filter(function (m) {
4098
+ return !!m.id;
4099
+ }).length;
4100
+
4101
+ var countEl = document.createElement('span');
4102
+ countEl.className = 'cumulus-selection-count';
4103
+ countEl.textContent = selectedCount + ' selected';
4104
+ footer.appendChild(countEl);
4105
+
4106
+ var selectAllBtn = document.createElement('button');
4107
+ selectAllBtn.className = 'cumulus-selection-select-all-btn';
4108
+ selectAllBtn.textContent =
4109
+ selectedCount === selectableCount && selectableCount > 0
4110
+ ? 'Deselect All'
4111
+ : 'Select All';
4112
+ selectAllBtn.addEventListener('click', function () {
4113
+ if (selectedCount === selectableCount && selectableCount > 0) {
4114
+ selectedIds = {};
4115
+ } else {
4116
+ messages.forEach(function (m) {
4117
+ if (m.id) selectedIds[m.id] = true;
4118
+ });
4119
+ }
4120
+ refresh();
4121
+ });
4122
+ footer.appendChild(selectAllBtn);
4123
+
4124
+ var deleteBtn = document.createElement('button');
4125
+ deleteBtn.className = 'cumulus-selection-delete-btn';
4126
+ deleteBtn.textContent = 'Delete';
4127
+ deleteBtn.disabled = selectedCount === 0;
4128
+ deleteBtn.setAttribute('data-testid', 'webchat-select-delete-btn');
4129
+ deleteBtn.addEventListener('click', function () {
4130
+ if (selectedCount === 0) return;
4131
+ showDeleteMessagesConfirm(sessionId, panel, Object.keys(selectedIds));
4132
+ });
4133
+ footer.appendChild(deleteBtn);
4114
4134
  }
4115
- }
4116
-
4117
- function showEmbeddedDeleteMessagesConfirm(ids) {
4118
- var existing = panel.querySelector('.cumulus-confirm-dialog');
4119
- if (existing) existing.remove();
4120
-
4121
- var dialog = document.createElement('div');
4122
- dialog.className = 'cumulus-confirm-dialog';
4123
-
4124
- var box = document.createElement('div');
4125
- box.className = 'cumulus-confirm-dialog-box';
4126
-
4127
- var title = document.createElement('div');
4128
- title.className = 'cumulus-confirm-dialog-title';
4129
- title.textContent = 'Delete Messages';
4130
- box.appendChild(title);
4131
-
4132
- var text = document.createElement('div');
4133
- text.className = 'cumulus-confirm-dialog-text';
4134
- text.textContent =
4135
- ids.length + ' message' + (ids.length === 1 ? '' : 's') + ' will be permanently deleted.';
4136
- box.appendChild(text);
4137
-
4138
- var warn = document.createElement('div');
4139
- warn.className = 'cumulus-confirm-dialog-warn';
4140
- warn.textContent = 'This cannot be undone.';
4141
- box.appendChild(warn);
4142
-
4143
- var actions = document.createElement('div');
4144
- actions.className = 'cumulus-confirm-dialog-actions';
4145
-
4146
- var cancelBtn = document.createElement('button');
4147
- cancelBtn.className = 'cumulus-confirm-dialog-cancel';
4148
- cancelBtn.textContent = 'Cancel';
4149
- cancelBtn.addEventListener('click', function () {
4150
- dialog.remove();
4151
- });
4152
- actions.appendChild(cancelBtn);
4153
-
4154
- var confirmBtn = document.createElement('button');
4155
- confirmBtn.className = 'cumulus-confirm-dialog-confirm';
4156
- confirmBtn.setAttribute('data-testid', 'webchat-delete-messages-confirm');
4157
- confirmBtn.textContent = 'Delete';
4158
- confirmBtn.addEventListener('click', function () {
4159
- confirmBtn.disabled = true;
4160
- confirmBtn.textContent = 'Deleting\u2026';
4161
- if (connection) {
4162
- connection.send({ type: 'delete_messages', threadName: sessionId, messageIds: ids });
4163
- }
4164
- dialog.remove();
4165
- });
4166
- actions.appendChild(confirmBtn);
4167
4135
 
4168
- box.appendChild(actions);
4169
- dialog.appendChild(box);
4170
- panel.appendChild(dialog);
4136
+ overlay._refresh = refresh;
4137
+ refresh();
4138
+ panel.appendChild(overlay);
4171
4139
  }
4172
4140
 
4173
4141
  function hasUploadingAttachments() {
@@ -4464,14 +4432,10 @@
4464
4432
  }
4465
4433
  break;
4466
4434
  case 'messages_deleted':
4467
- // Server confirmed deletion — reload history and exit selection mode
4468
- selectionMode = false;
4435
+ // Server confirmed deletion — reload history and close the overlay
4469
4436
  selectedIds = {};
4470
- var embSelectBtn = panel.querySelector('[data-testid="webchat-select-btn"]');
4471
- if (embSelectBtn) {
4472
- embSelectBtn.textContent = 'Select';
4473
- embSelectBtn.classList.remove('active');
4474
- }
4437
+ var selOverlay = panel.querySelector('.cumulus-overlay[data-overlay-kind="select"]');
4438
+ if (selOverlay) selOverlay.remove();
4475
4439
  messages = [];
4476
4440
  // Re-request history
4477
4441
  if (connection) {
@@ -4617,15 +4581,7 @@
4617
4581
  var embSelectBtn = panel.querySelector('[data-testid="webchat-select-btn"]');
4618
4582
  if (embSelectBtn) {
4619
4583
  embSelectBtn.addEventListener('click', function () {
4620
- selectionMode = !selectionMode;
4621
- selectedIds = {};
4622
- embSelectBtn.textContent = selectionMode ? 'Done' : 'Select';
4623
- if (selectionMode) {
4624
- embSelectBtn.classList.add('active');
4625
- } else {
4626
- embSelectBtn.classList.remove('active');
4627
- }
4628
- renderMessages();
4584
+ openEmbeddedSelectOverlay();
4629
4585
  });
4630
4586
  }
4631
4587
 
@@ -4738,7 +4694,6 @@
4738
4694
  interjecting: false,
4739
4695
  pendingAttachments: [],
4740
4696
  historyLoaded: false,
4741
- selectionMode: false,
4742
4697
  selectedIds: {},
4743
4698
  draft: '', // persists unsent textarea text across thread switches
4744
4699
  // Pagination state
@@ -7776,7 +7731,7 @@
7776
7731
  selectBtn.setAttribute('title', 'Select messages to delete');
7777
7732
  selectBtn.textContent = 'Select';
7778
7733
  selectBtn.addEventListener('click', function () {
7779
- toggleSelectionMode();
7734
+ openSelectOverlay(panel, threadName);
7780
7735
  });
7781
7736
  actions.appendChild(selectBtn);
7782
7737
 
@@ -8522,16 +8477,10 @@
8522
8477
  destroyBlexBlocks(m);
8523
8478
  });
8524
8479
  messagesEl.innerHTML = '';
8525
- // Apply selection mode class to messages container
8526
- if (state.selectionMode) {
8527
- messagesEl.classList.add('cumulus-selection-mode');
8528
- } else {
8529
- messagesEl.classList.remove('cumulus-selection-mode');
8530
- }
8531
8480
  if (state.messages.length === 0 && !state.streaming) {
8532
8481
  messagesEl.innerHTML =
8533
8482
  '<div class="cumulus-empty">Send a message to start chatting</div>';
8534
- updateSelectionBar();
8483
+ refreshSelectOverlay(panel);
8535
8484
  return;
8536
8485
  }
8537
8486
  // Show "load older" indicator if more messages are available
@@ -8548,24 +8497,6 @@
8548
8497
  var msg = state.messages[i];
8549
8498
  var row = document.createElement('div');
8550
8499
  row.className = 'cumulus-msg-row';
8551
- // Add checkbox if in selection mode and message has an id
8552
- if (state.selectionMode && msg.id) {
8553
- var cb = document.createElement('input');
8554
- cb.type = 'checkbox';
8555
- cb.className = 'cumulus-msg-checkbox';
8556
- cb.checked = !!state.selectedIds[msg.id];
8557
- (function (msgId) {
8558
- cb.addEventListener('change', function () {
8559
- if (cb.checked) {
8560
- state.selectedIds[msgId] = true;
8561
- } else {
8562
- delete state.selectedIds[msgId];
8563
- }
8564
- updateSelectionBar();
8565
- });
8566
- })(msg.id);
8567
- row.appendChild(cb);
8568
- }
8569
8500
  // Suppress thinking-role entries
8570
8501
  if (msg.role === 'thinking') continue;
8571
8502
 
@@ -8612,132 +8543,7 @@
8612
8543
  }
8613
8544
  renderActivityBar();
8614
8545
  scrollToBottom();
8615
- updateSelectionBar();
8616
- }
8617
-
8618
- function updateSelectionBar() {
8619
- // Remove existing bar
8620
- var existingBar = panel.querySelector('.cumulus-selection-bar');
8621
- if (existingBar) existingBar.remove();
8622
- if (!state.selectionMode) return;
8623
-
8624
- var selectedCount = Object.keys(state.selectedIds).length;
8625
- var selectableCount = state.messages.filter(function (m) {
8626
- return !!m.id;
8627
- }).length;
8628
-
8629
- var bar = document.createElement('div');
8630
- bar.className = 'cumulus-selection-bar';
8631
-
8632
- var countEl = document.createElement('span');
8633
- countEl.className = 'cumulus-selection-count';
8634
- countEl.textContent = selectedCount + ' selected';
8635
- bar.appendChild(countEl);
8636
-
8637
- var selectAllBtn = document.createElement('button');
8638
- selectAllBtn.className = 'cumulus-selection-select-all-btn';
8639
- selectAllBtn.textContent =
8640
- selectedCount === selectableCount && selectableCount > 0 ? 'Deselect All' : 'Select All';
8641
- selectAllBtn.addEventListener('click', function () {
8642
- if (selectedCount === selectableCount && selectableCount > 0) {
8643
- // Deselect all
8644
- state.selectedIds = {};
8645
- } else {
8646
- // Select all with IDs
8647
- state.messages.forEach(function (m) {
8648
- if (m.id) state.selectedIds[m.id] = true;
8649
- });
8650
- }
8651
- renderPanelMessages();
8652
- });
8653
- bar.appendChild(selectAllBtn);
8654
-
8655
- var deleteBtn = document.createElement('button');
8656
- deleteBtn.className = 'cumulus-selection-delete-btn';
8657
- deleteBtn.textContent = 'Delete';
8658
- deleteBtn.disabled = selectedCount === 0;
8659
- deleteBtn.addEventListener('click', function () {
8660
- if (selectedCount === 0) return;
8661
- showDeleteMessagesConfirm(threadName, panel, Object.keys(state.selectedIds));
8662
- });
8663
- bar.appendChild(deleteBtn);
8664
-
8665
- // Insert before input area
8666
- var inputAreaEl = panel.querySelector('.cumulus-input-area');
8667
- if (inputAreaEl) {
8668
- panel.insertBefore(bar, inputAreaEl);
8669
- } else {
8670
- panel.appendChild(bar);
8671
- }
8672
- }
8673
-
8674
- function toggleSelectionMode() {
8675
- state.selectionMode = !state.selectionMode;
8676
- state.selectedIds = {};
8677
- selectBtn.textContent = state.selectionMode ? 'Done' : 'Select';
8678
- if (state.selectionMode) {
8679
- selectBtn.classList.add('active');
8680
- } else {
8681
- selectBtn.classList.remove('active');
8682
- }
8683
- renderPanelMessages();
8684
- }
8685
-
8686
- function showDeleteMessagesConfirm(tName, panelEl, ids) {
8687
- // Remove any existing confirm dialog
8688
- var existing = panelEl.querySelector('.cumulus-confirm-dialog');
8689
- if (existing) existing.remove();
8690
-
8691
- var dialog = document.createElement('div');
8692
- dialog.className = 'cumulus-confirm-dialog';
8693
-
8694
- var box = document.createElement('div');
8695
- box.className = 'cumulus-confirm-dialog-box';
8696
-
8697
- var title = document.createElement('div');
8698
- title.className = 'cumulus-confirm-dialog-title';
8699
- title.textContent = 'Delete Messages';
8700
- box.appendChild(title);
8701
-
8702
- var text = document.createElement('div');
8703
- text.className = 'cumulus-confirm-dialog-text';
8704
- text.textContent =
8705
- ids.length + ' message' + (ids.length === 1 ? '' : 's') + ' will be permanently deleted.';
8706
- box.appendChild(text);
8707
-
8708
- var warn = document.createElement('div');
8709
- warn.className = 'cumulus-confirm-dialog-warn';
8710
- warn.textContent = 'This cannot be undone.';
8711
- box.appendChild(warn);
8712
-
8713
- var actions = document.createElement('div');
8714
- actions.className = 'cumulus-confirm-dialog-actions';
8715
-
8716
- var cancelBtn = document.createElement('button');
8717
- cancelBtn.className = 'cumulus-confirm-dialog-cancel';
8718
- cancelBtn.textContent = 'Cancel';
8719
- cancelBtn.addEventListener('click', function () {
8720
- dialog.remove();
8721
- });
8722
- actions.appendChild(cancelBtn);
8723
-
8724
- var confirmBtn = document.createElement('button');
8725
- confirmBtn.className = 'cumulus-confirm-dialog-confirm';
8726
- confirmBtn.setAttribute('data-testid', 'webchat-delete-messages-confirm');
8727
- confirmBtn.textContent = 'Delete';
8728
- confirmBtn.addEventListener('click', function () {
8729
- confirmBtn.disabled = true;
8730
- confirmBtn.textContent = 'Deleting\u2026';
8731
- if (connection) {
8732
- connection.send({ type: 'delete_messages', threadName: tName, messageIds: ids });
8733
- }
8734
- dialog.remove();
8735
- });
8736
- actions.appendChild(confirmBtn);
8737
-
8738
- box.appendChild(actions);
8739
- dialog.appendChild(box);
8740
- panelEl.appendChild(dialog);
8546
+ refreshSelectOverlay(panel);
8741
8547
  }
8742
8548
 
8743
8549
  function hasPanelUploading() {
@@ -9277,6 +9083,230 @@
9277
9083
  });
9278
9084
  }
9279
9085
 
9086
+ // ── Select-messages overlay ──
9087
+ // Compact one-line rows with checkboxes, modeled on the revert overlay's
9088
+ // list shape (task 163) — replaces the old inline checkboxes bolted onto
9089
+ // full message bubbles in the live thread view.
9090
+ function messagePreviewText(content) {
9091
+ if (typeof content !== 'string') return '';
9092
+ var text = content
9093
+ .replace(/```[\s\S]*?```/g, ' ')
9094
+ .replace(/[#*_`~>]/g, '')
9095
+ .replace(/\s+/g, ' ')
9096
+ .trim();
9097
+ if (text.length > 90) text = text.slice(0, 90) + '…';
9098
+ return text || '(empty)';
9099
+ }
9100
+
9101
+ function renderSelectRows(body, messages, selectedIds, onToggle) {
9102
+ body.innerHTML = '';
9103
+ var any = false;
9104
+ messages.forEach(function (msg) {
9105
+ if (msg.role === 'thinking') return;
9106
+ any = true;
9107
+
9108
+ var item = document.createElement('div');
9109
+ item.className = 'cumulus-select-item';
9110
+ item.setAttribute('data-testid', 'webchat-select-item');
9111
+
9112
+ var cb = document.createElement('input');
9113
+ cb.type = 'checkbox';
9114
+ cb.className = 'cumulus-select-checkbox';
9115
+ cb.disabled = !msg.id;
9116
+ cb.checked = !!(msg.id && selectedIds[msg.id]);
9117
+ item.appendChild(cb);
9118
+
9119
+ var roleEl = document.createElement('span');
9120
+ roleEl.className = 'cumulus-select-role';
9121
+ roleEl.textContent = msg.role || 'message';
9122
+ item.appendChild(roleEl);
9123
+
9124
+ var previewEl = document.createElement('span');
9125
+ previewEl.className = 'cumulus-select-preview';
9126
+ previewEl.textContent = messagePreviewText(msg.content);
9127
+ item.appendChild(previewEl);
9128
+
9129
+ var timeEl = document.createElement('span');
9130
+ timeEl.className = 'cumulus-select-time';
9131
+ timeEl.textContent = formatTime(msg.timestamp);
9132
+ item.appendChild(timeEl);
9133
+
9134
+ function applyToggle(checked) {
9135
+ if (!msg.id) return;
9136
+ cb.checked = checked;
9137
+ if (checked) {
9138
+ selectedIds[msg.id] = true;
9139
+ } else {
9140
+ delete selectedIds[msg.id];
9141
+ }
9142
+ onToggle();
9143
+ }
9144
+
9145
+ cb.addEventListener('change', function () {
9146
+ applyToggle(cb.checked);
9147
+ });
9148
+ item.addEventListener('click', function (e) {
9149
+ if (e.target === cb) return;
9150
+ applyToggle(!cb.checked);
9151
+ });
9152
+
9153
+ body.appendChild(item);
9154
+ });
9155
+ if (!any) {
9156
+ body.innerHTML = '<div class="cumulus-overlay-empty">No messages to select.</div>';
9157
+ }
9158
+ }
9159
+
9160
+ function showDeleteMessagesConfirm(tName, panelEl, ids) {
9161
+ // Remove any existing confirm dialog
9162
+ var existing = panelEl.querySelector('.cumulus-confirm-dialog');
9163
+ if (existing) existing.remove();
9164
+
9165
+ var dialog = document.createElement('div');
9166
+ dialog.className = 'cumulus-confirm-dialog';
9167
+
9168
+ var box = document.createElement('div');
9169
+ box.className = 'cumulus-confirm-dialog-box';
9170
+
9171
+ var title = document.createElement('div');
9172
+ title.className = 'cumulus-confirm-dialog-title';
9173
+ title.textContent = 'Delete Messages';
9174
+ box.appendChild(title);
9175
+
9176
+ var text = document.createElement('div');
9177
+ text.className = 'cumulus-confirm-dialog-text';
9178
+ text.textContent =
9179
+ ids.length + ' message' + (ids.length === 1 ? '' : 's') + ' will be permanently deleted.';
9180
+ box.appendChild(text);
9181
+
9182
+ var warn = document.createElement('div');
9183
+ warn.className = 'cumulus-confirm-dialog-warn';
9184
+ warn.textContent = 'This cannot be undone.';
9185
+ box.appendChild(warn);
9186
+
9187
+ var actions = document.createElement('div');
9188
+ actions.className = 'cumulus-confirm-dialog-actions';
9189
+
9190
+ var cancelBtn = document.createElement('button');
9191
+ cancelBtn.className = 'cumulus-confirm-dialog-cancel';
9192
+ cancelBtn.textContent = 'Cancel';
9193
+ cancelBtn.addEventListener('click', function () {
9194
+ dialog.remove();
9195
+ });
9196
+ actions.appendChild(cancelBtn);
9197
+
9198
+ var confirmBtn = document.createElement('button');
9199
+ confirmBtn.className = 'cumulus-confirm-dialog-confirm';
9200
+ confirmBtn.setAttribute('data-testid', 'webchat-delete-messages-confirm');
9201
+ confirmBtn.textContent = 'Delete';
9202
+ confirmBtn.addEventListener('click', function () {
9203
+ confirmBtn.disabled = true;
9204
+ confirmBtn.textContent = 'Deleting…';
9205
+ if (connection) {
9206
+ connection.send({ type: 'delete_messages', threadName: tName, messageIds: ids });
9207
+ }
9208
+ dialog.remove();
9209
+ });
9210
+ actions.appendChild(confirmBtn);
9211
+
9212
+ box.appendChild(actions);
9213
+ dialog.appendChild(box);
9214
+ panelEl.appendChild(dialog);
9215
+ }
9216
+
9217
+ function openSelectOverlay(panel, threadName) {
9218
+ var existing = panel.querySelector('.cumulus-overlay');
9219
+ if (existing) {
9220
+ existing.remove();
9221
+ return;
9222
+ }
9223
+
9224
+ getThreadState(threadName).selectedIds = {};
9225
+
9226
+ var overlay = document.createElement('div');
9227
+ overlay.className = 'cumulus-overlay';
9228
+ overlay.setAttribute('data-overlay-kind', 'select');
9229
+
9230
+ var header = document.createElement('div');
9231
+ header.className = 'cumulus-overlay-header';
9232
+ var title = document.createElement('span');
9233
+ title.className = 'cumulus-overlay-title';
9234
+ title.textContent = 'Select Messages';
9235
+ header.appendChild(title);
9236
+ var closeBtn = document.createElement('button');
9237
+ closeBtn.className = 'cumulus-overlay-close';
9238
+ closeBtn.textContent = '\xD7';
9239
+ closeBtn.addEventListener('click', function () {
9240
+ overlay.remove();
9241
+ });
9242
+ header.appendChild(closeBtn);
9243
+ overlay.appendChild(header);
9244
+
9245
+ var body = document.createElement('div');
9246
+ body.className = 'cumulus-overlay-body';
9247
+ overlay.appendChild(body);
9248
+
9249
+ var footer = document.createElement('div');
9250
+ footer.className = 'cumulus-selection-bar';
9251
+ overlay.appendChild(footer);
9252
+
9253
+ function refresh() {
9254
+ var st = getThreadState(threadName);
9255
+ renderSelectRows(body, st.messages, st.selectedIds, updateFooter);
9256
+ updateFooter();
9257
+ }
9258
+
9259
+ function updateFooter() {
9260
+ var st = getThreadState(threadName);
9261
+ footer.innerHTML = '';
9262
+ var selectedCount = Object.keys(st.selectedIds).length;
9263
+ var selectableCount = st.messages.filter(function (m) {
9264
+ return !!m.id;
9265
+ }).length;
9266
+
9267
+ var countEl = document.createElement('span');
9268
+ countEl.className = 'cumulus-selection-count';
9269
+ countEl.textContent = selectedCount + ' selected';
9270
+ footer.appendChild(countEl);
9271
+
9272
+ var selectAllBtn = document.createElement('button');
9273
+ selectAllBtn.className = 'cumulus-selection-select-all-btn';
9274
+ selectAllBtn.textContent =
9275
+ selectedCount === selectableCount && selectableCount > 0 ? 'Deselect All' : 'Select All';
9276
+ selectAllBtn.addEventListener('click', function () {
9277
+ if (selectedCount === selectableCount && selectableCount > 0) {
9278
+ st.selectedIds = {};
9279
+ } else {
9280
+ st.messages.forEach(function (m) {
9281
+ if (m.id) st.selectedIds[m.id] = true;
9282
+ });
9283
+ }
9284
+ refresh();
9285
+ });
9286
+ footer.appendChild(selectAllBtn);
9287
+
9288
+ var deleteBtn = document.createElement('button');
9289
+ deleteBtn.className = 'cumulus-selection-delete-btn';
9290
+ deleteBtn.textContent = 'Delete';
9291
+ deleteBtn.disabled = selectedCount === 0;
9292
+ deleteBtn.setAttribute('data-testid', 'webchat-select-delete-btn');
9293
+ deleteBtn.addEventListener('click', function () {
9294
+ if (selectedCount === 0) return;
9295
+ showDeleteMessagesConfirm(threadName, panel, Object.keys(st.selectedIds));
9296
+ });
9297
+ footer.appendChild(deleteBtn);
9298
+ }
9299
+
9300
+ overlay._refresh = refresh;
9301
+ refresh();
9302
+ panel.appendChild(overlay);
9303
+ }
9304
+
9305
+ function refreshSelectOverlay(panel) {
9306
+ var overlay = panel.querySelector('.cumulus-overlay[data-overlay-kind="select"]');
9307
+ if (overlay && overlay._refresh) overlay._refresh();
9308
+ }
9309
+
9280
9310
  // ── Revert overlay ──
9281
9311
  function openRevertOverlay(panel, threadName) {
9282
9312
  var existing = panel.querySelector('.cumulus-overlay');
@@ -9648,20 +9678,12 @@
9648
9678
  var dState = getThreadState(data.threadName);
9649
9679
  dState.messages = [];
9650
9680
  dState.historyLoaded = false;
9651
- dState.selectionMode = false;
9652
9681
  dState.selectedIds = {};
9653
- // Exit selection mode on visible panel
9682
+ // Close the select overlay on the visible panel, if open
9654
9683
  var dPanel = document.querySelector('[data-thread-panel="' + data.threadName + '"]');
9655
9684
  if (dPanel) {
9656
- var dMsgs = dPanel.querySelector('.cumulus-messages');
9657
- if (dMsgs) dMsgs.classList.remove('cumulus-selection-mode');
9658
- var dBar = dPanel.querySelector('.cumulus-selection-bar');
9659
- if (dBar) dBar.remove();
9660
- var dSelectBtn = dPanel.querySelector('[data-testid="webchat-select-btn"]');
9661
- if (dSelectBtn) {
9662
- dSelectBtn.textContent = 'Select';
9663
- dSelectBtn.classList.remove('active');
9664
- }
9685
+ var dOverlay = dPanel.querySelector('.cumulus-overlay[data-overlay-kind="select"]');
9686
+ if (dOverlay) dOverlay.remove();
9665
9687
  }
9666
9688
  connection &&
9667
9689
  connection.send({ type: 'history', threadName: data.threadName, limit: 200 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luckydraw/cumulus",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "description": "RLM-based CLI chat wrapper for Claude with external history context management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",