dsh-tg-bridge 1.2.2 → 1.2.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.
Files changed (2) hide show
  1. package/bridge.mjs +42 -0
  2. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -468,6 +468,37 @@ function commandOf(text) {
468
468
  return `/${match[1].toLowerCase().replace(/[.-]+/g, '')}`;
469
469
  }
470
470
 
471
+ /**
472
+ * Commands that must run *now*, not behind the turn they are about.
473
+ *
474
+ * Everything in a topic used to be queued, so `/stop` waited for the very turn
475
+ * it was supposed to kill — on 2026-10-24 a 26-minute turn swallowed `/stop`
476
+ * and the person got "ход уже идёт" instead of an interruption. These few
477
+ * commands touch no turn state, so they can run concurrently with one.
478
+ */
479
+ const IMMEDIATE_COMMANDS = new Set([
480
+ 'stop',
481
+ 'logs',
482
+ 'status',
483
+ 'queue',
484
+ 'help',
485
+ 'version',
486
+ 'doctor',
487
+ 'restart',
488
+ ]);
489
+
490
+ /** Canonical immediate command name for a message, or '' when it must queue. */
491
+ function immediateCommandOf(text) {
492
+ const trimmed = String(text ?? '').trim();
493
+ if (!trimmed.startsWith('/')) return '';
494
+ const head = trimmed.split(/\s+/)[0];
495
+ const collapsed = commandOf(head).replace(/^\//, '');
496
+ if (collapsed === 'apprestart' || collapsed === 'apprestartconfirm' || collapsed === 'restartconfirm') {
497
+ return 'restart';
498
+ }
499
+ return IMMEDIATE_COMMANDS.has(collapsed) ? collapsed : '';
500
+ }
501
+
471
502
  /**
472
503
  * Turn model markdown into plain readable text.
473
504
  *
@@ -1657,6 +1688,17 @@ async function main() {
1657
1688
  }
1658
1689
  const queueKey = sessionKey(msg.chat.id, threadOf(msg));
1659
1690
  const thread = threadOf(msg);
1691
+ // `/stop` behind the turn it should kill is a no-op; run the few commands
1692
+ // that only read or kill state outside the per-topic queue.
1693
+ const immediate = immediateCommandOf(msg.text ?? '');
1694
+ if (immediate) {
1695
+ log(`command ${immediate} handled outside the queue`);
1696
+ Promise.resolve()
1697
+ .then(() => handleMessage(msg))
1698
+ .then(() => ack(update.update_id))
1699
+ .catch((error) => log(`command ${immediate} failed: ${error.message}`));
1700
+ return;
1701
+ }
1660
1702
  enqueue(
1661
1703
  queueKey,
1662
1704
  async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tg-bridge",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
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",