@wrongstack/telegram 0.1.0 → 0.3.4
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/README.md +171 -149
- package/dist/index.js +25 -10
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,156 +1,178 @@
|
|
|
1
|
-
# @wrongstack/telegram
|
|
2
|
-
|
|
3
|
-
Telegram bridge for WrongStack — connect your agent to Telegram.
|
|
4
|
-
Send messages, receive instructions, get notified when long tasks finish.
|
|
5
|
-
|
|
6
|
-
## Features
|
|
7
|
-
|
|
8
|
-
- **`telegram_read`** — Agent reads incoming Telegram messages (newest first, filtered by chat, with ack support)
|
|
9
|
-
- **`telegram_send`** — Agent sends messages via Telegram (HTML formatting, confirm permission)
|
|
10
|
-
- **System prompt injection** — Unread messages appear in the agent's system prompt so it sees them naturally
|
|
11
|
-
- **Slash commands** — `/
|
|
12
|
-
- **Event notifications** — Session end summaries and long tool completions forwarded to Telegram
|
|
13
|
-
- **Allowlist filtering** — Restrict which users/chats can interact with the bot
|
|
14
|
-
- **Zero dependencies** — Uses Node.js native `fetch`, no third-party Telegram libraries
|
|
15
|
-
|
|
16
|
-
## Quickstart
|
|
17
|
-
|
|
18
|
-
### 1. Create a bot
|
|
19
|
-
|
|
20
|
-
Message [@BotFather](https://t.me/BotFather) on Telegram:
|
|
21
|
-
```
|
|
22
|
-
/newbot
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Copy the token (looks like `123456789:ABCdef...`).
|
|
26
|
-
|
|
27
|
-
### 2. Get your chat ID
|
|
28
|
-
|
|
29
|
-
Message your new bot, then visit:
|
|
30
|
-
```
|
|
31
|
-
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Find your `chat.id` in the response.
|
|
35
|
-
|
|
36
|
-
### 3.
|
|
37
|
-
|
|
38
|
-
In `~/.wrongstack/config.json` or `.wrongstack/config.json`:
|
|
39
|
-
|
|
40
|
-
```jsonc
|
|
41
|
-
{
|
|
42
|
-
"plugins": {
|
|
43
|
-
"telegram": {
|
|
44
|
-
"botToken": "123456789:ABCdefGHIjkl...",
|
|
45
|
-
"notifyChatId": "987654321",
|
|
46
|
-
"allowedUsers": [987654321],
|
|
47
|
-
"notifyOnSessionEnd": true,
|
|
48
|
-
"longToolThresholdMs": 30000,
|
|
49
|
-
"pollIntervalSec": 2
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 4. Install
|
|
1
|
+
# @wrongstack/telegram
|
|
2
|
+
|
|
3
|
+
Telegram bridge for WrongStack — connect your agent to Telegram.
|
|
4
|
+
Send messages, receive instructions, get notified when long tasks finish.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **`telegram_read`** — Agent reads incoming Telegram messages (newest first, filtered by chat, with ack support)
|
|
9
|
+
- **`telegram_send`** — Agent sends messages via Telegram (HTML formatting, confirm permission)
|
|
10
|
+
- **System prompt injection** — Unread messages appear in the agent's system prompt so it sees them naturally
|
|
11
|
+
- **Slash commands** — `/telegram:status`, `/telegram:send`, `/telegram:chatid` in the TUI
|
|
12
|
+
- **Event notifications** — Session end summaries and long tool completions forwarded to Telegram
|
|
13
|
+
- **Allowlist filtering** — Restrict which users/chats can interact with the bot
|
|
14
|
+
- **Zero dependencies** — Uses Node.js native `fetch`, no third-party Telegram libraries
|
|
15
|
+
|
|
16
|
+
## Quickstart
|
|
17
|
+
|
|
18
|
+
### 1. Create a bot
|
|
19
|
+
|
|
20
|
+
Message [@BotFather](https://t.me/BotFather) on Telegram:
|
|
21
|
+
```
|
|
22
|
+
/newbot
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Copy the token (looks like `123456789:ABCdef...`).
|
|
26
|
+
|
|
27
|
+
### 2. Get your chat ID
|
|
28
|
+
|
|
29
|
+
Message your new bot, then visit:
|
|
30
|
+
```
|
|
31
|
+
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Find your `chat.id` in the response.
|
|
35
|
+
|
|
36
|
+
### 3. Enable the official plugin
|
|
56
37
|
|
|
57
38
|
```bash
|
|
58
|
-
|
|
39
|
+
wstack plugin install telegram
|
|
59
40
|
```
|
|
60
41
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
| Field | Type | Required | Default | Description |
|
|
66
|
-
|---|---|---|---|---|
|
|
67
|
-
| `botToken` | `string` | **yes** | — | Bot token from @BotFather |
|
|
68
|
-
| `notifyChatId` | `string \| number` | no | — | Default chat for outgoing messages and notifications |
|
|
69
|
-
| `allowedUsers` | `(string \| number)[]` | no | `[]` | User IDs allowed to interact. Empty = all allowed |
|
|
70
|
-
| `allowedChats` | `(string \| number)[]` | no | `[]` | Chat IDs the bot reads from. Empty = all allowed |
|
|
71
|
-
| `pollIntervalSec` | `number` | no | `2` | How often to poll Telegram for new messages (1–60) |
|
|
72
|
-
| `notifyOnSessionEnd` | `boolean` | no | `false` | Send token usage summary when a session ends |
|
|
73
|
-
| `longToolThresholdMs` | `number` | no | `30000` | Notify when a tool runs longer than this (ms). `0` = off |
|
|
74
|
-
| `maxMessageLength` | `number` | no | `4000` | Max chars per outgoing message (Telegram limit: 4096) |
|
|
75
|
-
|
|
76
|
-
## Tools
|
|
77
|
-
|
|
78
|
-
### `telegram_read`
|
|
42
|
+
`telegram` is the bundled official alias for `@wrongstack/telegram`. In
|
|
43
|
+
WrongStack 0.3.4 and newer, the package is installed with the `wrongstack`
|
|
44
|
+
umbrella package; this command only enables plugin loading in config and does
|
|
45
|
+
not run npm.
|
|
79
46
|
|
|
80
|
-
|
|
47
|
+
If you are installing the plugin into a custom host instead of the official
|
|
48
|
+
CLI package, add it like a normal public package:
|
|
81
49
|
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
telegram_read()
|
|
85
|
-
|
|
86
|
-
// Read from a specific chat
|
|
87
|
-
telegram_read(chat_id: "987654321", limit: 5)
|
|
88
|
-
|
|
89
|
-
// Read and acknowledge (clear from buffer)
|
|
90
|
-
telegram_read(ack_last: 42)
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Permission: `auto` | Category: `Telegram`
|
|
94
|
-
|
|
95
|
-
### `telegram_send`
|
|
96
|
-
|
|
97
|
-
Send a message to a Telegram chat.
|
|
98
|
-
|
|
99
|
-
```jsonc
|
|
100
|
-
// Send using default chat
|
|
101
|
-
telegram_send(message: "Build succeeded ✓")
|
|
102
|
-
|
|
103
|
-
// Send to a specific chat
|
|
104
|
-
telegram_send(chat_id: "123456", message: "Deploy complete. Check staging.")
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Permission: `confirm` | Category: `Telegram`
|
|
108
|
-
|
|
109
|
-
Message text supports Telegram HTML: `<b>bold</b>`, `<i>italic</i>`, `<code>mono</code>`, `<a href="...">links</a>`, `<pre>code blocks</pre>`.
|
|
110
|
-
|
|
111
|
-
## Slash commands (TUI)
|
|
112
|
-
|
|
113
|
-
| Command | Description |
|
|
114
|
-
|---|---|
|
|
115
|
-
| `/tg status` | Bot connection health, polling config, allowlist stats, notification settings |
|
|
116
|
-
| `/tg send [chat_id] <msg>` | Send a message from the terminal |
|
|
117
|
-
| `/tg chatid` | Show the configured default chat ID |
|
|
118
|
-
|
|
119
|
-
## How it works
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
┌─────────────────┐ poll ┌──────────────┐
|
|
123
|
-
│ Telegram API │◄──────────────│ TelegramBot │
|
|
124
|
-
│ (getUpdates) │──────────────►│ (buffer) │
|
|
125
|
-
└────────┬────────┘ updates └──────┬───────┘
|
|
126
|
-
│ │
|
|
127
|
-
user sends ┌────▼───────┐
|
|
128
|
-
"build failed?" │ PluginAPI │
|
|
129
|
-
│ .emitCustom│
|
|
130
|
-
│ .contrib. │
|
|
131
|
-
└────┬───────┘
|
|
132
|
-
│
|
|
133
|
-
┌─────────▼─────────┐
|
|
134
|
-
│ Agent sees inbox │
|
|
135
|
-
│ in system prompt │
|
|
136
|
-
│ calls read/send │
|
|
137
|
-
└───────────────────┘
|
|
50
|
+
```bash
|
|
51
|
+
npm install @wrongstack/telegram
|
|
138
52
|
```
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
53
|
+
|
|
54
|
+
### 4. Configure
|
|
55
|
+
|
|
56
|
+
In `~/.wrongstack/config.json` or `.wrongstack/config.json`:
|
|
57
|
+
|
|
58
|
+
```jsonc
|
|
59
|
+
{
|
|
60
|
+
"features": {
|
|
61
|
+
"plugins": true
|
|
62
|
+
},
|
|
63
|
+
"plugins": ["@wrongstack/telegram"],
|
|
64
|
+
"extensions": {
|
|
65
|
+
"telegram": {
|
|
66
|
+
"botToken": "123456789:ABCdefGHIjkl...",
|
|
67
|
+
"notifyChatId": "987654321",
|
|
68
|
+
"allowedUsers": [987654321],
|
|
69
|
+
"notifyOnSessionEnd": true,
|
|
70
|
+
"longToolThresholdMs": 30000,
|
|
71
|
+
"pollIntervalSec": 2
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The `plugins` array controls loading. `extensions.telegram` stores this
|
|
78
|
+
plugin's options.
|
|
79
|
+
|
|
80
|
+
The plugin loads on the next WrongStack start. Use
|
|
81
|
+
`wstack plugin disable @wrongstack/telegram` and
|
|
82
|
+
`wstack plugin enable @wrongstack/telegram` to turn it off/on without deleting
|
|
83
|
+
the Telegram options.
|
|
84
|
+
|
|
85
|
+
## Configuration reference
|
|
86
|
+
|
|
87
|
+
| Field | Type | Required | Default | Description |
|
|
88
|
+
|---|---|---|---|---|
|
|
89
|
+
| `botToken` | `string` | **yes** | — | Bot token from @BotFather |
|
|
90
|
+
| `notifyChatId` | `string \| number` | no | — | Default chat for outgoing messages and notifications |
|
|
91
|
+
| `allowedUsers` | `(string \| number)[]` | no | `[]` | User IDs allowed to interact. Empty = all allowed |
|
|
92
|
+
| `allowedChats` | `(string \| number)[]` | no | `[]` | Chat IDs the bot reads from. Empty = all allowed |
|
|
93
|
+
| `pollIntervalSec` | `number` | no | `2` | How often to poll Telegram for new messages (1–60) |
|
|
94
|
+
| `notifyOnSessionEnd` | `boolean` | no | `false` | Send token usage summary when a session ends |
|
|
95
|
+
| `longToolThresholdMs` | `number` | no | `30000` | Notify when a tool runs longer than this (ms). `0` = off |
|
|
96
|
+
| `maxMessageLength` | `number` | no | `4000` | Max chars per outgoing message (Telegram limit: 4096) |
|
|
97
|
+
|
|
98
|
+
## Tools
|
|
99
|
+
|
|
100
|
+
### `telegram_read`
|
|
101
|
+
|
|
102
|
+
Read buffered incoming messages.
|
|
103
|
+
|
|
104
|
+
```jsonc
|
|
105
|
+
// Read all recent messages
|
|
106
|
+
telegram_read()
|
|
107
|
+
|
|
108
|
+
// Read from a specific chat
|
|
109
|
+
telegram_read(chat_id: "987654321", limit: 5)
|
|
110
|
+
|
|
111
|
+
// Read and acknowledge (clear from buffer)
|
|
112
|
+
telegram_read(ack_last: 42)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Permission: `auto` | Category: `Telegram`
|
|
116
|
+
|
|
117
|
+
### `telegram_send`
|
|
118
|
+
|
|
119
|
+
Send a message to a Telegram chat.
|
|
120
|
+
|
|
121
|
+
```jsonc
|
|
122
|
+
// Send using default chat
|
|
123
|
+
telegram_send(message: "Build succeeded ✓")
|
|
124
|
+
|
|
125
|
+
// Send to a specific chat
|
|
126
|
+
telegram_send(chat_id: "123456", message: "Deploy complete. Check staging.")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Permission: `confirm` | Category: `Telegram`
|
|
130
|
+
|
|
131
|
+
Message text supports Telegram HTML: `<b>bold</b>`, `<i>italic</i>`, `<code>mono</code>`, `<a href="...">links</a>`, `<pre>code blocks</pre>`.
|
|
132
|
+
|
|
133
|
+
## Slash commands (TUI)
|
|
134
|
+
|
|
135
|
+
| Command | Description |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `/telegram:status` | Bot connection health, polling config, allowlist stats, notification settings |
|
|
138
|
+
| `/telegram:send [chat_id] <msg>` | Send a message from the terminal |
|
|
139
|
+
| `/telegram:chatid` | Show the configured default chat ID |
|
|
140
|
+
|
|
141
|
+
## How it works
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
┌─────────────────┐ poll ┌──────────────┐
|
|
145
|
+
│ Telegram API │◄──────────────│ TelegramBot │
|
|
146
|
+
│ (getUpdates) │──────────────►│ (buffer) │
|
|
147
|
+
└────────┬────────┘ updates └──────┬───────┘
|
|
148
|
+
│ │
|
|
149
|
+
user sends ┌────▼───────┐
|
|
150
|
+
"build failed?" │ PluginAPI │
|
|
151
|
+
│ .emitCustom│
|
|
152
|
+
│ .contrib. │
|
|
153
|
+
└────┬───────┘
|
|
154
|
+
│
|
|
155
|
+
┌─────────▼─────────┐
|
|
156
|
+
│ Agent sees inbox │
|
|
157
|
+
│ in system prompt │
|
|
158
|
+
│ calls read/send │
|
|
159
|
+
└───────────────────┘
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
1. Bot polls Telegram every N seconds via `getUpdates`
|
|
163
|
+
2. Incoming messages go into a circular buffer (50 max)
|
|
164
|
+
3. A system prompt contributor injects unread messages so the agent sees them
|
|
165
|
+
4. Agent reads with `telegram_read`, responds with `telegram_send`
|
|
166
|
+
5. Custom event `telegram:message_received` fires for TUI panels / other plugins
|
|
167
|
+
|
|
168
|
+
## Events
|
|
169
|
+
|
|
170
|
+
| Event | Payload | When |
|
|
171
|
+
|---|---|---|
|
|
172
|
+
| `telegram:message_received` | `TelegramIncomingMessage` | Incoming message passes allowlist |
|
|
173
|
+
| `session.ended` | session summary → Telegram | If `notifyOnSessionEnd: true` |
|
|
174
|
+
| `tool.executed` | tool result → Telegram | If duration > `longToolThresholdMs` |
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -245,13 +245,28 @@ var telegramConfigSchema = {
|
|
|
245
245
|
required: ["botToken"]
|
|
246
246
|
};
|
|
247
247
|
function readTelegramConfig(api) {
|
|
248
|
-
const
|
|
249
|
-
const
|
|
248
|
+
const config = api.config;
|
|
249
|
+
const extensions = config.extensions;
|
|
250
|
+
const pluginEntries = config.plugins;
|
|
251
|
+
const legacyPlugins = pluginEntries;
|
|
252
|
+
const legacyOpts = legacyPlugins && !Array.isArray(legacyPlugins) ? legacyPlugins[PLUGIN_NAME] : void 0;
|
|
253
|
+
const entryOpts = pluginOptionsFromEntries(pluginEntries);
|
|
254
|
+
const opts = {
|
|
255
|
+
...legacyOpts ?? entryOpts,
|
|
256
|
+
...extensions?.[PLUGIN_NAME] ?? {}
|
|
257
|
+
};
|
|
250
258
|
return {
|
|
251
259
|
...DEFAULT_CONFIG,
|
|
252
260
|
...opts
|
|
253
261
|
};
|
|
254
262
|
}
|
|
263
|
+
function pluginOptionsFromEntries(entries) {
|
|
264
|
+
if (!Array.isArray(entries)) return void 0;
|
|
265
|
+
const found = entries.find(
|
|
266
|
+
(entry) => typeof entry === "object" && entry !== null && "name" in entry && (entry.name === "@wrongstack/telegram" || entry.name === PLUGIN_NAME)
|
|
267
|
+
);
|
|
268
|
+
return found?.options && typeof found.options === "object" ? found.options : void 0;
|
|
269
|
+
}
|
|
255
270
|
|
|
256
271
|
// src/slash-commands/index.ts
|
|
257
272
|
function tgStatusCommand(bot, cfg) {
|
|
@@ -259,7 +274,7 @@ function tgStatusCommand(bot, cfg) {
|
|
|
259
274
|
name: "status",
|
|
260
275
|
aliases: ["tgstat", "tgs"],
|
|
261
276
|
description: "Show Telegram bot connection status and config",
|
|
262
|
-
help: `Usage: /
|
|
277
|
+
help: `Usage: /telegram:status
|
|
263
278
|
|
|
264
279
|
Shows whether the bot is connected, its username, polling interval,
|
|
265
280
|
allowlist status, and notification settings.`,
|
|
@@ -283,18 +298,18 @@ function tgSendCommand(bot, defaultChatId) {
|
|
|
283
298
|
return {
|
|
284
299
|
name: "send",
|
|
285
300
|
description: "Send a message to a Telegram chat",
|
|
286
|
-
help: `Usage: /
|
|
301
|
+
help: `Usage: /telegram:send [chat_id] <message>
|
|
287
302
|
|
|
288
303
|
Send a message to a Telegram chat.
|
|
289
304
|
- First argument (optional): chat or user ID. Uses notifyChatId from config when omitted.
|
|
290
305
|
- Everything else: the message text.
|
|
291
306
|
|
|
292
307
|
Examples:
|
|
293
|
-
/
|
|
294
|
-
/
|
|
308
|
+
/telegram:send 123456789 Build completed successfully \u2713
|
|
309
|
+
/telegram:send Deploy finished \u2014 check staging`,
|
|
295
310
|
async run(args, _ctx) {
|
|
296
311
|
if (!args.trim()) {
|
|
297
|
-
return { message: "Usage: /
|
|
312
|
+
return { message: "Usage: /telegram:send [chat_id] <message>" };
|
|
298
313
|
}
|
|
299
314
|
let chatId;
|
|
300
315
|
let text;
|
|
@@ -308,7 +323,7 @@ Examples:
|
|
|
308
323
|
text = args.trim();
|
|
309
324
|
} else {
|
|
310
325
|
return {
|
|
311
|
-
message: "No chat_id provided and no default notifyChatId configured.\nUsage: /
|
|
326
|
+
message: "No chat_id provided and no default notifyChatId configured.\nUsage: /telegram:send <chat_id> <message>"
|
|
312
327
|
};
|
|
313
328
|
}
|
|
314
329
|
try {
|
|
@@ -327,7 +342,7 @@ function tgChatIdCommand(defaultChatId) {
|
|
|
327
342
|
return {
|
|
328
343
|
name: "chatid",
|
|
329
344
|
description: "Show the configured default chat ID",
|
|
330
|
-
help: `Usage: /
|
|
345
|
+
help: `Usage: /telegram:chatid
|
|
331
346
|
|
|
332
347
|
Shows the current default notifyChatId used for notifications
|
|
333
348
|
and the \`telegram_send\` tool when no chat_id is specified.`,
|
|
@@ -456,7 +471,7 @@ function makeTelegramSendTool(opts) {
|
|
|
456
471
|
var teardownState = null;
|
|
457
472
|
var plugin = {
|
|
458
473
|
name: PLUGIN_NAME,
|
|
459
|
-
version: "0.
|
|
474
|
+
version: "0.3.4",
|
|
460
475
|
description: "Telegram bridge \u2014 send/receive messages, get agent notifications.",
|
|
461
476
|
apiVersion: "^0.1.10",
|
|
462
477
|
capabilities: {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bot.ts","../src/config.ts","../src/slash-commands/index.ts","../src/tools/telegram-read.ts","../src/tools/telegram-send.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Logger } from '@wrongstack/core';\n\n// ---------------------------------------------------------------------------\n// Telegram Bot API types (subset used by this plugin)\n// ---------------------------------------------------------------------------\n\ninterface TgUser {\n id: number;\n is_bot: boolean;\n first_name: string;\n username?: string;\n}\n\ninterface TgChat {\n id: number;\n type: 'private' | 'group' | 'supergroup' | 'channel';\n title?: string;\n username?: string;\n}\n\ninterface TgMessage {\n message_id: number;\n from?: TgUser;\n chat: TgChat;\n date: number;\n text?: string;\n}\n\ninterface TgUpdate {\n update_id: number;\n message?: TgMessage;\n edited_message?: TgMessage;\n}\n\ninterface TgResponse<T> {\n ok: boolean;\n result?: T;\n description?: string;\n error_code?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Incoming message shape emitted as a custom event\n// ---------------------------------------------------------------------------\n\nexport interface TelegramIncomingMessage {\n messageId: number;\n chatId: number;\n chatType: string;\n userId?: number;\n userName?: string;\n text: string;\n timestamp: number;\n}\n\n// ---------------------------------------------------------------------------\n// Bot options\n// ---------------------------------------------------------------------------\n\nexport interface TelegramBotOptions {\n token: string;\n pollIntervalSec: number;\n allowedUsers: Set<string>;\n allowedChats: Set<string>;\n /** Max messages to buffer for the agent to read. Default: 50. */\n bufferSize: number;\n log: Logger;\n /** Called for each incoming message that passes allowlist checks. */\n onMessage(msg: TelegramIncomingMessage): void;\n}\n\n// ---------------------------------------------------------------------------\n// Bot\n// ---------------------------------------------------------------------------\n\nexport class TelegramBot {\n private readonly token: string;\n private readonly baseUrl: string;\n private readonly pollIntervalMs: number;\n private readonly allowedUsers: Set<string>;\n private readonly allowedChats: Set<string>;\n private readonly log: Logger;\n private readonly onMessage: (msg: TelegramIncomingMessage) => void;\n private readonly controller = new AbortController();\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private pollActive = false;\n private offset = 0;\n private _startedAt: number | null = null;\n\n // Circular buffer for incoming messages\n private readonly bufferMax: number;\n private readonly buffer: TelegramIncomingMessage[] = [];\n\n constructor(opts: TelegramBotOptions) {\n this.token = opts.token;\n this.baseUrl = `https://api.telegram.org/bot${opts.token}`;\n this.pollIntervalMs = opts.pollIntervalSec * 1000;\n this.allowedUsers = opts.allowedUsers;\n this.allowedChats = opts.allowedChats;\n this.bufferMax = opts.bufferSize;\n this.log = opts.log;\n this.onMessage = opts.onMessage;\n }\n\n // ------------------------------------------------------------------\n // Lifecycle\n // ------------------------------------------------------------------\n\n /** Start polling for updates. Idempotent. */\n start(): void {\n if (this.pollActive) return;\n this.pollActive = true;\n this._startedAt = Date.now();\n this.log.info('Telegram bot polling started');\n this.schedulePoll();\n }\n\n /** Stop polling and cancel all in-flight requests. */\n stop(): void {\n this.pollActive = false;\n this.controller.abort();\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.log.info('Telegram bot stopped');\n }\n\n get startedAt(): number | null {\n return this._startedAt;\n }\n\n get running(): boolean {\n return this.pollActive;\n }\n\n // ------------------------------------------------------------------\n // Buffer — incoming messages the agent can read\n // ------------------------------------------------------------------\n\n /** Return buffered messages, newest first. Optionally filter by chat. */\n getMessages(opts?: { chatId?: string | number; limit?: number }): TelegramIncomingMessage[] {\n let msgs = [...this.buffer].reverse();\n if (opts?.chatId) {\n const cid = String(opts.chatId);\n msgs = msgs.filter((m) => String(m.chatId) === cid);\n }\n const limit = opts?.limit ?? 20;\n return msgs.slice(0, limit);\n }\n\n /** Drop messages older than the given message ID from the buffer. */\n acknowledge(lastMessageId: number): number {\n const before = this.buffer.length;\n let i = this.buffer.length;\n while (i-- > 0) {\n if (this.buffer[i]!.messageId <= lastMessageId) {\n this.buffer.splice(0, i + 1);\n break;\n }\n }\n return before - this.buffer.length;\n }\n\n get bufferCount(): number {\n return this.buffer.length;\n }\n\n // ------------------------------------------------------------------\n // Outgoing — send a message\n // ------------------------------------------------------------------\n\n async sendMessage(chatId: string | number, text: string): Promise<TgResponse<TgMessage>> {\n const url = `${this.baseUrl}/sendMessage`;\n const body = JSON.stringify({\n chat_id: String(chatId),\n text,\n parse_mode: 'HTML',\n disable_web_page_preview: true,\n });\n\n this.log.debug(`Sending Telegram message to ${chatId} (${text.length} chars)`);\n\n let lastErr: unknown;\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n signal: AbortSignal.timeout(10_000),\n });\n const data = (await res.json()) as TgResponse<TgMessage>;\n if (!data.ok) {\n throw new Error(`Telegram API error ${data.error_code}: ${data.description}`);\n }\n return data;\n } catch (err) {\n lastErr = err;\n if (attempt < 3) {\n this.log.warn(`Telegram sendMessage attempt ${attempt} failed, retrying in 1s...`);\n await sleep(1000);\n }\n }\n }\n throw lastErr;\n }\n\n // ------------------------------------------------------------------\n // Health\n // ------------------------------------------------------------------\n\n async health(): Promise<{ ok: boolean; username?: string; error?: string }> {\n try {\n const url = `${this.baseUrl}/getMe`;\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n const data = (await res.json()) as TgResponse<TgUser>;\n if (!data.ok || !data.result) {\n return { ok: false, error: data.description ?? 'Unknown error' };\n }\n return { ok: true, username: data.result.username };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n }\n\n // ------------------------------------------------------------------\n // Polling\n // ------------------------------------------------------------------\n\n private schedulePoll(): void {\n if (!this.pollActive) return;\n this.pollTimer = setTimeout(() => {\n void this.poll().finally(() => this.schedulePoll());\n }, this.pollIntervalMs);\n }\n\n private async poll(): Promise<void> {\n try {\n const url = `${this.baseUrl}/getUpdates?offset=${this.offset}&timeout=10`;\n const res = await fetch(url, { signal: this.controller.signal });\n const data = (await res.json()) as TgResponse<TgUpdate[]>;\n\n if (!data.ok) {\n this.log.warn(`Telegram getUpdates failed: ${data.description}`);\n return;\n }\n\n const updates = data.result ?? [];\n for (const upd of updates) {\n this.offset = upd.update_id + 1;\n const raw = upd.message ?? upd.edited_message;\n if (!raw?.text) continue;\n const msg = { ...raw, text: raw.text };\n this.processMessage(msg);\n }\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n this.log.warn(`Telegram poll error: ${(err as Error).message}`);\n }\n }\n\n private processMessage(msg: TgMessage & { text: string }): void {\n const chatId = String(msg.chat.id);\n const userId = msg.from ? String(msg.from.id) : undefined;\n\n // Allowlist checks\n if (this.allowedUsers.size > 0 && userId && !this.allowedUsers.has(userId)) {\n this.log.debug(`Ignoring message from user ${userId} (not in allowedUsers)`);\n void this.sendMessage(chatId, '⛔ You are not authorized to interact with this bot.');\n return;\n }\n if (this.allowedChats.size > 0 && !this.allowedChats.has(chatId)) {\n this.log.debug(`Ignoring message from chat ${chatId} (not in allowedChats)`);\n return;\n }\n\n const incoming: TelegramIncomingMessage = {\n messageId: msg.message_id,\n chatId: msg.chat.id,\n chatType: msg.chat.type,\n userId: msg.from?.id,\n userName: msg.from?.username ?? msg.from?.first_name,\n text: msg.text,\n timestamp: msg.date * 1000,\n };\n\n // Push to circular buffer\n this.buffer.push(incoming);\n while (this.buffer.length > this.bufferMax) this.buffer.shift();\n\n this.onMessage(incoming);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Truncate text to fit Telegram's 4096-char message limit.\n * Splits on a newline when possible; otherwise hard-cuts with \"…\" suffix.\n */\nexport function truncateForTelegram(text: string, maxLen = 4000): string {\n if (text.length <= maxLen) return text;\n const cut = text.lastIndexOf('\\n', maxLen - 20);\n const idx = cut > maxLen / 2 ? cut : maxLen - 20;\n return `${text.slice(0, idx)}\\n\\n…[truncated ${text.length - idx} chars]`;\n}\n\n/**\n * Escape HTML special chars for Telegram's HTML parse mode.\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n","import type { PluginAPI } from '@wrongstack/core';\n\nexport const PLUGIN_NAME = 'telegram';\n\nexport interface TelegramPluginConfig {\n /** Telegram Bot API token (from @BotFather). */\n botToken: string;\n /**\n * Default chat ID for outgoing notifications.\n * The agent's `telegram_send` tool can override per-call.\n */\n notifyChatId?: string | number;\n /**\n * List of user/chat IDs allowed to interact with the bot.\n * Empty = allow all. Recommended to set in production.\n */\n allowedUsers?: Array<string | number>;\n /**\n * List of group/chat IDs the bot is allowed to read from.\n * Empty = allow all. Narrow this to prevent noise.\n */\n allowedChats?: Array<string | number>;\n /** Polling interval in seconds (default: 2). */\n pollIntervalSec?: number;\n /** Notify on Telegram when a session ends. */\n notifyOnSessionEnd?: boolean;\n /** Notify when a tool runs longer than this threshold (ms). Set 0 to disable. */\n longToolThresholdMs?: number;\n /** Maximum message length for Telegram (Telegram caps at 4096). */\n maxMessageLength?: number;\n}\n\nexport const DEFAULT_CONFIG: Required<Omit<TelegramPluginConfig, 'botToken' | 'notifyChatId'>> = {\n allowedUsers: [],\n allowedChats: [],\n pollIntervalSec: 2,\n notifyOnSessionEnd: false,\n longToolThresholdMs: 30_000,\n maxMessageLength: 4000,\n};\n\nexport const telegramConfigSchema = {\n type: 'object',\n properties: {\n botToken: { type: 'string', description: 'Telegram Bot API token from @BotFather' },\n notifyChatId: {\n oneOf: [{ type: 'string' }, { type: 'integer' }],\n description: 'Default chat ID for outgoing notifications',\n },\n allowedUsers: {\n type: 'array',\n items: { oneOf: [{ type: 'string' }, { type: 'integer' }] },\n description: 'User IDs allowed to interact with the bot',\n },\n allowedChats: {\n type: 'array',\n items: { oneOf: [{ type: 'string' }, { type: 'integer' }] },\n description: 'Chat IDs the bot is allowed to read from',\n },\n pollIntervalSec: {\n type: 'integer',\n minimum: 1,\n maximum: 60,\n description: 'Polling interval in seconds',\n },\n notifyOnSessionEnd: { type: 'boolean' },\n longToolThresholdMs: { type: 'integer', minimum: 0 },\n maxMessageLength: { type: 'integer', minimum: 100, maximum: 4096 },\n },\n required: ['botToken'],\n};\n\nexport function readTelegramConfig(\n api: Pick<PluginAPI, 'config'>,\n): Required<Omit<TelegramPluginConfig, 'notifyChatId'>> & Pick<TelegramPluginConfig, 'notifyChatId'> {\n const raw = (api.config as unknown as Record<string, unknown>).plugins as\n | Record<string, unknown>\n | undefined;\n const opts = (raw?.[PLUGIN_NAME] ?? {}) as TelegramPluginConfig;\n return {\n ...DEFAULT_CONFIG,\n ...opts,\n };\n}\n","import type { PluginAPI, SlashCommand } from '@wrongstack/core';\nimport type { TelegramBot } from '../bot.js';\nimport type { TelegramPluginConfig } from '../config.js';\n\n// ---------------------------------------------------------------------------\n// /tg status\n// ---------------------------------------------------------------------------\n\nexport function tgStatusCommand(bot: TelegramBot, cfg: TelegramPluginConfig): SlashCommand {\n return {\n name: 'status',\n aliases: ['tgstat', 'tgs'],\n description: 'Show Telegram bot connection status and config',\n help: `Usage: /tg status\n\nShows whether the bot is connected, its username, polling interval,\nallowlist status, and notification settings.`,\n async run(_args, _ctx) {\n const health = await bot.health();\n const lines = [\n '═══ Telegram Plugin Status ═══',\n '',\n `Bot: ${health.ok ? `✅ @${health.username ?? 'connected'}` : `❌ ${health.error ?? 'offline'}`}`,\n `Running: ${bot.running ? 'yes' : 'no'}`,\n `Started: ${bot.startedAt ? new Date(bot.startedAt).toLocaleTimeString() : 'N/A'}`,\n `Poll: every ${cfg.pollIntervalSec ?? 2}s`,\n `Allowed: ${(cfg.allowedUsers?.length ?? 0) > 0 ? `${cfg.allowedUsers!.length} users` : 'everyone (users)'} / ${(cfg.allowedChats?.length ?? 0) > 0 ? `${cfg.allowedChats!.length} chats` : 'everyone (chats)'}`,\n `Notify: sessionEnd=${cfg.notifyOnSessionEnd ?? false}, longTool=${cfg.longToolThresholdMs ? `${cfg.longToolThresholdMs}ms` : 'off'}`,\n ];\n\n return { message: lines.join('\\n') };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// /tg send\n// ---------------------------------------------------------------------------\n\nexport function tgSendCommand(\n bot: TelegramBot,\n defaultChatId: string | number | undefined,\n): SlashCommand {\n return {\n name: 'send',\n description: 'Send a message to a Telegram chat',\n help: `Usage: /tg send [chat_id] <message>\n\nSend a message to a Telegram chat.\n- First argument (optional): chat or user ID. Uses notifyChatId from config when omitted.\n- Everything else: the message text.\n\nExamples:\n /tg send 123456789 Build completed successfully ✓\n /tg send Deploy finished — check staging`,\n async run(args, _ctx) {\n if (!args.trim()) {\n return { message: 'Usage: /tg send [chat_id] <message>' };\n }\n\n let chatId: string | number;\n let text: string;\n\n // First token might be a numeric chat_id\n const parts = args.trim().split(/\\s+/);\n const maybeId = parts[0];\n if (/^\\d+$/.test(maybeId!) && parts.length > 1) {\n chatId = maybeId!;\n text = parts.slice(1).join(' ');\n } else if (defaultChatId) {\n chatId = defaultChatId;\n text = args.trim();\n } else {\n return {\n message:\n 'No chat_id provided and no default notifyChatId configured.\\nUsage: /tg send <chat_id> <message>',\n };\n }\n\n try {\n const res = await bot.sendMessage(chatId, text);\n return {\n message: `✅ Message sent to ${chatId} (msg_id=${res.result?.message_id ?? '?'})`,\n };\n } catch (err) {\n return { message: `❌ Failed to send: ${(err as Error).message}` };\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// /tg chatid\n// ---------------------------------------------------------------------------\n\nexport function tgChatIdCommand(defaultChatId?: string | number): SlashCommand {\n const chatIdStr = defaultChatId ? String(defaultChatId) : null;\n return {\n name: 'chatid',\n description: 'Show the configured default chat ID',\n help: `Usage: /tg chatid\n\nShows the current default notifyChatId used for notifications\nand the \\`telegram_send\\` tool when no chat_id is specified.`,\n async run(_args, _ctx) {\n if (chatIdStr) {\n return { message: `Configured notifyChatId: ${chatIdStr}` };\n }\n return { message: 'No notifyChatId configured. Set it in the plugin config or pass chat_id explicitly to telegram_send.' };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Register all\n// ---------------------------------------------------------------------------\n\nexport function registerSlashCommands(\n api: PluginAPI,\n bot: TelegramBot,\n cfg: TelegramPluginConfig,\n): string[] {\n const cmds = [\n tgStatusCommand(bot, cfg),\n tgSendCommand(bot, cfg.notifyChatId),\n tgChatIdCommand(cfg.notifyChatId),\n ];\n for (const cmd of cmds) api.slashCommands.register(cmd);\n return cmds.map((c) => c.name);\n}\n","import type { Tool } from '@wrongstack/core';\nimport type { TelegramBot } from '../bot.js';\n\ninterface TelegramReadInput {\n /** Filter to messages from a specific chat/user ID. Omit to see all chats. */\n chat_id?: string | number;\n /** Max messages to return (default: 10, max: 50). */\n limit?: number;\n /**\n * If a message_id is provided, acknowledge all messages up to and\n * including this ID (mark them as processed / remove from buffer).\n */\n ack_last?: number;\n}\n\nexport function makeTelegramReadTool(opts: {\n bot: TelegramBot;\n}): Tool<TelegramReadInput> {\n return {\n name: 'telegram_read',\n description:\n 'Read incoming Telegram messages from the bot. Returns recent messages the bot received, newest first. Use this to check if anyone sent instructions, questions, or feedback via Telegram. After processing messages, pass the last message_id to ack_last to clear them from the inbox.',\n usageHint: 'telegram_read(chat_id: \"123456789\", limit: 5)',\n category: 'Telegram',\n inputSchema: {\n type: 'object',\n properties: {\n chat_id: {\n oneOf: [{ type: 'string' }, { type: 'integer' }],\n description: 'Read messages only from this chat/user.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: 50,\n description: 'Max messages to return (default: 10).',\n },\n ack_last: {\n type: 'integer',\n description:\n 'After processing messages, pass the highest message_id to clear them from the buffer.',\n },\n },\n },\n permission: 'auto',\n mutating: false,\n timeoutMs: 5_000,\n async execute(input) {\n const msgs = opts.bot.getMessages({\n chatId: input.chat_id,\n limit: input.limit ?? 10,\n });\n\n let acked = 0;\n if (input.ack_last !== undefined && input.ack_last > 0) {\n acked = opts.bot.acknowledge(input.ack_last);\n }\n\n return {\n buffer_total: opts.bot.bufferCount,\n messages: msgs.map((m) => ({\n message_id: m.messageId,\n chat_id: m.chatId,\n chat_type: m.chatType,\n from: m.userName ?? `user_${m.userId ?? 'unknown'}`,\n text: m.text,\n ts: new Date(m.timestamp).toISOString(),\n })),\n acked,\n hint: acked > 0\n ? undefined\n : 'Use ack_last with the highest message_id to clear processed messages.',\n };\n },\n };\n}\n","import type { Tool } from '@wrongstack/core';\nimport type { Logger } from '@wrongstack/core';\nimport type { TelegramBot } from '../bot.js';\nimport { escapeHtml, truncateForTelegram } from '../bot.js';\n\ninterface TelegramSendInput {\n /** Chat or user ID to send the message to. Falls back to config.notifyChatId when omitted. */\n chat_id?: string | number;\n /** Message text. Supports Telegram HTML parse mode. */\n message: string;\n}\n\nexport function makeTelegramSendTool(opts: {\n bot: TelegramBot;\n defaultChatId?: string | number;\n maxMessageLength: number;\n log: Logger;\n}): Tool<TelegramSendInput> {\n return {\n name: 'telegram_send',\n description:\n 'Send a message via Telegram to a specified chat. Use this to notify users, report results, or communicate through Telegram. The message supports HTML formatting (bold, italic, code, links).',\n usageHint: 'telegram_send(chat_id: \"123456789\", message: \"Task completed ✓\")',\n category: 'Telegram',\n inputSchema: {\n type: 'object',\n properties: {\n chat_id: {\n oneOf: [{ type: 'string' }, { type: 'integer' }],\n description: 'Target chat or user ID. Uses the plugin default when omitted.',\n },\n message: {\n type: 'string',\n description:\n 'Message text (supports HTML: <b>bold</b>, <i>italic</i>, <code>mono</code>, <a href=\"...\">links</a>).',\n },\n },\n required: ['message'],\n },\n permission: 'confirm',\n mutating: true,\n timeoutMs: 15_000,\n async execute(input, _ctx, _opts) {\n const chatId = input.chat_id ?? opts.defaultChatId;\n if (!chatId) {\n throw new Error(\n 'No chat_id provided and no default notifyChatId configured. Set notifyChatId in plugin config or pass chat_id.',\n );\n }\n\n // Format: wrap the message in a code block if it looks like raw output\n const safeMsg = escapeHtml(input.message);\n const truncated = truncateForTelegram(safeMsg, opts.maxMessageLength);\n\n opts.log.info(`telegram_send → chat_id=${chatId} (${truncated.length} chars)`);\n\n const res = await opts.bot.sendMessage(chatId, truncated);\n\n return {\n ok: res.ok,\n message_id: res.result?.message_id,\n chat: res.result?.chat\n ? {\n id: res.result.chat.id,\n type: res.result.chat.type,\n title: res.result.chat.title,\n }\n : undefined,\n };\n },\n };\n}\n","import type { Plugin } from '@wrongstack/core';\nimport type { Logger } from '@wrongstack/core';\nimport { TelegramBot } from './bot.js';\nimport type { TelegramIncomingMessage } from './bot.js';\nimport { truncateForTelegram, escapeHtml } from './bot.js';\nimport { PLUGIN_NAME, readTelegramConfig, telegramConfigSchema } from './config.js';\nimport { registerSlashCommands } from './slash-commands/index.js';\nimport { makeTelegramReadTool } from './tools/telegram-read.js';\nimport { makeTelegramSendTool } from './tools/telegram-send.js';\n\n// ---------------------------------------------------------------------------\n// Teardown state\n// ---------------------------------------------------------------------------\n\nlet teardownState: {\n offs: Array<() => void>;\n toolNames: string[];\n commandNames: string[];\n bot: TelegramBot;\n} | null = null;\n\n// ---------------------------------------------------------------------------\n// Plugin\n// ---------------------------------------------------------------------------\n\nconst plugin: Plugin = {\n name: PLUGIN_NAME,\n version: '0.1.0',\n description: 'Telegram bridge — send/receive messages, get agent notifications.',\n apiVersion: '^0.1.10',\n capabilities: {\n tools: true,\n slashCommands: true,\n pipelines: [],\n },\n configSchema: telegramConfigSchema,\n defaultConfig: {\n pollIntervalSec: 2,\n notifyOnSessionEnd: false,\n longToolThresholdMs: 30_000,\n maxMessageLength: 4000,\n },\n\n async setup(api) {\n const cfg = readTelegramConfig(api);\n const log = api.log;\n\n log.info('Starting Telegram plugin...');\n\n // ---- Bot ----\n const bot = new TelegramBot({\n token: cfg.botToken,\n pollIntervalSec: cfg.pollIntervalSec,\n allowedUsers: new Set((cfg.allowedUsers ?? []).map(String)),\n allowedChats: new Set((cfg.allowedChats ?? []).map(String)),\n bufferSize: 50,\n log,\n onMessage(msg: TelegramIncomingMessage) {\n // Emit custom event so other plugins or the host can react.\n // The TUI can subscribe and surface it (future hook).\n api.emitCustom('telegram:message_received', msg);\n\n // Log it for the user in the TUI\n const who = msg.userName ?? msg.userId ?? 'unknown';\n log.info(`📨 Telegram: ${who} (chat=${msg.chatId}): ${msg.text.slice(0, 200)}`);\n },\n });\n\n // ---- Register tools ----\n const sendTool = makeTelegramSendTool({\n bot,\n defaultChatId: cfg.notifyChatId,\n maxMessageLength: cfg.maxMessageLength,\n log,\n });\n const readTool = makeTelegramReadTool({ bot });\n api.tools.register(sendTool);\n api.tools.register(readTool);\n\n // ---- Event subscriptions ----\n const offs: Array<() => void> = [];\n\n // System prompt contributor — inject unread Telegram messages\n const unregisterPrompt = api.registerSystemPromptContributor(async () => {\n const msgs = bot.getMessages({ limit: 5 });\n if (msgs.length === 0) return [];\n\n const blocks: Array<{ type: 'text'; text: string }> = [\n {\n type: 'text',\n text: [\n '## Telegram Inbox',\n `You have ${bot.bufferCount} unread Telegram message(s).`,\n 'Read them with `telegram_read` and reply with `telegram_send`.',\n '',\n 'Recent messages:',\n ...msgs.map((m) => {\n const who = m.userName ?? `user_${m.userId ?? 'unknown'}`;\n const ts = new Date(m.timestamp).toLocaleTimeString();\n return `- [${ts}] **${who}** (chat=${m.chatId}): ${m.text.slice(0, 200)}`;\n }),\n '',\n ].join('\\n'),\n },\n ];\n return blocks;\n });\n offs.push(unregisterPrompt);\n\n // Register slash commands\n const commandNames = registerSlashCommands(api, bot, cfg);\n\n // Notify on session end\n if (cfg.notifyOnSessionEnd && cfg.notifyChatId) {\n offs.push(\n api.events.on('session.ended', (event) => {\n const inputTokens = event.usage.input ?? 0;\n const outputTokens = event.usage.output ?? 0;\n const totalTokens = inputTokens + outputTokens;\n const msg = [\n '✅ <b>Session ended</b>',\n '',\n `Session: <code>${event.id.slice(0, 8)}</code>`,\n `Input: ${inputTokens} tokens`,\n `Output: ${outputTokens} tokens`,\n `Total: ${totalTokens} tokens`,\n ].join('\\n');\n\n void bot.sendMessage(cfg.notifyChatId!, msg).catch((err) => {\n log.warn(`Failed to send session end notification: ${(err as Error).message}`);\n });\n }),\n );\n }\n\n // Notify for long-running tools\n if (cfg.longToolThresholdMs && cfg.longToolThresholdMs > 0 && cfg.notifyChatId) {\n offs.push(\n api.events.on('tool.executed', (event) => {\n if (event.durationMs < cfg.longToolThresholdMs!) return;\n const sec = (event.durationMs / 1000).toFixed(1);\n const status = event.ok ? '✅' : '❌';\n const preview = event.output\n ? truncateForTelegram(escapeHtml(event.output), 500)\n : '(no output)';\n\n const msg = [\n `${status} <b>${escapeHtml(event.name)}</b> completed in ${sec}s`,\n '',\n `<pre>${preview}</pre>`,\n ].join('\\n');\n\n void bot.sendMessage(cfg.notifyChatId!, msg).catch((err) => {\n log.warn(`Failed to send tool notification: ${(err as Error).message}`);\n });\n }),\n );\n }\n\n // ---- Start polling ----\n bot.start();\n\n teardownState = { offs, toolNames: [sendTool.name, readTool.name], commandNames, bot };\n\n log.info('Telegram plugin ready');\n },\n\n async teardown(api) {\n const state = teardownState;\n if (!state) return;\n teardownState = null;\n\n state.bot.stop();\n for (const off of state.offs) off();\n for (const name of state.toolNames) api.tools.unregister(name);\n for (const name of state.commandNames) {\n api.slashCommands.unregister(`${PLUGIN_NAME}:${name}`);\n }\n\n api.log.info('Telegram plugin torn down');\n },\n\n async health() {\n const state = teardownState;\n if (!state?.bot) return { ok: false, message: 'Plugin not initialized' };\n const h = await state.bot.health();\n return h;\n },\n};\n\nexport default plugin;\n\n// Re-export the types consumers may want\nexport type { TelegramIncomingMessage } from './bot.js';\nexport type { TelegramPluginConfig } from './config.js';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/bot.ts","../src/config.ts","../src/slash-commands/index.ts","../src/tools/telegram-read.ts","../src/tools/telegram-send.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Logger } from '@wrongstack/core';\n\n// ---------------------------------------------------------------------------\n// Telegram Bot API types (subset used by this plugin)\n// ---------------------------------------------------------------------------\n\ninterface TgUser {\n id: number;\n is_bot: boolean;\n first_name: string;\n username?: string;\n}\n\ninterface TgChat {\n id: number;\n type: 'private' | 'group' | 'supergroup' | 'channel';\n title?: string;\n username?: string;\n}\n\ninterface TgMessage {\n message_id: number;\n from?: TgUser;\n chat: TgChat;\n date: number;\n text?: string;\n}\n\ninterface TgUpdate {\n update_id: number;\n message?: TgMessage;\n edited_message?: TgMessage;\n}\n\ninterface TgResponse<T> {\n ok: boolean;\n result?: T;\n description?: string;\n error_code?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Incoming message shape emitted as a custom event\n// ---------------------------------------------------------------------------\n\nexport interface TelegramIncomingMessage {\n messageId: number;\n chatId: number;\n chatType: string;\n userId?: number;\n userName?: string;\n text: string;\n timestamp: number;\n}\n\n// ---------------------------------------------------------------------------\n// Bot options\n// ---------------------------------------------------------------------------\n\nexport interface TelegramBotOptions {\n token: string;\n pollIntervalSec: number;\n allowedUsers: Set<string>;\n allowedChats: Set<string>;\n /** Max messages to buffer for the agent to read. Default: 50. */\n bufferSize: number;\n log: Logger;\n /** Called for each incoming message that passes allowlist checks. */\n onMessage(msg: TelegramIncomingMessage): void;\n}\n\n// ---------------------------------------------------------------------------\n// Bot\n// ---------------------------------------------------------------------------\n\nexport class TelegramBot {\n private readonly token: string;\n private readonly baseUrl: string;\n private readonly pollIntervalMs: number;\n private readonly allowedUsers: Set<string>;\n private readonly allowedChats: Set<string>;\n private readonly log: Logger;\n private readonly onMessage: (msg: TelegramIncomingMessage) => void;\n private readonly controller = new AbortController();\n private pollTimer: ReturnType<typeof setTimeout> | null = null;\n private pollActive = false;\n private offset = 0;\n private _startedAt: number | null = null;\n\n // Circular buffer for incoming messages\n private readonly bufferMax: number;\n private readonly buffer: TelegramIncomingMessage[] = [];\n\n constructor(opts: TelegramBotOptions) {\n this.token = opts.token;\n this.baseUrl = `https://api.telegram.org/bot${opts.token}`;\n this.pollIntervalMs = opts.pollIntervalSec * 1000;\n this.allowedUsers = opts.allowedUsers;\n this.allowedChats = opts.allowedChats;\n this.bufferMax = opts.bufferSize;\n this.log = opts.log;\n this.onMessage = opts.onMessage;\n }\n\n // ------------------------------------------------------------------\n // Lifecycle\n // ------------------------------------------------------------------\n\n /** Start polling for updates. Idempotent. */\n start(): void {\n if (this.pollActive) return;\n this.pollActive = true;\n this._startedAt = Date.now();\n this.log.info('Telegram bot polling started');\n this.schedulePoll();\n }\n\n /** Stop polling and cancel all in-flight requests. */\n stop(): void {\n this.pollActive = false;\n this.controller.abort();\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n this.log.info('Telegram bot stopped');\n }\n\n get startedAt(): number | null {\n return this._startedAt;\n }\n\n get running(): boolean {\n return this.pollActive;\n }\n\n // ------------------------------------------------------------------\n // Buffer — incoming messages the agent can read\n // ------------------------------------------------------------------\n\n /** Return buffered messages, newest first. Optionally filter by chat. */\n getMessages(opts?: { chatId?: string | number; limit?: number }): TelegramIncomingMessage[] {\n let msgs = [...this.buffer].reverse();\n if (opts?.chatId) {\n const cid = String(opts.chatId);\n msgs = msgs.filter((m) => String(m.chatId) === cid);\n }\n const limit = opts?.limit ?? 20;\n return msgs.slice(0, limit);\n }\n\n /** Drop messages older than the given message ID from the buffer. */\n acknowledge(lastMessageId: number): number {\n const before = this.buffer.length;\n let i = this.buffer.length;\n while (i-- > 0) {\n if (this.buffer[i]!.messageId <= lastMessageId) {\n this.buffer.splice(0, i + 1);\n break;\n }\n }\n return before - this.buffer.length;\n }\n\n get bufferCount(): number {\n return this.buffer.length;\n }\n\n // ------------------------------------------------------------------\n // Outgoing — send a message\n // ------------------------------------------------------------------\n\n async sendMessage(chatId: string | number, text: string): Promise<TgResponse<TgMessage>> {\n const url = `${this.baseUrl}/sendMessage`;\n const body = JSON.stringify({\n chat_id: String(chatId),\n text,\n parse_mode: 'HTML',\n disable_web_page_preview: true,\n });\n\n this.log.debug(`Sending Telegram message to ${chatId} (${text.length} chars)`);\n\n let lastErr: unknown;\n for (let attempt = 1; attempt <= 3; attempt++) {\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n signal: AbortSignal.timeout(10_000),\n });\n const data = (await res.json()) as TgResponse<TgMessage>;\n if (!data.ok) {\n throw new Error(`Telegram API error ${data.error_code}: ${data.description}`);\n }\n return data;\n } catch (err) {\n lastErr = err;\n if (attempt < 3) {\n this.log.warn(`Telegram sendMessage attempt ${attempt} failed, retrying in 1s...`);\n await sleep(1000);\n }\n }\n }\n throw lastErr;\n }\n\n // ------------------------------------------------------------------\n // Health\n // ------------------------------------------------------------------\n\n async health(): Promise<{ ok: boolean; username?: string; error?: string }> {\n try {\n const url = `${this.baseUrl}/getMe`;\n const res = await fetch(url, { signal: AbortSignal.timeout(5000) });\n const data = (await res.json()) as TgResponse<TgUser>;\n if (!data.ok || !data.result) {\n return { ok: false, error: data.description ?? 'Unknown error' };\n }\n return { ok: true, username: data.result.username };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n }\n\n // ------------------------------------------------------------------\n // Polling\n // ------------------------------------------------------------------\n\n private schedulePoll(): void {\n if (!this.pollActive) return;\n this.pollTimer = setTimeout(() => {\n void this.poll().finally(() => this.schedulePoll());\n }, this.pollIntervalMs);\n }\n\n private async poll(): Promise<void> {\n try {\n const url = `${this.baseUrl}/getUpdates?offset=${this.offset}&timeout=10`;\n const res = await fetch(url, { signal: this.controller.signal });\n const data = (await res.json()) as TgResponse<TgUpdate[]>;\n\n if (!data.ok) {\n this.log.warn(`Telegram getUpdates failed: ${data.description}`);\n return;\n }\n\n const updates = data.result ?? [];\n for (const upd of updates) {\n this.offset = upd.update_id + 1;\n const raw = upd.message ?? upd.edited_message;\n if (!raw?.text) continue;\n const msg = { ...raw, text: raw.text };\n this.processMessage(msg);\n }\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n this.log.warn(`Telegram poll error: ${(err as Error).message}`);\n }\n }\n\n private processMessage(msg: TgMessage & { text: string }): void {\n const chatId = String(msg.chat.id);\n const userId = msg.from ? String(msg.from.id) : undefined;\n\n // Allowlist checks\n if (this.allowedUsers.size > 0 && userId && !this.allowedUsers.has(userId)) {\n this.log.debug(`Ignoring message from user ${userId} (not in allowedUsers)`);\n void this.sendMessage(chatId, '⛔ You are not authorized to interact with this bot.');\n return;\n }\n if (this.allowedChats.size > 0 && !this.allowedChats.has(chatId)) {\n this.log.debug(`Ignoring message from chat ${chatId} (not in allowedChats)`);\n return;\n }\n\n const incoming: TelegramIncomingMessage = {\n messageId: msg.message_id,\n chatId: msg.chat.id,\n chatType: msg.chat.type,\n userId: msg.from?.id,\n userName: msg.from?.username ?? msg.from?.first_name,\n text: msg.text,\n timestamp: msg.date * 1000,\n };\n\n // Push to circular buffer\n this.buffer.push(incoming);\n while (this.buffer.length > this.bufferMax) this.buffer.shift();\n\n this.onMessage(incoming);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Truncate text to fit Telegram's 4096-char message limit.\n * Splits on a newline when possible; otherwise hard-cuts with \"…\" suffix.\n */\nexport function truncateForTelegram(text: string, maxLen = 4000): string {\n if (text.length <= maxLen) return text;\n const cut = text.lastIndexOf('\\n', maxLen - 20);\n const idx = cut > maxLen / 2 ? cut : maxLen - 20;\n return `${text.slice(0, idx)}\\n\\n…[truncated ${text.length - idx} chars]`;\n}\n\n/**\n * Escape HTML special chars for Telegram's HTML parse mode.\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n","import type { PluginAPI } from '@wrongstack/core';\r\n\r\nexport const PLUGIN_NAME = 'telegram';\r\n\r\nexport interface TelegramPluginConfig {\r\n /** Telegram Bot API token (from @BotFather). */\r\n botToken: string;\r\n /**\r\n * Default chat ID for outgoing notifications.\r\n * The agent's `telegram_send` tool can override per-call.\r\n */\r\n notifyChatId?: string | number;\r\n /**\r\n * List of user/chat IDs allowed to interact with the bot.\r\n * Empty = allow all. Recommended to set in production.\r\n */\r\n allowedUsers?: Array<string | number>;\r\n /**\r\n * List of group/chat IDs the bot is allowed to read from.\r\n * Empty = allow all. Narrow this to prevent noise.\r\n */\r\n allowedChats?: Array<string | number>;\r\n /** Polling interval in seconds (default: 2). */\r\n pollIntervalSec?: number;\r\n /** Notify on Telegram when a session ends. */\r\n notifyOnSessionEnd?: boolean;\r\n /** Notify when a tool runs longer than this threshold (ms). Set 0 to disable. */\r\n longToolThresholdMs?: number;\r\n /** Maximum message length for Telegram (Telegram caps at 4096). */\r\n maxMessageLength?: number;\r\n}\r\n\r\nexport const DEFAULT_CONFIG: Required<Omit<TelegramPluginConfig, 'botToken' | 'notifyChatId'>> = {\r\n allowedUsers: [],\r\n allowedChats: [],\r\n pollIntervalSec: 2,\r\n notifyOnSessionEnd: false,\r\n longToolThresholdMs: 30_000,\r\n maxMessageLength: 4000,\r\n};\r\n\r\nexport const telegramConfigSchema = {\r\n type: 'object',\r\n properties: {\r\n botToken: { type: 'string', description: 'Telegram Bot API token from @BotFather' },\r\n notifyChatId: {\r\n oneOf: [{ type: 'string' }, { type: 'integer' }],\r\n description: 'Default chat ID for outgoing notifications',\r\n },\r\n allowedUsers: {\r\n type: 'array',\r\n items: { oneOf: [{ type: 'string' }, { type: 'integer' }] },\r\n description: 'User IDs allowed to interact with the bot',\r\n },\r\n allowedChats: {\r\n type: 'array',\r\n items: { oneOf: [{ type: 'string' }, { type: 'integer' }] },\r\n description: 'Chat IDs the bot is allowed to read from',\r\n },\r\n pollIntervalSec: {\r\n type: 'integer',\r\n minimum: 1,\r\n maximum: 60,\r\n description: 'Polling interval in seconds',\r\n },\r\n notifyOnSessionEnd: { type: 'boolean' },\r\n longToolThresholdMs: { type: 'integer', minimum: 0 },\r\n maxMessageLength: { type: 'integer', minimum: 100, maximum: 4096 },\r\n },\r\n required: ['botToken'],\r\n};\r\n\r\nexport function readTelegramConfig(\r\n api: Pick<PluginAPI, 'config'>,\r\n): Required<Omit<TelegramPluginConfig, 'notifyChatId'>> & Pick<TelegramPluginConfig, 'notifyChatId'> {\r\n const config = api.config as unknown as Record<string, unknown>;\r\n const extensions = config.extensions as Record<string, unknown> | undefined;\r\n const pluginEntries = config.plugins;\r\n const legacyPlugins = pluginEntries as Record<string, unknown> | undefined;\r\n const legacyOpts =\r\n legacyPlugins && !Array.isArray(legacyPlugins) ? legacyPlugins[PLUGIN_NAME] : undefined;\r\n const entryOpts = pluginOptionsFromEntries(pluginEntries);\r\n const opts = {\r\n ...((legacyOpts ?? entryOpts) as TelegramPluginConfig),\r\n ...((extensions?.[PLUGIN_NAME] ?? {}) as TelegramPluginConfig),\r\n };\r\n return {\r\n ...DEFAULT_CONFIG,\r\n ...opts,\r\n };\r\n}\r\n\r\nfunction pluginOptionsFromEntries(entries: unknown): TelegramPluginConfig | undefined {\r\n if (!Array.isArray(entries)) return undefined;\r\n const found = entries.find(\r\n (entry) =>\r\n typeof entry === 'object' &&\r\n entry !== null &&\r\n 'name' in entry &&\r\n ((entry as { name?: unknown }).name === '@wrongstack/telegram' ||\r\n (entry as { name?: unknown }).name === PLUGIN_NAME),\r\n ) as { name?: unknown; options?: unknown } | undefined;\r\n return found?.options && typeof found.options === 'object'\r\n ? (found.options as TelegramPluginConfig)\r\n : undefined;\r\n}\r\n","import type { PluginAPI, SlashCommand } from '@wrongstack/core';\r\nimport type { TelegramBot } from '../bot.js';\r\nimport type { TelegramPluginConfig } from '../config.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// /telegram:status\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function tgStatusCommand(bot: TelegramBot, cfg: TelegramPluginConfig): SlashCommand {\r\n return {\r\n name: 'status',\r\n aliases: ['tgstat', 'tgs'],\r\n description: 'Show Telegram bot connection status and config',\r\n help: `Usage: /telegram:status\r\n\r\nShows whether the bot is connected, its username, polling interval,\r\nallowlist status, and notification settings.`,\r\n async run(_args, _ctx) {\r\n const health = await bot.health();\r\n const lines = [\r\n '═══ Telegram Plugin Status ═══',\r\n '',\r\n `Bot: ${health.ok ? `✅ @${health.username ?? 'connected'}` : `❌ ${health.error ?? 'offline'}`}`,\r\n `Running: ${bot.running ? 'yes' : 'no'}`,\r\n `Started: ${bot.startedAt ? new Date(bot.startedAt).toLocaleTimeString() : 'N/A'}`,\r\n `Poll: every ${cfg.pollIntervalSec ?? 2}s`,\r\n `Allowed: ${(cfg.allowedUsers?.length ?? 0) > 0 ? `${cfg.allowedUsers!.length} users` : 'everyone (users)'} / ${(cfg.allowedChats?.length ?? 0) > 0 ? `${cfg.allowedChats!.length} chats` : 'everyone (chats)'}`,\r\n `Notify: sessionEnd=${cfg.notifyOnSessionEnd ?? false}, longTool=${cfg.longToolThresholdMs ? `${cfg.longToolThresholdMs}ms` : 'off'}`,\r\n ];\r\n\r\n return { message: lines.join('\\n') };\r\n },\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// /telegram:send\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function tgSendCommand(\r\n bot: TelegramBot,\r\n defaultChatId: string | number | undefined,\r\n): SlashCommand {\r\n return {\r\n name: 'send',\r\n description: 'Send a message to a Telegram chat',\r\n help: `Usage: /telegram:send [chat_id] <message>\r\n\r\nSend a message to a Telegram chat.\r\n- First argument (optional): chat or user ID. Uses notifyChatId from config when omitted.\r\n- Everything else: the message text.\r\n\r\nExamples:\r\n /telegram:send 123456789 Build completed successfully ✓\r\n /telegram:send Deploy finished — check staging`,\r\n async run(args, _ctx) {\r\n if (!args.trim()) {\r\n return { message: 'Usage: /telegram:send [chat_id] <message>' };\r\n }\r\n\r\n let chatId: string | number;\r\n let text: string;\r\n\r\n // First token might be a numeric chat_id\r\n const parts = args.trim().split(/\\s+/);\r\n const maybeId = parts[0];\r\n if (/^\\d+$/.test(maybeId!) && parts.length > 1) {\r\n chatId = maybeId!;\r\n text = parts.slice(1).join(' ');\r\n } else if (defaultChatId) {\r\n chatId = defaultChatId;\r\n text = args.trim();\r\n } else {\r\n return {\r\n message:\r\n 'No chat_id provided and no default notifyChatId configured.\\nUsage: /telegram:send <chat_id> <message>',\r\n };\r\n }\r\n\r\n try {\r\n const res = await bot.sendMessage(chatId, text);\r\n return {\r\n message: `✅ Message sent to ${chatId} (msg_id=${res.result?.message_id ?? '?'})`,\r\n };\r\n } catch (err) {\r\n return { message: `❌ Failed to send: ${(err as Error).message}` };\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// /telegram:chatid\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function tgChatIdCommand(defaultChatId?: string | number): SlashCommand {\r\n const chatIdStr = defaultChatId ? String(defaultChatId) : null;\r\n return {\r\n name: 'chatid',\r\n description: 'Show the configured default chat ID',\r\n help: `Usage: /telegram:chatid\r\n\r\nShows the current default notifyChatId used for notifications\r\nand the \\`telegram_send\\` tool when no chat_id is specified.`,\r\n async run(_args, _ctx) {\r\n if (chatIdStr) {\r\n return { message: `Configured notifyChatId: ${chatIdStr}` };\r\n }\r\n return { message: 'No notifyChatId configured. Set it in the plugin config or pass chat_id explicitly to telegram_send.' };\r\n },\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Register all\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function registerSlashCommands(\r\n api: PluginAPI,\r\n bot: TelegramBot,\r\n cfg: TelegramPluginConfig,\r\n): string[] {\r\n const cmds = [\r\n tgStatusCommand(bot, cfg),\r\n tgSendCommand(bot, cfg.notifyChatId),\r\n tgChatIdCommand(cfg.notifyChatId),\r\n ];\r\n for (const cmd of cmds) api.slashCommands.register(cmd);\r\n return cmds.map((c) => c.name);\r\n}\r\n","import type { Tool } from '@wrongstack/core';\nimport type { TelegramBot } from '../bot.js';\n\ninterface TelegramReadInput {\n /** Filter to messages from a specific chat/user ID. Omit to see all chats. */\n chat_id?: string | number;\n /** Max messages to return (default: 10, max: 50). */\n limit?: number;\n /**\n * If a message_id is provided, acknowledge all messages up to and\n * including this ID (mark them as processed / remove from buffer).\n */\n ack_last?: number;\n}\n\nexport function makeTelegramReadTool(opts: {\n bot: TelegramBot;\n}): Tool<TelegramReadInput> {\n return {\n name: 'telegram_read',\n description:\n 'Read incoming Telegram messages from the bot. Returns recent messages the bot received, newest first. Use this to check if anyone sent instructions, questions, or feedback via Telegram. After processing messages, pass the last message_id to ack_last to clear them from the inbox.',\n usageHint: 'telegram_read(chat_id: \"123456789\", limit: 5)',\n category: 'Telegram',\n inputSchema: {\n type: 'object',\n properties: {\n chat_id: {\n oneOf: [{ type: 'string' }, { type: 'integer' }],\n description: 'Read messages only from this chat/user.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n maximum: 50,\n description: 'Max messages to return (default: 10).',\n },\n ack_last: {\n type: 'integer',\n description:\n 'After processing messages, pass the highest message_id to clear them from the buffer.',\n },\n },\n },\n permission: 'auto',\n mutating: false,\n timeoutMs: 5_000,\n async execute(input) {\n const msgs = opts.bot.getMessages({\n chatId: input.chat_id,\n limit: input.limit ?? 10,\n });\n\n let acked = 0;\n if (input.ack_last !== undefined && input.ack_last > 0) {\n acked = opts.bot.acknowledge(input.ack_last);\n }\n\n return {\n buffer_total: opts.bot.bufferCount,\n messages: msgs.map((m) => ({\n message_id: m.messageId,\n chat_id: m.chatId,\n chat_type: m.chatType,\n from: m.userName ?? `user_${m.userId ?? 'unknown'}`,\n text: m.text,\n ts: new Date(m.timestamp).toISOString(),\n })),\n acked,\n hint: acked > 0\n ? undefined\n : 'Use ack_last with the highest message_id to clear processed messages.',\n };\n },\n };\n}\n","import type { Tool } from '@wrongstack/core';\nimport type { Logger } from '@wrongstack/core';\nimport type { TelegramBot } from '../bot.js';\nimport { escapeHtml, truncateForTelegram } from '../bot.js';\n\ninterface TelegramSendInput {\n /** Chat or user ID to send the message to. Falls back to config.notifyChatId when omitted. */\n chat_id?: string | number;\n /** Message text. Supports Telegram HTML parse mode. */\n message: string;\n}\n\nexport function makeTelegramSendTool(opts: {\n bot: TelegramBot;\n defaultChatId?: string | number;\n maxMessageLength: number;\n log: Logger;\n}): Tool<TelegramSendInput> {\n return {\n name: 'telegram_send',\n description:\n 'Send a message via Telegram to a specified chat. Use this to notify users, report results, or communicate through Telegram. The message supports HTML formatting (bold, italic, code, links).',\n usageHint: 'telegram_send(chat_id: \"123456789\", message: \"Task completed ✓\")',\n category: 'Telegram',\n inputSchema: {\n type: 'object',\n properties: {\n chat_id: {\n oneOf: [{ type: 'string' }, { type: 'integer' }],\n description: 'Target chat or user ID. Uses the plugin default when omitted.',\n },\n message: {\n type: 'string',\n description:\n 'Message text (supports HTML: <b>bold</b>, <i>italic</i>, <code>mono</code>, <a href=\"...\">links</a>).',\n },\n },\n required: ['message'],\n },\n permission: 'confirm',\n mutating: true,\n timeoutMs: 15_000,\n async execute(input, _ctx, _opts) {\n const chatId = input.chat_id ?? opts.defaultChatId;\n if (!chatId) {\n throw new Error(\n 'No chat_id provided and no default notifyChatId configured. Set notifyChatId in plugin config or pass chat_id.',\n );\n }\n\n // Format: wrap the message in a code block if it looks like raw output\n const safeMsg = escapeHtml(input.message);\n const truncated = truncateForTelegram(safeMsg, opts.maxMessageLength);\n\n opts.log.info(`telegram_send → chat_id=${chatId} (${truncated.length} chars)`);\n\n const res = await opts.bot.sendMessage(chatId, truncated);\n\n return {\n ok: res.ok,\n message_id: res.result?.message_id,\n chat: res.result?.chat\n ? {\n id: res.result.chat.id,\n type: res.result.chat.type,\n title: res.result.chat.title,\n }\n : undefined,\n };\n },\n };\n}\n","import type { Plugin } from '@wrongstack/core';\nimport type { Logger } from '@wrongstack/core';\nimport { TelegramBot } from './bot.js';\nimport type { TelegramIncomingMessage } from './bot.js';\nimport { truncateForTelegram, escapeHtml } from './bot.js';\nimport { PLUGIN_NAME, readTelegramConfig, telegramConfigSchema } from './config.js';\nimport { registerSlashCommands } from './slash-commands/index.js';\nimport { makeTelegramReadTool } from './tools/telegram-read.js';\nimport { makeTelegramSendTool } from './tools/telegram-send.js';\n\n// ---------------------------------------------------------------------------\n// Teardown state\n// ---------------------------------------------------------------------------\n\nlet teardownState: {\n offs: Array<() => void>;\n toolNames: string[];\n commandNames: string[];\n bot: TelegramBot;\n} | null = null;\n\n// ---------------------------------------------------------------------------\n// Plugin\n// ---------------------------------------------------------------------------\n\nconst plugin: Plugin = {\n name: PLUGIN_NAME,\n version: '0.3.4',\n description: 'Telegram bridge — send/receive messages, get agent notifications.',\n apiVersion: '^0.1.10',\n capabilities: {\n tools: true,\n slashCommands: true,\n pipelines: [],\n },\n configSchema: telegramConfigSchema,\n defaultConfig: {\n pollIntervalSec: 2,\n notifyOnSessionEnd: false,\n longToolThresholdMs: 30_000,\n maxMessageLength: 4000,\n },\n\n async setup(api) {\n const cfg = readTelegramConfig(api);\n const log = api.log;\n\n log.info('Starting Telegram plugin...');\n\n // ---- Bot ----\n const bot = new TelegramBot({\n token: cfg.botToken,\n pollIntervalSec: cfg.pollIntervalSec,\n allowedUsers: new Set((cfg.allowedUsers ?? []).map(String)),\n allowedChats: new Set((cfg.allowedChats ?? []).map(String)),\n bufferSize: 50,\n log,\n onMessage(msg: TelegramIncomingMessage) {\n // Emit custom event so other plugins or the host can react.\n // The TUI can subscribe and surface it (future hook).\n api.emitCustom('telegram:message_received', msg);\n\n // Log it for the user in the TUI\n const who = msg.userName ?? msg.userId ?? 'unknown';\n log.info(`📨 Telegram: ${who} (chat=${msg.chatId}): ${msg.text.slice(0, 200)}`);\n },\n });\n\n // ---- Register tools ----\n const sendTool = makeTelegramSendTool({\n bot,\n defaultChatId: cfg.notifyChatId,\n maxMessageLength: cfg.maxMessageLength,\n log,\n });\n const readTool = makeTelegramReadTool({ bot });\n api.tools.register(sendTool);\n api.tools.register(readTool);\n\n // ---- Event subscriptions ----\n const offs: Array<() => void> = [];\n\n // System prompt contributor — inject unread Telegram messages\n const unregisterPrompt = api.registerSystemPromptContributor(async () => {\n const msgs = bot.getMessages({ limit: 5 });\n if (msgs.length === 0) return [];\n\n const blocks: Array<{ type: 'text'; text: string }> = [\n {\n type: 'text',\n text: [\n '## Telegram Inbox',\n `You have ${bot.bufferCount} unread Telegram message(s).`,\n 'Read them with `telegram_read` and reply with `telegram_send`.',\n '',\n 'Recent messages:',\n ...msgs.map((m) => {\n const who = m.userName ?? `user_${m.userId ?? 'unknown'}`;\n const ts = new Date(m.timestamp).toLocaleTimeString();\n return `- [${ts}] **${who}** (chat=${m.chatId}): ${m.text.slice(0, 200)}`;\n }),\n '',\n ].join('\\n'),\n },\n ];\n return blocks;\n });\n offs.push(unregisterPrompt);\n\n // Register slash commands\n const commandNames = registerSlashCommands(api, bot, cfg);\n\n // Notify on session end\n if (cfg.notifyOnSessionEnd && cfg.notifyChatId) {\n offs.push(\n api.events.on('session.ended', (event) => {\n const inputTokens = event.usage.input ?? 0;\n const outputTokens = event.usage.output ?? 0;\n const totalTokens = inputTokens + outputTokens;\n const msg = [\n '✅ <b>Session ended</b>',\n '',\n `Session: <code>${event.id.slice(0, 8)}</code>`,\n `Input: ${inputTokens} tokens`,\n `Output: ${outputTokens} tokens`,\n `Total: ${totalTokens} tokens`,\n ].join('\\n');\n\n void bot.sendMessage(cfg.notifyChatId!, msg).catch((err) => {\n log.warn(`Failed to send session end notification: ${(err as Error).message}`);\n });\n }),\n );\n }\n\n // Notify for long-running tools\n if (cfg.longToolThresholdMs && cfg.longToolThresholdMs > 0 && cfg.notifyChatId) {\n offs.push(\n api.events.on('tool.executed', (event) => {\n if (event.durationMs < cfg.longToolThresholdMs!) return;\n const sec = (event.durationMs / 1000).toFixed(1);\n const status = event.ok ? '✅' : '❌';\n const preview = event.output\n ? truncateForTelegram(escapeHtml(event.output), 500)\n : '(no output)';\n\n const msg = [\n `${status} <b>${escapeHtml(event.name)}</b> completed in ${sec}s`,\n '',\n `<pre>${preview}</pre>`,\n ].join('\\n');\n\n void bot.sendMessage(cfg.notifyChatId!, msg).catch((err) => {\n log.warn(`Failed to send tool notification: ${(err as Error).message}`);\n });\n }),\n );\n }\n\n // ---- Start polling ----\n bot.start();\n\n teardownState = { offs, toolNames: [sendTool.name, readTool.name], commandNames, bot };\n\n log.info('Telegram plugin ready');\n },\n\n async teardown(api) {\n const state = teardownState;\n if (!state) return;\n teardownState = null;\n\n state.bot.stop();\n for (const off of state.offs) off();\n for (const name of state.toolNames) api.tools.unregister(name);\n for (const name of state.commandNames) {\n api.slashCommands.unregister(`${PLUGIN_NAME}:${name}`);\n }\n\n api.log.info('Telegram plugin torn down');\n },\n\n async health() {\n const state = teardownState;\n if (!state?.bot) return { ok: false, message: 'Plugin not initialized' };\n const h = await state.bot.health();\n return h;\n },\n};\n\nexport default plugin;\n\n// Re-export the types consumers may want\nexport type { TelegramIncomingMessage } from './bot.js';\nexport type { TelegramPluginConfig } from './config.js';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/telegram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack plugin — Telegram bridge: send messages, receive prompts, get notified.",
|
|
6
6
|
"repository": {
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"dist"
|
|
26
26
|
],
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@wrongstack/core": "0.3.
|
|
28
|
+
"@wrongstack/core": "0.3.4"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^22.19.19",
|
|
32
32
|
"tsup": "^8.5.1",
|
|
33
33
|
"typescript": "^5.9.3",
|
|
34
|
-
"@wrongstack/core": "0.3.
|
|
34
|
+
"@wrongstack/core": "0.3.4"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|