@delt/claude-alarm 0.5.2 → 0.5.3

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.
@@ -650,24 +650,64 @@
650
650
  </div>
651
651
  </div>
652
652
  <div id="settingsTelegram" style="display:none">
653
- <p style="margin-bottom:12px;font-size:12px;color:var(--text-dim)">Connect a Telegram bot to receive notifications and send messages.</p>
654
- <div style="margin-bottom:12px">
655
- <label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:4px">Bot Token</label>
656
- <input type="text" id="tgBotToken" placeholder="123456:ABC-DEF..." autocomplete="off" style="width:100%;box-sizing:border-box;padding:10px;background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;font-family:monospace">
653
+ <!-- Step 1: Bot Token -->
654
+ <div id="tgStep1">
655
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
656
+ <span style="background:var(--accent);color:#fff;border-radius:50%;width:22px;height:22px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0">1</span>
657
+ <span style="font-size:13px;font-weight:600;color:var(--text)">Create a bot &amp; paste the token</span>
658
+ </div>
659
+ <p style="margin:0 0 10px 30px;font-size:12px;color:var(--text-dim)">Open <strong>@BotFather</strong> on Telegram → <code>/newbot</code> → copy the token</p>
660
+ <div style="margin-left:30px;margin-bottom:12px">
661
+ <input type="text" id="tgBotToken" placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v..." autocomplete="off" style="width:100%;box-sizing:border-box;padding:10px;background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;font-family:monospace">
662
+ </div>
663
+ <div style="margin-left:30px">
664
+ <button id="tgNextStep2" style="padding:8px 20px;font-size:13px">Next →</button>
665
+ </div>
657
666
  </div>
658
- <div style="margin-bottom:12px">
659
- <label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:4px">Chat ID</label>
660
- <input type="text" id="tgChatId" placeholder="-1001234567890" autocomplete="off" style="width:100%;box-sizing:border-box;padding:10px;background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;font-family:monospace">
661
- </div>
662
- <div style="margin-bottom:16px;display:flex;align-items:center;gap:8px">
663
- <input type="checkbox" id="tgEnabled" style="width:16px;height:16px;accent-color:var(--accent)">
664
- <label for="tgEnabled" style="font-size:13px;color:var(--text)">Enable Telegram notifications</label>
667
+
668
+ <!-- Step 2: Detect Chat ID -->
669
+ <div id="tgStep2" style="display:none">
670
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
671
+ <span style="background:var(--accent);color:#fff;border-radius:50%;width:22px;height:22px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0">2</span>
672
+ <span style="font-size:13px;font-weight:600;color:var(--text)">Find your Chat ID</span>
673
+ </div>
674
+ <p style="margin:0 0 10px 30px;font-size:12px;color:var(--text-dim)">Send any message to your bot on Telegram, then click Detect.</p>
675
+ <div style="margin-left:30px;margin-bottom:10px;display:flex;gap:8px">
676
+ <button id="tgDetect" style="padding:8px 20px;font-size:13px;background:none;color:var(--accent);border:1px solid var(--accent);border-radius:6px;cursor:pointer;font-weight:500">Detect Chat ID</button>
677
+ <span id="tgDetectStatus" style="font-size:12px;color:var(--text-dim);display:flex;align-items:center"></span>
678
+ </div>
679
+ <div id="tgChatList" style="margin-left:30px;margin-bottom:10px"></div>
680
+ <div style="margin-left:30px;margin-bottom:12px">
681
+ <label style="display:block;font-size:11px;color:var(--text-dim);margin-bottom:4px">Or enter manually:</label>
682
+ <input type="text" id="tgChatId" placeholder="-1001234567890" autocomplete="off" style="width:100%;box-sizing:border-box;padding:10px;background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;font-family:monospace">
683
+ </div>
684
+ <div style="margin-left:30px;display:flex;gap:8px">
685
+ <button id="tgBackStep1" style="padding:8px 20px;font-size:13px;background:none;color:var(--text-dim);border:1px solid var(--border);border-radius:6px;cursor:pointer">← Back</button>
686
+ <button id="tgNextStep3" style="padding:8px 20px;font-size:13px">Next →</button>
687
+ </div>
665
688
  </div>
666
- <div id="tgStatus" style="display:none;margin-bottom:12px;padding:8px 12px;border-radius:6px;font-size:12px"></div>
667
- <div style="display:flex;gap:8px">
668
- <button id="tgTest" style="flex:1;padding:10px;background:none;color:var(--accent);border:1px solid var(--accent);border-radius:6px;cursor:pointer;font-size:13px;font-weight:500">Test</button>
669
- <button id="tgSave" style="flex:1;padding:10px">Save</button>
670
- <button id="settingsCancel2" style="flex:1;padding:10px;background:none;color:var(--text);border:1px solid var(--border);border-radius:6px;cursor:pointer;font-size:14px;font-weight:500">Cancel</button>
689
+
690
+ <!-- Step 3: Test & Save -->
691
+ <div id="tgStep3" style="display:none">
692
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
693
+ <span style="background:var(--accent);color:#fff;border-radius:50%;width:22px;height:22px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0">3</span>
694
+ <span style="font-size:13px;font-weight:600;color:var(--text)">Test &amp; Enable</span>
695
+ </div>
696
+ <div style="margin-left:30px;margin-bottom:12px;padding:10px;background:var(--input-bg);border-radius:6px;font-size:12px;color:var(--text-dim)">
697
+ <div>Bot Token: <span id="tgSummaryToken" style="color:var(--text);font-family:monospace"></span></div>
698
+ <div style="margin-top:4px">Chat ID: <span id="tgSummaryChatId" style="color:var(--text);font-family:monospace"></span></div>
699
+ </div>
700
+ <div style="margin-left:30px;margin-bottom:12px;display:flex;align-items:center;gap:8px">
701
+ <input type="checkbox" id="tgEnabled" checked style="width:16px;height:16px;accent-color:var(--accent)">
702
+ <label for="tgEnabled" style="font-size:13px;color:var(--text)">Enable Telegram notifications</label>
703
+ </div>
704
+ <div id="tgStatus" style="display:none;margin:0 0 12px 30px;padding:8px 12px;border-radius:6px;font-size:12px"></div>
705
+ <div style="margin-left:30px;display:flex;gap:8px">
706
+ <button id="tgBackStep2" style="padding:8px 20px;font-size:13px;background:none;color:var(--text-dim);border:1px solid var(--border);border-radius:6px;cursor:pointer">← Back</button>
707
+ <button id="tgTest" style="flex:1;padding:10px;background:none;color:var(--accent);border:1px solid var(--accent);border-radius:6px;cursor:pointer;font-size:13px;font-weight:500">Send Test</button>
708
+ <button id="tgSave" style="flex:1;padding:10px">Save</button>
709
+ <button id="settingsCancel2" style="padding:10px 16px;background:none;color:var(--text);border:1px solid var(--border);border-radius:6px;cursor:pointer;font-size:13px">Cancel</button>
710
+ </div>
671
711
  </div>
672
712
  </div>
673
713
  </div>
@@ -1217,7 +1257,17 @@
1217
1257
  }
1218
1258
  $('#tgChatId').value = tg.chatId || '';
1219
1259
  $('#tgEnabled').checked = !!tg.enabled;
1220
- } catch {}
1260
+ // Jump to appropriate step
1261
+ if (tg.chatId && tg.botToken) {
1262
+ $('#tgSummaryToken').textContent = (tg.botToken || '').slice(0, 8) + '...';
1263
+ $('#tgSummaryChatId').textContent = tg.chatId;
1264
+ showTgStep(3);
1265
+ } else if (tg.botToken) {
1266
+ showTgStep(2);
1267
+ } else {
1268
+ showTgStep(1);
1269
+ }
1270
+ } catch { showTgStep(1); }
1221
1271
  $('#tgStatus').style.display = 'none';
1222
1272
  $('#settingsOverlay').classList.remove('hidden');
1223
1273
  });
@@ -1268,7 +1318,13 @@
1268
1318
  });
1269
1319
  }
1270
1320
 
1271
- // Telegram
1321
+ // Telegram wizard
1322
+ function showTgStep(step) {
1323
+ $('#tgStep1').style.display = step === 1 ? 'block' : 'none';
1324
+ $('#tgStep2').style.display = step === 2 ? 'block' : 'none';
1325
+ $('#tgStep3').style.display = step === 3 ? 'block' : 'none';
1326
+ }
1327
+
1272
1328
  function showTgStatus(msg, ok) {
1273
1329
  const el = $('#tgStatus');
1274
1330
  el.textContent = msg;
@@ -1277,11 +1333,70 @@
1277
1333
  el.style.color = ok ? 'var(--green)' : 'var(--red)';
1278
1334
  }
1279
1335
 
1336
+ // Step navigation
1337
+ $('#tgNextStep2').addEventListener('click', () => {
1338
+ const token = $('#tgBotToken').value.trim();
1339
+ if (!token) { $('#tgBotToken').style.borderColor = 'var(--red)'; return; }
1340
+ $('#tgBotToken').style.borderColor = 'var(--border)';
1341
+ showTgStep(2);
1342
+ });
1343
+ $('#tgBackStep1').addEventListener('click', () => showTgStep(1));
1344
+ $('#tgNextStep3').addEventListener('click', () => {
1345
+ const chatId = $('#tgChatId').value.trim();
1346
+ if (!chatId) { $('#tgChatId').style.borderColor = 'var(--red)'; return; }
1347
+ $('#tgChatId').style.borderColor = 'var(--border)';
1348
+ const token = $('#tgBotToken').value.trim();
1349
+ $('#tgSummaryToken').textContent = token.slice(0, 8) + '...';
1350
+ $('#tgSummaryChatId').textContent = chatId;
1351
+ $('#tgStatus').style.display = 'none';
1352
+ showTgStep(3);
1353
+ });
1354
+ $('#tgBackStep2').addEventListener('click', () => showTgStep(2));
1355
+
1356
+ // Detect Chat ID
1357
+ $('#tgDetect').addEventListener('click', async () => {
1358
+ const botToken = $('#tgBotToken').value.trim();
1359
+ if (!botToken || botToken.includes('...')) { $('#tgDetectStatus').textContent = 'Enter a valid Bot Token first.'; return; }
1360
+ $('#tgDetectStatus').textContent = 'Detecting...';
1361
+ $('#tgChatList').innerHTML = '';
1362
+ try {
1363
+ const tokenQuery = state.token ? `?token=${encodeURIComponent(state.token)}` : '';
1364
+ const res = await fetch(`/api/telegram/detect${tokenQuery}`, {
1365
+ method: 'POST',
1366
+ headers: { 'Content-Type': 'application/json' },
1367
+ body: JSON.stringify({ botToken }),
1368
+ });
1369
+ const data = await res.json();
1370
+ if (data.error) { $('#tgDetectStatus').textContent = data.error; return; }
1371
+ if (!data.ok || !data.chats.length) {
1372
+ $('#tgDetectStatus').textContent = 'No messages found. Send a message to your bot first!';
1373
+ return;
1374
+ }
1375
+ $('#tgDetectStatus').textContent = 'Found ' + data.chats.length + ' chat(s):';
1376
+ $('#tgChatList').innerHTML = data.chats.map(c =>
1377
+ `<button class="tg-chat-pick" data-id="${esc(c.id)}" style="display:block;width:100%;text-align:left;padding:8px 12px;margin-bottom:4px;background:var(--input-bg);border:1px solid var(--border);border-radius:6px;color:var(--text);cursor:pointer;font-size:12px;transition:border-color 0.15s">
1378
+ <strong>${esc(c.name)}</strong> <span style="color:var(--text-dim)">(${esc(c.type)}, ID: ${esc(c.id)})</span>
1379
+ </button>`
1380
+ ).join('');
1381
+ $('#tgChatList').querySelectorAll('.tg-chat-pick').forEach(btn => {
1382
+ btn.addEventListener('click', () => {
1383
+ $('#tgChatId').value = btn.dataset.id;
1384
+ $('#tgChatList').querySelectorAll('.tg-chat-pick').forEach(b => b.style.borderColor = 'var(--border)');
1385
+ btn.style.borderColor = 'var(--accent)';
1386
+ });
1387
+ btn.addEventListener('mouseenter', () => { btn.style.borderColor = 'var(--accent)'; });
1388
+ btn.addEventListener('mouseleave', () => {
1389
+ if ($('#tgChatId').value !== btn.dataset.id) btn.style.borderColor = 'var(--border)';
1390
+ });
1391
+ });
1392
+ } catch { $('#tgDetectStatus').textContent = 'Connection error.'; }
1393
+ });
1394
+
1395
+ // Test
1280
1396
  $('#tgTest').addEventListener('click', async () => {
1281
1397
  const botToken = $('#tgBotToken').value.trim();
1282
1398
  const chatId = $('#tgChatId').value.trim();
1283
1399
  if (!botToken || !chatId) { showTgStatus('Bot Token and Chat ID are required.', false); return; }
1284
- if (botToken.includes('...')) { showTgStatus('Please enter full Bot Token (not masked).', false); return; }
1285
1400
  try {
1286
1401
  const tokenQuery = state.token ? `?token=${encodeURIComponent(state.token)}` : '';
1287
1402
  const res = await fetch(`/api/telegram/test${tokenQuery}`, {
@@ -1295,11 +1410,12 @@
1295
1410
  } catch (e) { showTgStatus('Connection error.', false); }
1296
1411
  });
1297
1412
 
1413
+ // Save
1298
1414
  $('#tgSave').addEventListener('click', async () => {
1299
1415
  const botToken = $('#tgBotToken').value.trim();
1300
1416
  const chatId = $('#tgChatId').value.trim();
1301
1417
  const enabled = $('#tgEnabled').checked;
1302
- if (enabled && botToken.includes('...')) { showTgStatus('Please enter full Bot Token to enable.', false); return; }
1418
+ if (!botToken || !chatId) { showTgStatus('Bot Token and Chat ID are required.', false); return; }
1303
1419
  try {
1304
1420
  const tokenQuery = state.token ? `?token=${encodeURIComponent(state.token)}` : '';
1305
1421
  await fetch(`/api/telegram${tokenQuery}`, {