dsh-tg-bridge 1.2.7 → 1.2.8

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.
Files changed (2) hide show
  1. package/bridge.mjs +33 -2
  2. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -607,6 +607,7 @@ export function toTelegramHtml(input) {
607
607
  async function send(chatId, text, threadId = 0, replyTo = 0) {
608
608
  const html = config.plainText === true ? '' : toTelegramHtml(text);
609
609
  const parts = html ? chunk(html, 3800) : chunk(toPlainText(text) || '(пусто)');
610
+ let lastId = 0;
610
611
  for (const part of parts) {
611
612
  const body = { chat_id: chatId, text: part, disable_web_page_preview: true };
612
613
  if (html) body.parse_mode = 'HTML';
@@ -627,7 +628,9 @@ async function send(chatId, text, threadId = 0, replyTo = 0) {
627
628
  res = await tg('sendMessage', body);
628
629
  }
629
630
  log(`sent chat=${chatId}${threadId ? ` topic=${threadId}` : ''} msg=${res.message_id} len=${part.length}${html ? ' html' : ''}`);
631
+ lastId = res.message_id;
630
632
  }
633
+ return lastId;
631
634
  }
632
635
 
633
636
  /** Remember which topics already got their seed message, so it happens once. */
@@ -1398,12 +1401,33 @@ function maybeExitForRestart() {
1398
1401
  setTimeout(() => process.exit(75), 300).unref?.();
1399
1402
  }
1400
1403
 
1404
+ /**
1405
+ * Queue notices, one per topic. A notice exists only while the person is
1406
+ * waiting: the moment the queued turn starts it is deleted, so a long session
1407
+ * does not leave a column of "идёт уже 7 мин" messages behind (it did).
1408
+ */
1409
+ const busyNotices = new Map();
1410
+
1411
+ async function clearBusyNotice(key) {
1412
+ const notice = busyNotices.get(key);
1413
+ if (!notice) return;
1414
+ busyNotices.delete(key);
1415
+ try {
1416
+ await tg('deleteMessage', { chat_id: notice.chatId, message_id: notice.messageId });
1417
+ } catch (error) {
1418
+ log(`busy notice delete failed: ${error.message}`);
1419
+ }
1420
+ }
1421
+
1401
1422
  function enqueue(key, task, onBusy) {
1402
1423
  const prev = queues.get(key) || Promise.resolve();
1403
1424
  const queued = queues.has(key);
1404
1425
  const run = prev
1405
1426
  .then(() => acquire())
1406
- .then(() => {
1427
+ .then(async () => {
1428
+ // The person was told "your message is queued"; that notice has done its
1429
+ // job the moment the turn starts and must not linger in the chat.
1430
+ await clearBusyNotice(key);
1407
1431
  // Remember when the turn actually started: the queue notice has to say
1408
1432
  // "идёт уже 24 мин", not just "занято" — silence is what reads as a hang.
1409
1433
  turnStartedAt.set(key, Date.now());
@@ -1412,6 +1436,7 @@ function enqueue(key, task, onBusy) {
1412
1436
  .catch((error) => log(`turn queue error ${key}: ${error.message}`))
1413
1437
  .finally(() => {
1414
1438
  turnStartedAt.delete(key);
1439
+ clearBusyNotice(key).catch(() => {});
1415
1440
  release();
1416
1441
  if (queues.get(key) === run) queues.delete(key);
1417
1442
  // A deferred restart waits for exactly this moment: the answer is out and
@@ -1728,16 +1753,22 @@ async function main() {
1728
1753
  ? async () => {
1729
1754
  await new Promise((resolve) => setTimeout(resolve, Number(config.busyNoticeMs ?? 45000)));
1730
1755
  if (!queues.has(queueKey)) return; // already finished
1756
+ // One notice per topic: a second queued message must not add a
1757
+ // second copy of the same line.
1758
+ if (busyNotices.has(queueKey)) return;
1731
1759
  const started = turnStartedAt.get(queueKey);
1732
1760
  const mins = started ? Math.max(1, Math.round((Date.now() - started) / 60000)) : 0;
1733
1761
  const notice = mins > 0
1734
1762
  ? t(lang, 'msg.busy.since', { min: mins })
1735
1763
  : t(lang, 'msg.busy.now');
1736
- await send(
1764
+ const messageId = await send(
1737
1765
  msg.chat.id,
1738
1766
  `⏳ ${notice}`,
1739
1767
  thread,
1740
1768
  );
1769
+ if (messageId) busyNotices.set(queueKey, { chatId: msg.chat.id, messageId });
1770
+ // The turn may have started while the notice was in flight.
1771
+ if (!queues.has(queueKey)) await clearBusyNotice(queueKey);
1741
1772
  }
1742
1773
  : undefined,
1743
1774
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tg-bridge",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "Telegram bridge for DeepSeek Harness: text, voice, photos and project-per-topic sessions without opening the desktop app",
5
5
  "type": "module",
6
6
  "main": "bridge.mjs",