dsh-tg-bridge 1.2.4 → 1.2.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.
Files changed (3) hide show
  1. package/bridge.mjs +22 -15
  2. package/control.mjs +11 -0
  3. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  } from 'node:fs';
13
13
  import { homedir } from 'node:os';
14
14
  import { join, basename } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
15
16
  // Force IPv4 for every fetch. DNS returns an AAAA next to the A record, and
16
17
  // Happy Eyeballs happily picks the IPv6 path, which here costs ~5 s or dies
17
18
  // outright ("fetch failed" every 6 s, measured 22.10.2026: IPv4 0.34 s, IPv6
@@ -36,6 +37,10 @@ const CRED = join(DSH_HOME, '.credentials.yaml');
36
37
  const PENDING_DIR = join(DIR, 'pending');
37
38
  const DONE_FILE = join(DIR, 'done.json');
38
39
  const RESTART_MARKER = join(DIR, 'restart.pending');
40
+ // `/restart confirm` leaves a note here for the process that replaces it: the
41
+ // old code exits ~300 ms after spawning the new one, and without this the chat
42
+ // saw "Перезапускаю мост…" and then silence — no proof the bot came back.
43
+ const RESTART_NOTICE = join(fileURLToPath(new URL('.', import.meta.url)), 'restart-notice.json');
39
44
  const DONE_TTL_MS = 24 * 60 * 60 * 1000;
40
45
  // dsh.cmd runs the Electron binary as Node against this CLI entrypoint; the
41
46
  // bridge mirrors that exactly so no shell quoting of task text is needed.
@@ -853,10 +858,6 @@ async function startProgress(chatId, threadId, lang = 'ru') {
853
858
  chat_id: chatId,
854
859
  text: body(),
855
860
  disable_web_page_preview: true,
856
- // Stop is available for as long as the turn runs; the keyboard is cleared
857
- // when the status turns into the final line, so a stale button cannot be
858
- // pressed after the work is over.
859
- reply_markup: stopKeyboard(sessionKey(chatId, threadId), lang),
860
861
  ...(threadId > 0 ? { message_thread_id: threadId } : {}),
861
862
  });
862
863
  messageId = res.message_id;
@@ -1439,17 +1440,6 @@ const lastPrompt = new Map();
1439
1440
  const approvals = new Map();
1440
1441
  let approvalSeq = 0;
1441
1442
 
1442
- function stopKeyboard(key, lang = 'ru') {
1443
- return {
1444
- inline_keyboard: [
1445
- [
1446
- { text: `⏹ ${t(lang, 'btn.stop')}`, callback_data: 'stop' },
1447
- { text: `📄 ${t(lang, 'btn.logs')}`, callback_data: 'logs' },
1448
- ],
1449
- ],
1450
- };
1451
- }
1452
-
1453
1443
  function errorKeyboard(key, lang = 'ru') {
1454
1444
  return {
1455
1445
  inline_keyboard: [
@@ -1670,6 +1660,23 @@ async function main() {
1670
1660
  const me = await tg('getMe');
1671
1661
  botUsername = me.username || '';
1672
1662
  log(`bot @${me.username}`);
1663
+ // Confirm the restart in the topic it was asked from, not in the DM: the
1664
+ // person who typed `/restart confirm` was looking at that thread.
1665
+ try {
1666
+ if (existsSync(RESTART_NOTICE)) {
1667
+ const notice = JSON.parse(readFileSync(RESTART_NOTICE, 'utf8'));
1668
+ unlinkSync(RESTART_NOTICE);
1669
+ if (Date.now() - Number(notice.at || 0) < 10 * 60 * 1000) {
1670
+ await send(
1671
+ notice.chatId,
1672
+ `✅ Мост перезапущен — на связи (pid ${process.pid}).\nТема и сессия прежние, можно продолжать.`,
1673
+ notice.threadId || 0,
1674
+ );
1675
+ }
1676
+ }
1677
+ } catch (error) {
1678
+ log(`restart notice failed: ${error.message}`);
1679
+ }
1673
1680
  for (const id of config.allowedUserIds) {
1674
1681
  try { await send(id, `🤖 ${t(config.lang || 'ru', 'msg.started')}`); } catch {}
1675
1682
  }
package/control.mjs CHANGED
@@ -554,6 +554,17 @@ export async function handleControl(ctx) {
554
554
  }
555
555
  say('Перезапускаю мост…');
556
556
  const bridge = fileURLToPath(new URL('./bridge.mjs', import.meta.url));
557
+ // Tell the replacement process where to confirm, so the chat does not go
558
+ // silent after "Перезапускаю мост…" (it did, twice on 2026-10-24).
559
+ try {
560
+ writeFileSync(
561
+ fileURLToPath(new URL('./restart-notice.json', import.meta.url)),
562
+ JSON.stringify({ chatId: ctx.chatId, threadId: ctx.threadId || 0, at: Date.now() }),
563
+ 'utf8',
564
+ );
565
+ } catch (error) {
566
+ log(`restart notice not written: ${error.message}`);
567
+ }
557
568
  spawn(process.execPath, [bridge], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
558
569
  setTimeout(() => process.exit(0), 300);
559
570
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tg-bridge",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
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",