@delt/claude-alarm 0.4.4 → 0.4.6

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.
@@ -266,6 +266,33 @@
266
266
  margin-top: 4px;
267
267
  }
268
268
 
269
+ /* Typing indicator */
270
+ .typing-indicator {
271
+ display: none;
272
+ padding: 10px 14px;
273
+ margin-bottom: 12px;
274
+ max-width: 80px;
275
+ }
276
+ .typing-indicator.active { display: block; }
277
+ .typing-dots {
278
+ display: flex;
279
+ gap: 4px;
280
+ align-items: center;
281
+ }
282
+ .typing-dots span {
283
+ width: 6px;
284
+ height: 6px;
285
+ border-radius: 50%;
286
+ background: var(--text-dim);
287
+ animation: typing 1.4s infinite ease-in-out;
288
+ }
289
+ .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
290
+ .typing-dots span:nth-child(3) { animation-delay: 0.4s; }
291
+ @keyframes typing {
292
+ 0%, 60%, 100% { opacity: 0.3; transform: scale(1); }
293
+ 30% { opacity: 1; transform: scale(1.2); }
294
+ }
295
+
269
296
  /* Scroll to bottom button */
270
297
  .scroll-bottom {
271
298
  position: absolute;
@@ -683,6 +710,7 @@
683
710
  token: null,
684
711
  pendingImage: null,
685
712
  unread: {},
713
+ waitingReply: {},
686
714
  };
687
715
 
688
716
  const $ = (sel) => document.querySelector(sel);
@@ -782,6 +810,7 @@
782
810
  case 'reply_from_session':
783
811
  if (!state.messages[msg.sessionId]) state.messages[msg.sessionId] = [];
784
812
  state.messages[msg.sessionId].push({ from: 'session', content: msg.content, time: msg.timestamp });
813
+ state.waitingReply[msg.sessionId] = false;
785
814
  if (state.selectedSession === msg.sessionId) { renderMessages(); }
786
815
  else { state.unread[msg.sessionId] = (state.unread[msg.sessionId] || 0) + 1; renderSessions(); }
787
816
  state.notifications.unshift({ sessionId: msg.sessionId, title: 'Reply', message: msg.content.slice(0, 100), level: 'info', time: msg.timestamp });
@@ -874,6 +903,9 @@
874
903
  </div>`;
875
904
  }).join('');
876
905
 
906
+ if (state.waitingReply[state.selectedSession]) {
907
+ el.innerHTML += '<div class="typing-indicator active"><div class="typing-dots"><span></span><span></span><span></span></div></div>';
908
+ }
877
909
  setTimeout(() => { el.scrollTop = el.scrollHeight; }, 0);
878
910
  }
879
911
 
@@ -1017,6 +1049,7 @@
1017
1049
  input.value = '';
1018
1050
  input.style.height = 'auto';
1019
1051
  clearPendingImage();
1052
+ state.waitingReply[state.selectedSession] = true;
1020
1053
  renderMessages();
1021
1054
  }
1022
1055
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delt/claude-alarm",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "Monitor and get notifications from multiple Claude Code sessions via MCP Channels",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,8 @@
20
20
  },
21
21
  "files": [
22
22
  "dist",
23
- "src/dashboard/index.html"
23
+ "src/dashboard/index.html",
24
+ "README.md"
24
25
  ],
25
26
  "scripts": {
26
27
  "build": "tsup && node -e \"const fs=require('fs');const p=require('path');fs.mkdirSync(p.join('dist','dashboard'),{recursive:true});fs.copyFileSync(p.join('src','dashboard','index.html'),p.join('dist','dashboard','index.html'));\"",
@@ -266,6 +266,33 @@
266
266
  margin-top: 4px;
267
267
  }
268
268
 
269
+ /* Typing indicator */
270
+ .typing-indicator {
271
+ display: none;
272
+ padding: 10px 14px;
273
+ margin-bottom: 12px;
274
+ max-width: 80px;
275
+ }
276
+ .typing-indicator.active { display: block; }
277
+ .typing-dots {
278
+ display: flex;
279
+ gap: 4px;
280
+ align-items: center;
281
+ }
282
+ .typing-dots span {
283
+ width: 6px;
284
+ height: 6px;
285
+ border-radius: 50%;
286
+ background: var(--text-dim);
287
+ animation: typing 1.4s infinite ease-in-out;
288
+ }
289
+ .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
290
+ .typing-dots span:nth-child(3) { animation-delay: 0.4s; }
291
+ @keyframes typing {
292
+ 0%, 60%, 100% { opacity: 0.3; transform: scale(1); }
293
+ 30% { opacity: 1; transform: scale(1.2); }
294
+ }
295
+
269
296
  /* Scroll to bottom button */
270
297
  .scroll-bottom {
271
298
  position: absolute;
@@ -683,6 +710,7 @@
683
710
  token: null,
684
711
  pendingImage: null,
685
712
  unread: {},
713
+ waitingReply: {},
686
714
  };
687
715
 
688
716
  const $ = (sel) => document.querySelector(sel);
@@ -782,6 +810,7 @@
782
810
  case 'reply_from_session':
783
811
  if (!state.messages[msg.sessionId]) state.messages[msg.sessionId] = [];
784
812
  state.messages[msg.sessionId].push({ from: 'session', content: msg.content, time: msg.timestamp });
813
+ state.waitingReply[msg.sessionId] = false;
785
814
  if (state.selectedSession === msg.sessionId) { renderMessages(); }
786
815
  else { state.unread[msg.sessionId] = (state.unread[msg.sessionId] || 0) + 1; renderSessions(); }
787
816
  state.notifications.unshift({ sessionId: msg.sessionId, title: 'Reply', message: msg.content.slice(0, 100), level: 'info', time: msg.timestamp });
@@ -874,6 +903,9 @@
874
903
  </div>`;
875
904
  }).join('');
876
905
 
906
+ if (state.waitingReply[state.selectedSession]) {
907
+ el.innerHTML += '<div class="typing-indicator active"><div class="typing-dots"><span></span><span></span><span></span></div></div>';
908
+ }
877
909
  setTimeout(() => { el.scrollTop = el.scrollHeight; }, 0);
878
910
  }
879
911
 
@@ -1017,6 +1049,7 @@
1017
1049
  input.value = '';
1018
1050
  input.style.height = 'auto';
1019
1051
  clearPendingImage();
1052
+ state.waitingReply[state.selectedSession] = true;
1020
1053
  renderMessages();
1021
1054
  }
1022
1055