dsh-telegram-multiagent 1.2.0 → 1.2.2

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/package.json +1 -1
  2. package/src/index.js +38 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-telegram-multiagent",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Telegram channel for DeepSeek Harness — one shared module serving several agents, with unforgeable sender marks, merged owner+coordinator memory, and a delivery mode you switch in a file outside the code.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -453,8 +453,12 @@ export function apply(ctx, config = {}) {
453
453
  const url = `https://api.telegram.org/file/bot${token}/${filePath}`;
454
454
  const ext = path.extname(filePath) || '.oga';
455
455
  const tmp = path.join(os.tmpdir(), `dsh-voice-${Date.now()}${ext}`);
456
- // curl доступен на хосте; fetch тоже можно, но curl проще для бинарника.
457
- execFileSync('curl', ['-s', '-o', tmp, url]);
456
+ // 🔴 Скачиваем ВСТРОЕННЫМ fetch, а не curl: адрес содержит токен бота, а
457
+ // строка запуска процесса (/proc/<pid>/cmdline) читается ЛЮБЫМ пользователем
458
+ // машины. Через curl токен утекал бы при КАЖДОМ голосовом сообщении.
459
+ const res = await fetch(url);
460
+ if (!res.ok) throw new Error(`telegram file download: HTTP ${res.status}`);
461
+ fs.writeFileSync(tmp, Buffer.from(await res.arrayBuffer()));
458
462
  return tmp;
459
463
  }
460
464
 
@@ -598,14 +602,43 @@ export function apply(ctx, config = {}) {
598
602
  const A2A_OUT = A2A_DIR ? path.join(A2A_DIR, 'out') : null;
599
603
  const A2A_CHAT = config.a2aSession || 'a2a'; // отдельная сессия, не смешивается с Telegram
600
604
 
605
+ // Берём простые текстовые форматы. Всё остальное НЕ берём — но и не
606
+ // проглатываем: имя отвергнутого файла называем в журнале. Поймано
607
+ // 21.08.2026: письмо с расширением .md пролежало во входящих 26 минут,
608
+ // и снаружи это выглядело как «агент не отвечает».
609
+ const A2A_EXT = ['.txt', '.md'];
610
+ // ГРАНИЦА СТОРОЖА: о каждом имени сообщаем ОДИН раз — опрос идёт
611
+ // каждые ~25 секунд, и повтор превратил бы защиту в шум. Файл убрали —
612
+ // имя забываем, положат снова — сообщим снова.
613
+ const a2aReported = new Set();
614
+
601
615
  async function pollA2A() {
602
616
  if (!A2A_DIR) return;
603
- let files = [];
617
+ let all = [];
604
618
  try {
605
619
  fs.mkdirSync(A2A_IN, { recursive: true });
606
620
  fs.mkdirSync(A2A_OUT, { recursive: true });
607
- files = fs.readdirSync(A2A_IN).filter((f) => f.endsWith('.txt')).sort();
608
- } catch { return; }
621
+ all = fs.readdirSync(A2A_IN).sort();
622
+ } catch (e) {
623
+ // Раньше здесь стояло `catch { return; }`: каталог мог быть недоступен,
624
+ // а канал молча не работал вовсе. Одна строка на каждую причину.
625
+ const key = `DIR:${e?.code ?? 'ERR'}`;
626
+ if (!a2aReported.has(key)) {
627
+ a2aReported.add(key);
628
+ log(`[a2a] \u{1F534} каталог входящих недоступен (${A2A_IN}): ${e?.message ?? e}`);
629
+ }
630
+ return;
631
+ }
632
+ const files = all.filter((f) => A2A_EXT.some((x) => f.endsWith(x)));
633
+ for (const f of all) {
634
+ if (files.includes(f) || a2aReported.has(f)) continue;
635
+ a2aReported.add(f);
636
+ log(`[a2a] \u{1F534} НЕ ВЗЯТ файл ${f}: беру только ${A2A_EXT.join(', ')}. `
637
+ + `Он так и будет лежать во входящих — переименуй отправителю`);
638
+ }
639
+ for (const name of [...a2aReported]) {
640
+ if (!name.startsWith('DIR:') && !all.includes(name)) a2aReported.delete(name);
641
+ }
609
642
  for (const f of files) {
610
643
  const full = path.join(A2A_IN, f);
611
644
  let text = '';