@link-assistant/hive-mind 1.56.18 → 1.57.0
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.
- package/CHANGELOG.md +23 -0
- package/README.hi.md +43 -2
- package/README.md +40 -2
- package/README.ru.md +45 -2
- package/README.zh.md +39 -2
- package/package.json +2 -2
- package/src/isolation-runner.lib.mjs +13 -4
- package/src/session-monitor.lib.mjs +15 -0
- package/src/telegram-bot.mjs +22 -27
- package/src/telegram-log-command.lib.mjs +372 -0
- package/src/telegram-safe-reply.lib.mjs +19 -0
- package/src/telegram-terminal-watch-command.lib.mjs +412 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.57.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 272a2d4: Add live terminal watch support for hive-telegram-bot
|
|
8
|
+
|
|
9
|
+
This feature adds `/terminal_watch` plus the experimental `--auto-start-screen-watch-message` option. The command watches the log reported by `$ --status <uuid>` and updates a separate Telegram message with a terminal-sized text snapshot.
|
|
10
|
+
|
|
11
|
+
Key features:
|
|
12
|
+
- Manual `/terminal_watch <uuid>` command, including reply-based usage
|
|
13
|
+
- Configurable terminal snapshot size with `--size`, `--width`, and `--height`
|
|
14
|
+
- Auto-freezes the watch message and attaches the full log when the session ends
|
|
15
|
+
- Public repository logs can update in chat; private/unknown visibility uses DM for manual watches
|
|
16
|
+
- Auto-start remains off by default and never starts for private or unknown-visibility repositories
|
|
17
|
+
|
|
18
|
+
Based on the proof-of-concept from konard/telegram-terminal-bot.
|
|
19
|
+
|
|
20
|
+
## 1.56.19
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- 0da8eba: Add a `/log` Telegram command that lets a chat owner pull the on-disk log of a `$` isolation session (`screen`, `tmux`, `docker`). The command accepts `/log <UUID>` directly or `/log` as a reply to any session message that contains a session UUID, validates the id with `$ --status`, derives the log path from start-command's `logPath` field, and uploads the file as a reply to the user. Logs from public GitHub repositories are uploaded to the same chat; logs from private (or unknown-visibility) repositories are sent via direct message after forwarding the originating session message into the DM, so private logs never leak into public chats. Access is restricted to the chat owner (Telegram `creator` status), matching the existing `/start`, `/stop`, and `/top` policy.
|
|
25
|
+
|
|
3
26
|
## 1.56.18
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/README.hi.md
CHANGED
|
@@ -431,9 +431,21 @@ Hive Mind को क्रिया में देखना चाहते
|
|
|
431
431
|
hive-telegram-bot 2>&1 | tee -a "logs/bot-$(date +%Y%m%d-%H%M%S).log"
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
+
**Experimental: live terminal watch**
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
hive-telegram-bot --auto-start-screen-watch-message
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
यह opt-in flag सार्वजनिक `/solve` sessions के लिए एक अलग live terminal
|
|
441
|
+
message शुरू करता है। Private या unknown-visibility repositories के लिए watch
|
|
442
|
+
message अपने आप शुरू नहीं होता।
|
|
443
|
+
|
|
434
444
|
### बॉट कमांड
|
|
435
445
|
|
|
436
|
-
|
|
446
|
+
अधिकांश operational commands केवल **ग्रुप चैट में** काम करते हैं (बॉट के साथ
|
|
447
|
+
निजी संदेशों में नहीं)। `/terminal_watch` जैसे commands, जो जानबूझकर private
|
|
448
|
+
updates भेजते हैं, direct messages में भी उपयोग किए जा सकते हैं:
|
|
437
449
|
|
|
438
450
|
#### `/solve` - GitHub इश्यू हल करें
|
|
439
451
|
|
|
@@ -494,6 +506,22 @@ Shows:
|
|
|
494
506
|
- Claude usage limits (session and weekly)
|
|
495
507
|
```
|
|
496
508
|
|
|
509
|
+
#### `/terminal_watch` - Live Session Log
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
/terminal_watch <uuid> [--size 120x25]
|
|
513
|
+
|
|
514
|
+
Examples:
|
|
515
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12
|
|
516
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12 --width 100 --height 20
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
आप bot session message पर `/terminal_watch` के साथ reply भी कर सकते हैं। यह
|
|
520
|
+
command `$ --status <uuid>` द्वारा report किए गए session log की latest lines के
|
|
521
|
+
साथ एक अलग Telegram message update करता है और session खत्म होने पर पूरी log file
|
|
522
|
+
attach करता है। Public repository logs chat में watch किए जा सकते हैं; private या
|
|
523
|
+
unknown-visibility repository logs केवल direct message से भेजे जाते हैं।
|
|
524
|
+
|
|
497
525
|
#### `/help` - सहायता और डायग्नोस्टिक जानकारी प्राप्त करें
|
|
498
526
|
|
|
499
527
|
```
|
|
@@ -508,12 +536,25 @@ Shows:
|
|
|
508
536
|
|
|
509
537
|
### विशेषताएँ
|
|
510
538
|
|
|
511
|
-
- ✅
|
|
539
|
+
- ✅ **Group Chat Execution**: `/solve` और `/hive` workflows authorized group chats से चलते हैं
|
|
512
540
|
- ✅ **पूर्ण विकल्प सपोर्ट**: सभी कमांड-लाइन विकल्प Telegram में काम करते हैं
|
|
513
541
|
- ✅ **Screen सत्र**: कमांड डिटैच्ड screen सत्रों में चलते हैं
|
|
542
|
+
- ✅ **Live Terminal Watch**: `/terminal_watch` और opt-in auto-start live session logs दिखाते हैं
|
|
514
543
|
- ✅ **चैट प्रतिबंध**: अनुमत चैट ID की वैकल्पिक सफेद सूची
|
|
515
544
|
- ✅ **डायग्नोस्टिक टूल**: चैट ID और कॉन्फ़िगरेशन जानकारी प्राप्त करें
|
|
516
545
|
|
|
546
|
+
#### Live Terminal Watch
|
|
547
|
+
|
|
548
|
+
`--auto-start-screen-watch-message` से enabled होने पर, bot public `/solve`
|
|
549
|
+
sessions के लिए अपने आप एक अलग live terminal watch message शुरू करता है:
|
|
550
|
+
|
|
551
|
+
- **Manual Watch**: `/terminal_watch <uuid>` या `/terminal_watch` के साथ reply
|
|
552
|
+
- **Real-time Updates**: Commands execute होते समय live session log output देखें
|
|
553
|
+
- **Auto-freeze**: Command पूरा होने पर message freeze हो जाता है
|
|
554
|
+
- **Log Attachment**: Session खत्म होने पर full logs अपने आप attach होते हैं
|
|
555
|
+
- **Security**: Private या unknown-visibility repositories के लिए auto-start disabled है
|
|
556
|
+
- **Smart Updates**: केवल वास्तविक बदलाव मिलने पर update करता है (API limits से बचने के लिए rate-limited)
|
|
557
|
+
|
|
517
558
|
### सुरक्षा नोट
|
|
518
559
|
|
|
519
560
|
- केवल उन ग्रुप चैट में काम करता है जहाँ बॉट एडमिन है
|
package/README.md
CHANGED
|
@@ -440,9 +440,19 @@ Want to see the Hive Mind in action? Request a free demo or get faster support b
|
|
|
440
440
|
hive-telegram-bot 2>&1 | tee -a "logs/bot-$(date +%Y%m%d-%H%M%S).log"
|
|
441
441
|
```
|
|
442
442
|
|
|
443
|
+
**Experimental: live terminal watch**
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
hive-telegram-bot --auto-start-screen-watch-message
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
This opt-in flag starts a separate live terminal message for public `/solve`
|
|
450
|
+
sessions. Private or unknown-visibility repositories never auto-start a
|
|
451
|
+
watch message.
|
|
452
|
+
|
|
443
453
|
### Bot Commands
|
|
444
454
|
|
|
445
|
-
|
|
455
|
+
Most operational commands work in **group chats only** (not in private messages with the bot). Commands that intentionally deliver private updates, such as `/terminal_watch`, may also be used in direct messages:
|
|
446
456
|
|
|
447
457
|
#### `/solve` - Solve GitHub Issues
|
|
448
458
|
|
|
@@ -514,6 +524,22 @@ Shows:
|
|
|
514
524
|
- Claude usage limits (session and weekly)
|
|
515
525
|
```
|
|
516
526
|
|
|
527
|
+
#### `/terminal_watch` - Live Session Log
|
|
528
|
+
|
|
529
|
+
```
|
|
530
|
+
/terminal_watch <uuid> [--size 120x25]
|
|
531
|
+
|
|
532
|
+
Examples:
|
|
533
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12
|
|
534
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12 --width 100 --height 20
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
You can also reply to a bot session message with `/terminal_watch`. The command
|
|
538
|
+
updates a separate Telegram message with the latest lines from the session log
|
|
539
|
+
reported by `$ --status <uuid>` and attaches the full log file when the session
|
|
540
|
+
finishes. Public repository logs can be watched in the chat; private or
|
|
541
|
+
unknown-visibility repository logs are delivered by direct message only.
|
|
542
|
+
|
|
517
543
|
#### `/help` - Get Help and Diagnostic Info
|
|
518
544
|
|
|
519
545
|
```
|
|
@@ -528,12 +554,24 @@ Shows:
|
|
|
528
554
|
|
|
529
555
|
### Features
|
|
530
556
|
|
|
531
|
-
- ✅ **Group Chat
|
|
557
|
+
- ✅ **Group Chat Execution**: `/solve` and `/hive` workflows run from authorized group chats
|
|
532
558
|
- ✅ **Full Options Support**: All command-line options work in Telegram
|
|
533
559
|
- ✅ **Screen Sessions**: Commands run in detached screen sessions
|
|
560
|
+
- ✅ **Live Terminal Watch**: `/terminal_watch` and opt-in auto-start show live session logs
|
|
534
561
|
- ✅ **Chat Restrictions**: Optional whitelist of allowed chat IDs
|
|
535
562
|
- ✅ **Diagnostic Tools**: Get chat ID and configuration info
|
|
536
563
|
|
|
564
|
+
#### Live Terminal Watch
|
|
565
|
+
|
|
566
|
+
When enabled with `--auto-start-screen-watch-message`, the bot automatically starts a separate live terminal watch message for public `/solve` sessions:
|
|
567
|
+
|
|
568
|
+
- **Manual Watch**: `/terminal_watch <uuid>` or reply with `/terminal_watch`
|
|
569
|
+
- **Real-time Updates**: See live session log output as commands execute
|
|
570
|
+
- **Auto-freeze**: Message freezes when command completes
|
|
571
|
+
- **Log Attachment**: Full logs attached automatically when session ends
|
|
572
|
+
- **Security**: Auto-start is disabled for private or unknown-visibility repositories
|
|
573
|
+
- **Smart Updates**: Only updates when actual changes detected (rate-limited to avoid API limits)
|
|
574
|
+
|
|
537
575
|
### Security Notes
|
|
538
576
|
|
|
539
577
|
- Only works in group chats where the bot is admin
|
package/README.ru.md
CHANGED
|
@@ -431,9 +431,22 @@ Hive Mind включает интерфейс Telegram-бота (SwarmMindBot)
|
|
|
431
431
|
hive-telegram-bot 2>&1 | tee -a "logs/bot-$(date +%Y%m%d-%H%M%S).log"
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
+
**Экспериментально: live terminal watch**
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
hive-telegram-bot --auto-start-screen-watch-message
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Этот opt-in флаг запускает отдельное live terminal сообщение для публичных
|
|
441
|
+
сессий `/solve`. Для приватных репозиториев или репозиториев с неизвестной
|
|
442
|
+
видимостью watch-сообщение автоматически не запускается.
|
|
443
|
+
|
|
434
444
|
### Команды бота
|
|
435
445
|
|
|
436
|
-
|
|
446
|
+
Большинство операционных команд работают **только в групповых чатах** (не в
|
|
447
|
+
личных сообщениях боту). Команды, которые намеренно доставляют приватные
|
|
448
|
+
обновления, например `/terminal_watch`, также можно использовать в личных
|
|
449
|
+
сообщениях:
|
|
437
450
|
|
|
438
451
|
#### `/solve` — Решение задач GitHub
|
|
439
452
|
|
|
@@ -494,6 +507,23 @@ Shows:
|
|
|
494
507
|
- Claude usage limits (session and weekly)
|
|
495
508
|
```
|
|
496
509
|
|
|
510
|
+
#### `/terminal_watch` — Live Session Log
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
/terminal_watch <uuid> [--size 120x25]
|
|
514
|
+
|
|
515
|
+
Examples:
|
|
516
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12
|
|
517
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12 --width 100 --height 20
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Также можно ответить на сообщение сессии бота командой `/terminal_watch`. Команда
|
|
521
|
+
обновляет отдельное сообщение Telegram последними строками лога сессии,
|
|
522
|
+
полученного через `$ --status <uuid>`, и прикрепляет полный файл лога после
|
|
523
|
+
завершения сессии. Логи публичных репозиториев можно смотреть в чате; логи
|
|
524
|
+
приватных репозиториев или репозиториев с неизвестной видимостью доставляются
|
|
525
|
+
только личным сообщением.
|
|
526
|
+
|
|
497
527
|
#### `/help` — Получить справку и диагностическую информацию
|
|
498
528
|
|
|
499
529
|
```
|
|
@@ -508,12 +538,25 @@ Shows:
|
|
|
508
538
|
|
|
509
539
|
### Возможности
|
|
510
540
|
|
|
511
|
-
- ✅
|
|
541
|
+
- ✅ **Запуск из групповых чатов**: workflows `/solve` и `/hive` запускаются из авторизованных групповых чатов
|
|
512
542
|
- ✅ **Полная поддержка параметров**: все параметры командной строки работают в Telegram
|
|
513
543
|
- ✅ **Screen-сессии**: команды запускаются в отсоединённых screen-сессиях
|
|
544
|
+
- ✅ **Live Terminal Watch**: `/terminal_watch` и opt-in auto-start показывают live session logs
|
|
514
545
|
- ✅ **Ограничения по чатам**: опциональный белый список разрешённых ID чатов
|
|
515
546
|
- ✅ **Диагностические инструменты**: получение ID чата и информации о конфигурации
|
|
516
547
|
|
|
548
|
+
#### Live Terminal Watch
|
|
549
|
+
|
|
550
|
+
Если включить `--auto-start-screen-watch-message`, бот автоматически запускает
|
|
551
|
+
отдельное live terminal watch сообщение для публичных сессий `/solve`:
|
|
552
|
+
|
|
553
|
+
- **Manual Watch**: `/terminal_watch <uuid>` или ответ командой `/terminal_watch`
|
|
554
|
+
- **Real-time Updates**: смотрите live session log output во время выполнения команд
|
|
555
|
+
- **Auto-freeze**: сообщение замораживается после завершения команды
|
|
556
|
+
- **Log Attachment**: полные логи автоматически прикрепляются после завершения сессии
|
|
557
|
+
- **Security**: auto-start отключён для приватных репозиториев и репозиториев с неизвестной видимостью
|
|
558
|
+
- **Smart Updates**: обновляет сообщение только при реальных изменениях (rate-limited для защиты от API limits)
|
|
559
|
+
|
|
517
560
|
### Замечания по безопасности
|
|
518
561
|
|
|
519
562
|
- Работает только в групповых чатах, где бот является администратором
|
package/README.zh.md
CHANGED
|
@@ -431,9 +431,18 @@ Hive Mind 内置 Telegram 机器人接口(SwarmMindBot),支持远程命令
|
|
|
431
431
|
hive-telegram-bot 2>&1 | tee -a "logs/bot-$(date +%Y%m%d-%H%M%S).log"
|
|
432
432
|
```
|
|
433
433
|
|
|
434
|
+
**实验性:live terminal watch**
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
hive-telegram-bot --auto-start-screen-watch-message
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
这个 opt-in 标志会为公开仓库的 `/solve` 会话启动一条单独的 live terminal
|
|
441
|
+
消息。私有仓库或可见性未知的仓库不会自动启动 watch 消息。
|
|
442
|
+
|
|
434
443
|
### 机器人命令
|
|
435
444
|
|
|
436
|
-
|
|
445
|
+
大多数操作类命令仅在**群聊中**有效(不支持与机器人的私聊)。有意发送私密更新的命令(例如 `/terminal_watch`)也可以在私聊中使用:
|
|
437
446
|
|
|
438
447
|
#### `/solve` - 解决 GitHub Issue
|
|
439
448
|
|
|
@@ -494,6 +503,21 @@ Shows:
|
|
|
494
503
|
- Claude usage limits (session and weekly)
|
|
495
504
|
```
|
|
496
505
|
|
|
506
|
+
#### `/terminal_watch` - Live Session Log
|
|
507
|
+
|
|
508
|
+
```
|
|
509
|
+
/terminal_watch <uuid> [--size 120x25]
|
|
510
|
+
|
|
511
|
+
Examples:
|
|
512
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12
|
|
513
|
+
/terminal_watch 4d934f71-4cdb-4b8c-b474-582116d12c12 --width 100 --height 20
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
您也可以回复机器人会话消息并发送 `/terminal_watch`。该命令会用
|
|
517
|
+
`$ --status <uuid>` 报告的会话日志最新内容更新一条单独的 Telegram
|
|
518
|
+
消息,并在会话结束时附加完整日志文件。公开仓库日志可以在群聊中 watch;
|
|
519
|
+
私有仓库或可见性未知仓库的日志只会通过私聊发送。
|
|
520
|
+
|
|
497
521
|
#### `/help` - 获取帮助和诊断信息
|
|
498
522
|
|
|
499
523
|
```
|
|
@@ -508,12 +532,25 @@ Shows:
|
|
|
508
532
|
|
|
509
533
|
### 功能特性
|
|
510
534
|
|
|
511
|
-
- ✅
|
|
535
|
+
- ✅ **群聊执行**:`/solve` 和 `/hive` workflow 从已授权群聊中运行
|
|
512
536
|
- ✅ **完整选项支持**:所有命令行选项均可在 Telegram 中使用
|
|
513
537
|
- ✅ **Screen 会话**:命令在后台 Screen 会话中运行
|
|
538
|
+
- ✅ **Live Terminal Watch**:`/terminal_watch` 和 opt-in auto-start 显示 live session logs
|
|
514
539
|
- ✅ **聊天限制**:可选配置允许的聊天 ID 白名单
|
|
515
540
|
- ✅ **诊断工具**:获取聊天 ID 和配置信息
|
|
516
541
|
|
|
542
|
+
#### Live Terminal Watch
|
|
543
|
+
|
|
544
|
+
启用 `--auto-start-screen-watch-message` 后,机器人会为公开仓库的 `/solve`
|
|
545
|
+
会话自动启动一条单独的 live terminal watch 消息:
|
|
546
|
+
|
|
547
|
+
- **Manual Watch**:`/terminal_watch <uuid>` 或回复 `/terminal_watch`
|
|
548
|
+
- **Real-time Updates**:在命令执行时查看 live session log output
|
|
549
|
+
- **Auto-freeze**:命令完成时消息会被冻结
|
|
550
|
+
- **Log Attachment**:会话结束时自动附加完整日志
|
|
551
|
+
- **Security**:私有仓库或可见性未知的仓库禁用 auto-start
|
|
552
|
+
- **Smart Updates**:仅在实际内容变化时更新(rate-limited 以避免 API limits)
|
|
553
|
+
|
|
517
554
|
### 安全注意事项
|
|
518
555
|
|
|
519
556
|
- 仅在机器人为管理员的群聊中有效
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/hive-mind",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.57.0",
|
|
4
4
|
"description": "AI-powered issue solver and hive mind for collaborative problem solving",
|
|
5
5
|
"main": "src/hive.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"hive-telegram-bot": "./src/telegram-bot.mjs"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"test": "node tests/solve-queue.test.mjs && node tests/limits-display.test.mjs && node tests/test-usage-limit.mjs && node tests/test-codex-support.mjs && node tests/test-build-cost-info-string.mjs && node tests/test-claude-code-install-method.mjs && node tests/test-claude-quiet-config.mjs && node tests/test-configure-claude-bin.mjs && node tests/test-docker-release-order.mjs && node tests/test-docker-box-migration.mjs && node tests/test-hive-screens.mjs && node tests/test-issue-1616-pr-issue-link-preservation.mjs && node tests/test-pre-pr-failure-notifier-1640.mjs && node tests/test-ready-to-merge-pagination-1645.mjs && node tests/test-require-gh-paginate-rule.mjs && node tests/test-auto-restart-limits-1664.mjs && node tests/test-log-upload-output-1678.mjs && node tests/test-log-upload-output-1682.mjs && node tests/test-telegram-message-filters.mjs && node tests/test-telegram-bot-command-aliases.mjs && node tests/test-telegram-options-before-url.mjs && node tests/test-telegram-bot-configuration-isolation-links-notation.mjs && node tests/test-extract-isolation-from-args.mjs && node tests/test-solve-queue-command.mjs && node tests/test-queue-display-1267.mjs && node tests/test-issue-1670-screen-status-monitoring.mjs && node tests/test-issue-1680-session-monitoring.mjs && node tests/test-issue-1684-message-formatting.mjs && node tests/test-issue-1688-subscribe-and-pr-link.mjs && node tests/test-issue-1694-stabilized-defaults.mjs && node tests/test-telegram-bot-launcher.mjs",
|
|
18
|
+
"test": "node tests/solve-queue.test.mjs && node tests/limits-display.test.mjs && node tests/test-usage-limit.mjs && node tests/test-codex-support.mjs && node tests/test-build-cost-info-string.mjs && node tests/test-claude-code-install-method.mjs && node tests/test-claude-quiet-config.mjs && node tests/test-configure-claude-bin.mjs && node tests/test-docker-release-order.mjs && node tests/test-docker-box-migration.mjs && node tests/test-hive-screens.mjs && node tests/test-issue-1616-pr-issue-link-preservation.mjs && node tests/test-pre-pr-failure-notifier-1640.mjs && node tests/test-ready-to-merge-pagination-1645.mjs && node tests/test-require-gh-paginate-rule.mjs && node tests/test-auto-restart-limits-1664.mjs && node tests/test-log-upload-output-1678.mjs && node tests/test-log-upload-output-1682.mjs && node tests/test-telegram-message-filters.mjs && node tests/test-telegram-bot-command-aliases.mjs && node tests/test-telegram-options-before-url.mjs && node tests/test-telegram-bot-configuration-isolation-links-notation.mjs && node tests/test-extract-isolation-from-args.mjs && node tests/test-solve-queue-command.mjs && node tests/test-queue-display-1267.mjs && node tests/test-issue-467-terminal-watch.mjs && node tests/test-issue-1670-screen-status-monitoring.mjs && node tests/test-issue-1680-session-monitoring.mjs && node tests/test-issue-1684-message-formatting.mjs && node tests/test-issue-1686-log-command.mjs && node tests/test-issue-1688-subscribe-and-pr-link.mjs && node tests/test-issue-1694-stabilized-defaults.mjs && node tests/test-telegram-bot-launcher.mjs",
|
|
19
19
|
"test:queue": "node tests/solve-queue.test.mjs",
|
|
20
20
|
"test:limits-display": "node tests/limits-display.test.mjs",
|
|
21
21
|
"test:usage-limit": "node tests/test-usage-limit.mjs",
|
|
@@ -41,17 +41,18 @@ export function generateSessionId() {
|
|
|
41
41
|
* Keep the parser tolerant so completion monitoring survives either format.
|
|
42
42
|
*
|
|
43
43
|
* @param {string} output - Raw stdout from `$ --status`
|
|
44
|
-
* @returns {{exists: boolean, uuid: string|null, status: string|null, exitCode: number|null, startTime: string|null, endTime: string|null, currentTime: string|null, raw: string}}
|
|
44
|
+
* @returns {{exists: boolean, uuid: string|null, status: string|null, exitCode: number|null, startTime: string|null, endTime: string|null, currentTime: string|null, logPath: string|null, command: string|null, isolation: string|null, workingDirectory: string|null, raw: string}}
|
|
45
45
|
*/
|
|
46
46
|
export function parseSessionStatusOutput(output) {
|
|
47
47
|
const raw = (output || '').trim();
|
|
48
48
|
if (!raw) {
|
|
49
|
-
return { exists: false, uuid: null, status: null, exitCode: null, startTime: null, endTime: null, currentTime: null, raw: '' };
|
|
49
|
+
return { exists: false, uuid: null, status: null, exitCode: null, startTime: null, endTime: null, currentTime: null, logPath: null, command: null, isolation: null, workingDirectory: null, raw: '' };
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
53
|
const parsed = JSON.parse(raw);
|
|
54
54
|
const data = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
55
|
+
const isolationFromOptions = typeof data?.options?.isolation === 'string' ? data.options.isolation.toLowerCase() : null;
|
|
55
56
|
return {
|
|
56
57
|
exists: true,
|
|
57
58
|
uuid: data?.uuid || null,
|
|
@@ -60,6 +61,10 @@ export function parseSessionStatusOutput(output) {
|
|
|
60
61
|
startTime: data?.startTime || null,
|
|
61
62
|
endTime: data?.endTime || null,
|
|
62
63
|
currentTime: data?.currentTime || null,
|
|
64
|
+
logPath: data?.logPath || null,
|
|
65
|
+
command: data?.command || null,
|
|
66
|
+
isolation: typeof data?.isolation === 'string' ? data.isolation.toLowerCase() : isolationFromOptions,
|
|
67
|
+
workingDirectory: data?.workingDirectory || null,
|
|
63
68
|
raw,
|
|
64
69
|
};
|
|
65
70
|
} catch {
|
|
@@ -87,6 +92,10 @@ export function parseSessionStatusOutput(output) {
|
|
|
87
92
|
startTime: readField('startTime'),
|
|
88
93
|
endTime: readField('endTime'),
|
|
89
94
|
currentTime: readField('currentTime'),
|
|
95
|
+
logPath: readField('logPath'),
|
|
96
|
+
command: readField('command'),
|
|
97
|
+
isolation: readField('isolation')?.toLowerCase() || null,
|
|
98
|
+
workingDirectory: readField('workingDirectory'),
|
|
90
99
|
raw,
|
|
91
100
|
};
|
|
92
101
|
}
|
|
@@ -213,7 +222,7 @@ export async function querySessionStatus(sessionId, verbose = false) {
|
|
|
213
222
|
if (verbose) {
|
|
214
223
|
console.log('[VERBOSE] isolation-runner: Cannot query status - $ binary not found');
|
|
215
224
|
}
|
|
216
|
-
return { exists: false, uuid: null, status: null, exitCode: null, startTime: null, endTime: null, currentTime: null, raw: '' };
|
|
225
|
+
return { exists: false, uuid: null, status: null, exitCode: null, startTime: null, endTime: null, currentTime: null, logPath: null, command: null, isolation: null, workingDirectory: null, raw: '' };
|
|
217
226
|
}
|
|
218
227
|
|
|
219
228
|
try {
|
|
@@ -230,7 +239,7 @@ export async function querySessionStatus(sessionId, verbose = false) {
|
|
|
230
239
|
if (verbose) {
|
|
231
240
|
console.log(`[VERBOSE] isolation-runner: Status query error: ${error.message}`);
|
|
232
241
|
}
|
|
233
|
-
return { exists: false, uuid: null, status: null, exitCode: null, startTime: null, endTime: null, currentTime: null, raw: '' };
|
|
242
|
+
return { exists: false, uuid: null, status: null, exitCode: null, startTime: null, endTime: null, currentTime: null, logPath: null, command: null, isolation: null, workingDirectory: null, raw: '' };
|
|
234
243
|
}
|
|
235
244
|
}
|
|
236
245
|
|
|
@@ -89,6 +89,21 @@ export function trackSession(sessionName, sessionInfo, verbose = false) {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Look up the in-memory record for a session id (UUID for isolation sessions
|
|
94
|
+
* or the screen session name for non-isolation sessions). Returns null when no
|
|
95
|
+
* record exists — for example, after a process restart or for sessions that
|
|
96
|
+
* were never tracked through the Telegram bot. Used by `/log` to discover the
|
|
97
|
+
* originating chat id and the GitHub URL associated with a session.
|
|
98
|
+
*
|
|
99
|
+
* @param {string} sessionName
|
|
100
|
+
* @returns {Object|null}
|
|
101
|
+
*/
|
|
102
|
+
export function getTrackedSessionInfo(sessionName) {
|
|
103
|
+
if (!sessionName) return null;
|
|
104
|
+
return activeSessions.get(sessionName) || null;
|
|
105
|
+
}
|
|
106
|
+
|
|
92
107
|
/**
|
|
93
108
|
* Get the number of active sessions being tracked
|
|
94
109
|
* @param {boolean} verbose - Whether to log verbose output
|
package/src/telegram-bot.mjs
CHANGED
|
@@ -49,6 +49,8 @@ const { getSolveQueue, createQueueExecuteCallback } = await import('./telegram-s
|
|
|
49
49
|
const { applySolveToolAlias, getFirstParsedPositionalArg, getSolveCommandNameFromText, getSolveToolAliasFromText, moveArgumentToFront, parseArgsWithYargs, parseCommandArgs, SOLVE_COMMAND_NAMES } = await import('./telegram-solve-command.lib.mjs');
|
|
50
50
|
const { isChatStopped, getChatStopInfo, getStoppedChatRejectMessage, DEFAULT_STOP_REASON } = await import('./telegram-start-stop-command.lib.mjs');
|
|
51
51
|
const { isOldMessage: _isOldMessage, isGroupChat: _isGroupChat, isChatAuthorized: _isChatAuthorized, isForwardedOrReply: _isForwardedOrReply, extractCommandFromText, extractGitHubUrl: _extractGitHubUrl } = await import('./telegram-message-filters.lib.mjs');
|
|
52
|
+
const { safeReply } = await import('./telegram-safe-reply.lib.mjs');
|
|
53
|
+
const { registerTerminalWatchCommand, startAutoTerminalWatchForSession } = await import('./telegram-terminal-watch-command.lib.mjs');
|
|
52
54
|
const { launchBotWithRetry } = await import('./telegram-bot-launcher.lib.mjs');
|
|
53
55
|
const { trackSession, startSessionMonitoring, hasActiveSessionForUrlAsync } = await import('./session-monitor.lib.mjs');
|
|
54
56
|
const { formatExecutingWorkSessionMessage, formatStartingWorkSessionMessage } = await import('./work-session-formatting.lib.mjs');
|
|
@@ -113,6 +115,7 @@ const config = yargs(hideBin(process.argv))
|
|
|
113
115
|
alias: 'v',
|
|
114
116
|
default: getenv('TELEGRAM_BOT_VERBOSE', 'false') === 'true',
|
|
115
117
|
})
|
|
118
|
+
.option('autoStartScreenWatchMessage', { type: 'boolean', description: 'Experimental: auto-start separate /terminal_watch messages for public /solve sessions', alias: 'auto-start-screen-watch-message', default: getenv('TELEGRAM_AUTO_START_SCREEN_WATCH_MESSAGE', getenv('TELEGRAM_AUTO_WATCH_MESSAGE', 'false')) === 'true' })
|
|
116
119
|
.option('isolation', { type: 'string', description: "Isolation backend (screen/tmux/docker). Defaults to 'screen' so Telegram-bot work sessions survive bot restarts; pass --isolation '' (or set TELEGRAM_ISOLATION='') to disable.", default: getenv('TELEGRAM_ISOLATION', 'screen') })
|
|
117
120
|
.help('h')
|
|
118
121
|
.alias('h', 'help')
|
|
@@ -130,6 +133,7 @@ if (config.configuration) {
|
|
|
130
133
|
|
|
131
134
|
const BOT_TOKEN = config.token || getenv('TELEGRAM_BOT_TOKEN', '');
|
|
132
135
|
const VERBOSE = config.verbose || getenv('TELEGRAM_BOT_VERBOSE', 'false') === 'true';
|
|
136
|
+
const AUTO_WATCH_MESSAGE = config.autoStartScreenWatchMessage === true;
|
|
133
137
|
if (!BOT_TOKEN) {
|
|
134
138
|
console.error('Error: TELEGRAM_BOT_TOKEN not set. Use --token or TELEGRAM_BOT_TOKEN env var.');
|
|
135
139
|
process.exit(1);
|
|
@@ -532,25 +536,6 @@ async function validateGitHubUrl(args, options = {}) {
|
|
|
532
536
|
return { valid: true, parsed, normalizedUrl: url };
|
|
533
537
|
}
|
|
534
538
|
|
|
535
|
-
// Issue #1460/#1497: safeReply - try Markdown first, fall back to plain text on parsing errors
|
|
536
|
-
async function safeReply(ctx, text, options = {}) {
|
|
537
|
-
try {
|
|
538
|
-
return await ctx.reply(text, { parse_mode: 'Markdown', ...options });
|
|
539
|
-
} catch (error) {
|
|
540
|
-
const isParsingError = error.message && (error.message.includes("can't parse entities") || error.message.includes("Can't parse entities") || error.message.includes("can't find end of") || (error.message.includes('Bad Request') && error.message.includes('400')));
|
|
541
|
-
if (!isParsingError) throw error;
|
|
542
|
-
console.error(`[telegram-bot] safeReply: Markdown parsing failed: ${error.message}`);
|
|
543
|
-
console.error(`[telegram-bot] safeReply: Failing message (${Buffer.byteLength(text, 'utf-8')} bytes): ${text}`);
|
|
544
|
-
const plainText = text
|
|
545
|
-
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1 ($2)')
|
|
546
|
-
.replace(/\\_/g, '_')
|
|
547
|
-
.replace(/\\\*/g, '*')
|
|
548
|
-
.replace(/\*([^*]+)\*/g, '$1')
|
|
549
|
-
.replace(/`([^`]+)`/g, '$1');
|
|
550
|
-
return await ctx.reply(plainText, { ...options, parse_mode: undefined });
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
539
|
async function executeAndUpdateMessage(ctx, startingMessage, commandName, args, infoBlock, perCommandIsolation = null, tool = 'claude', urlContext = null) {
|
|
555
540
|
const { chat, message_id: msgId } = startingMessage;
|
|
556
541
|
const safeEdit = async text => {
|
|
@@ -562,18 +547,24 @@ async function executeAndUpdateMessage(ctx, startingMessage, commandName, args,
|
|
|
562
547
|
};
|
|
563
548
|
const requesterUserId = ctx.from?.id ?? null; // Issue #1688: suppress duplicate /subscribe DM
|
|
564
549
|
const iso = await resolveIsolation(perCommandIsolation, ISOLATION_BACKEND, isolationRunner, VERBOSE);
|
|
565
|
-
let result, session;
|
|
550
|
+
let result, session, sessionInfo;
|
|
566
551
|
if (iso) {
|
|
567
552
|
session = iso.runner.generateSessionId();
|
|
568
553
|
VERBOSE && console.log(`[VERBOSE] Using isolation (${iso.backend}), session: ${session}`);
|
|
569
554
|
result = await iso.runner.executeWithIsolation(commandName, args, { backend: iso.backend, sessionId: session, verbose: VERBOSE });
|
|
570
|
-
if (result.success)
|
|
555
|
+
if (result.success) {
|
|
556
|
+
sessionInfo = { chatId: ctx.chat.id, messageId: msgId, startTime: new Date(), url: args[0], command: commandName, isolationBackend: iso.backend, sessionId: session, tool, infoBlock, urlContext, requesterUserId };
|
|
557
|
+
trackSession(session, sessionInfo, VERBOSE);
|
|
558
|
+
}
|
|
571
559
|
} else {
|
|
572
560
|
result = await executeStartScreen(commandName, args);
|
|
573
561
|
const match = result.success && (result.output.match(/session:\s*(\S+)/i) || result.output.match(/screen -R\s+(\S+)/));
|
|
574
562
|
session = match ? match[1] : 'unknown';
|
|
575
563
|
// Issue #1586: Non-isolation sessions auto-expire after 10 min — screen stays alive via `exec bash` so completion can't be detected reliably; this still blocks duplicate commands in the timeout window.
|
|
576
|
-
if (result.success && session !== 'unknown')
|
|
564
|
+
if (result.success && session !== 'unknown') {
|
|
565
|
+
sessionInfo = { chatId: ctx.chat.id, messageId: msgId, startTime: new Date(), url: args[0], command: commandName, tool, infoBlock, urlContext, requesterUserId };
|
|
566
|
+
trackSession(session, sessionInfo, VERBOSE);
|
|
567
|
+
}
|
|
577
568
|
}
|
|
578
569
|
if (result.warning) return safeEdit(`⚠️ ${result.warning}`);
|
|
579
570
|
if (result.success) {
|
|
@@ -584,6 +575,7 @@ async function executeAndUpdateMessage(ctx, startingMessage, commandName, args,
|
|
|
584
575
|
infoBlock,
|
|
585
576
|
})
|
|
586
577
|
);
|
|
578
|
+
if (AUTO_WATCH_MESSAGE && commandName === 'solve' && sessionInfo?.isolationBackend) await startAutoTerminalWatchForSession({ bot, ctx, sessionId: session, sessionInfo, verbose: VERBOSE });
|
|
587
579
|
} else await safeEdit(`❌ Error executing ${commandName} command:\n\n\`\`\`\n${result.error || result.output}\n\`\`\`\n\n${infoBlock}`);
|
|
588
580
|
}
|
|
589
581
|
|
|
@@ -662,12 +654,13 @@ bot.command('help', async ctx => {
|
|
|
662
654
|
message += "Merges all PRs with 'ready' label sequentially.\n";
|
|
663
655
|
message += '*/subscribe* / */unsubscribe* - 🔔 Get private DM forward of /solve completion (experimental, #1688)\n';
|
|
664
656
|
message += '*/help* - Show this help message\n';
|
|
665
|
-
message += '*/stop* - Stop accepting new tasks (owner only)\n';
|
|
666
|
-
message += '*/
|
|
667
|
-
message += '
|
|
657
|
+
message += '*/stop* / */start* - Stop or resume accepting new tasks (owner only)\n';
|
|
658
|
+
message += '*/log* - Fetch isolation session log (owner only). Usage: `/log <uuid>` or reply with `/log`\n';
|
|
659
|
+
message += '*/terminal\\_watch* - Live-update an isolation session log (owner only). Usage: `/terminal_watch <uuid>` or reply with `/terminal_watch`\n\n';
|
|
660
|
+
message += '🔔 *Session Notifications:* Completion notifications are automatic; use /subscribe for private DM forwards.\n';
|
|
668
661
|
if (ISOLATION_BACKEND) message += `🔒 *Isolation Mode:* \`${ISOLATION_BACKEND}\` (experimental)\n`;
|
|
669
662
|
message += '\n';
|
|
670
|
-
message += '⚠️ *Note:* /solve, /do, /continue, /claude, /codex, /opencode, /agent, /hive, /solve\\_queue, /limits, /version, /accept\\_invites, /merge, /stop and /start commands only work in group chats. /subscribe and /unsubscribe work in private and group chats.\n\n';
|
|
663
|
+
message += '⚠️ *Note:* /solve, /do, /continue, /claude, /codex, /opencode, /agent, /hive, /solve\\_queue, /limits, /version, /accept\\_invites, /merge, /stop and /start commands only work in group chats. /terminal\\_watch, /subscribe and /unsubscribe work in private and group chats.\n\n';
|
|
671
664
|
message += '🔧 *Common Options:*\n';
|
|
672
665
|
message += `• \`--model <model>\` or \`-m\` - ${buildModelOptionDescription()}\n`;
|
|
673
666
|
message += '• `--base-branch <branch>` or `-b` - Target branch for PR (default: repo default branch)\n';
|
|
@@ -763,7 +756,6 @@ bot.command('version', async ctx => {
|
|
|
763
756
|
await ctx.telegram.editMessageText(fetchingMessage.chat.id, fetchingMessage.message_id, undefined, '🤖 *Version Information*\n\n' + formatVersionMessage(result.versions), { parse_mode: 'Markdown' });
|
|
764
757
|
});
|
|
765
758
|
|
|
766
|
-
// Register external command modules (keeps telegram-bot.mjs under line limit)
|
|
767
759
|
const { registerAcceptInvitesCommand } = await import('./telegram-accept-invitations.lib.mjs');
|
|
768
760
|
const sharedCommandOpts = { VERBOSE, isOldMessage, isForwardedOrReply, isGroupChat: _isGroupChat, isChatAuthorized, isTopicAuthorized, buildAuthErrorMessage, addBreadcrumb, isChatStopped, getStoppedChatRejectMessage };
|
|
769
761
|
registerAcceptInvitesCommand(bot, sharedCommandOpts);
|
|
@@ -1191,8 +1183,11 @@ bot.command(/^hive$/i, handleHiveCommand);
|
|
|
1191
1183
|
|
|
1192
1184
|
const { registerTopCommand } = await import('./telegram-top-command.lib.mjs');
|
|
1193
1185
|
const { registerStartStopCommands } = await import('./telegram-start-stop-command.lib.mjs');
|
|
1186
|
+
const { registerLogCommand } = await import('./telegram-log-command.lib.mjs');
|
|
1194
1187
|
registerTopCommand(bot, sharedCommandOpts);
|
|
1195
1188
|
registerStartStopCommands(bot, sharedCommandOpts);
|
|
1189
|
+
await registerLogCommand(bot, sharedCommandOpts);
|
|
1190
|
+
await registerTerminalWatchCommand(bot, sharedCommandOpts);
|
|
1196
1191
|
|
|
1197
1192
|
// Add message listener for verbose debugging
|
|
1198
1193
|
if (VERBOSE) {
|