@wrongstack/telegram 0.77.0 → 0.82.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +11 -11
- package/dist/index.js +23 -10
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ interface TelegramIncomingMessage {
|
|
|
4
4
|
messageId: number;
|
|
5
5
|
chatId: number;
|
|
6
6
|
chatType: string;
|
|
7
|
-
userId?: number;
|
|
8
|
-
userName?: string;
|
|
7
|
+
userId?: number | undefined;
|
|
8
|
+
userName?: string | undefined;
|
|
9
9
|
text: string;
|
|
10
10
|
timestamp: number;
|
|
11
11
|
}
|
|
@@ -17,34 +17,34 @@ interface TelegramPluginConfig {
|
|
|
17
17
|
* Default chat ID for outgoing notifications.
|
|
18
18
|
* The agent's `telegram_send` tool can override per-call.
|
|
19
19
|
*/
|
|
20
|
-
notifyChatId?: string | number;
|
|
20
|
+
notifyChatId?: string | number | undefined;
|
|
21
21
|
/**
|
|
22
22
|
* List of user/chat IDs allowed to interact with the bot.
|
|
23
23
|
* Empty = allow all. Recommended to set in production.
|
|
24
24
|
*/
|
|
25
|
-
allowedUsers?: Array<string | number
|
|
25
|
+
allowedUsers?: Array<string | number> | undefined;
|
|
26
26
|
/**
|
|
27
27
|
* List of group/chat IDs the bot is allowed to read from.
|
|
28
28
|
* Empty = allow all. Narrow this to prevent noise.
|
|
29
29
|
*/
|
|
30
|
-
allowedChats?: Array<string | number
|
|
30
|
+
allowedChats?: Array<string | number> | undefined;
|
|
31
31
|
/** Polling interval in seconds (default: 2). */
|
|
32
|
-
pollIntervalSec?: number;
|
|
32
|
+
pollIntervalSec?: number | undefined;
|
|
33
33
|
/** Notify on Telegram when a session ends. */
|
|
34
|
-
notifyOnSessionEnd?: boolean;
|
|
34
|
+
notifyOnSessionEnd?: boolean | undefined;
|
|
35
35
|
/** Notify when a tool runs longer than this threshold (ms). Set 0 to disable. */
|
|
36
|
-
longToolThresholdMs?: number;
|
|
36
|
+
longToolThresholdMs?: number | undefined;
|
|
37
37
|
/** Notify (humanized) when a `delegate` subagent finishes. Default: true. */
|
|
38
|
-
notifyOnDelegate?: boolean;
|
|
38
|
+
notifyOnDelegate?: boolean | undefined;
|
|
39
39
|
/** Maximum message length for Telegram (Telegram caps at 4096). */
|
|
40
|
-
maxMessageLength?: number;
|
|
40
|
+
maxMessageLength?: number | undefined;
|
|
41
41
|
/**
|
|
42
42
|
* Path to a file that stores the Telegram polling offset. When set,
|
|
43
43
|
* the offset is persisted on every successful poll and restored on startup,
|
|
44
44
|
* preventing message replay after crashes or restarts.
|
|
45
45
|
* The directory must already exist and be writable.
|
|
46
46
|
*/
|
|
47
|
-
offsetStoragePath?: string;
|
|
47
|
+
offsetStoragePath?: string | undefined;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
declare const plugin: Plugin;
|
package/dist/index.js
CHANGED
|
@@ -74,7 +74,8 @@ var TelegramBot = class {
|
|
|
74
74
|
const before = this.buffer.length;
|
|
75
75
|
let i = this.buffer.length;
|
|
76
76
|
while (i-- > 0) {
|
|
77
|
-
|
|
77
|
+
const buffered = this.buffer[i];
|
|
78
|
+
if (buffered && buffered.messageId <= lastMessageId) {
|
|
78
79
|
this.buffer.splice(0, i + 1);
|
|
79
80
|
break;
|
|
80
81
|
}
|
|
@@ -318,6 +319,12 @@ function formatDelegateCompleted(e) {
|
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
// src/slash-commands/index.ts
|
|
322
|
+
function expectDefined(value) {
|
|
323
|
+
if (value === null || value === void 0) {
|
|
324
|
+
throw new Error("Expected value to be defined");
|
|
325
|
+
}
|
|
326
|
+
return value;
|
|
327
|
+
}
|
|
321
328
|
function tgStatusCommand(bot, cfg) {
|
|
322
329
|
return {
|
|
323
330
|
name: "status",
|
|
@@ -336,7 +343,7 @@ allowlist status, and notification settings.`,
|
|
|
336
343
|
`Running: ${bot.running ? "yes" : "no"}`,
|
|
337
344
|
`Started: ${bot.startedAt ? new Date(bot.startedAt).toLocaleTimeString() : "N/A"}`,
|
|
338
345
|
`Poll: every ${cfg.pollIntervalSec ?? 2}s`,
|
|
339
|
-
`Allowed: ${(cfg.allowedUsers?.length ?? 0) > 0 ? `${cfg.allowedUsers
|
|
346
|
+
`Allowed: ${(cfg.allowedUsers?.length ?? 0) > 0 ? `${cfg.allowedUsers?.length} users` : "everyone (users)"} / ${(cfg.allowedChats?.length ?? 0) > 0 ? `${cfg.allowedChats?.length} chats` : "everyone (chats)"}`,
|
|
340
347
|
`Notify: sessionEnd=${cfg.notifyOnSessionEnd ?? false}, longTool=${cfg.longToolThresholdMs ? `${cfg.longToolThresholdMs}ms` : "off"}`
|
|
341
348
|
];
|
|
342
349
|
return { message: lines.join("\n") };
|
|
@@ -364,8 +371,8 @@ Examples:
|
|
|
364
371
|
let text;
|
|
365
372
|
const parts = args.trim().split(/\s+/);
|
|
366
373
|
const maybeId = parts[0];
|
|
367
|
-
if (/^\d+$/.test(maybeId) && parts.length > 1) {
|
|
368
|
-
chatId = maybeId;
|
|
374
|
+
if (/^\d+$/.test(expectDefined(maybeId)) && parts.length > 1) {
|
|
375
|
+
chatId = expectDefined(maybeId);
|
|
369
376
|
text = parts.slice(1).join(" ");
|
|
370
377
|
} else if (defaultChatId) {
|
|
371
378
|
chatId = defaultChatId;
|
|
@@ -516,6 +523,12 @@ function makeTelegramSendTool(opts) {
|
|
|
516
523
|
}
|
|
517
524
|
|
|
518
525
|
// src/index.ts
|
|
526
|
+
function expectDefined2(value) {
|
|
527
|
+
if (value === null || value === void 0) {
|
|
528
|
+
throw new Error("Expected value to be defined");
|
|
529
|
+
}
|
|
530
|
+
return value;
|
|
531
|
+
}
|
|
519
532
|
var teardownState = null;
|
|
520
533
|
var plugin = {
|
|
521
534
|
name: PLUGIN_NAME,
|
|
@@ -540,7 +553,7 @@ var plugin = {
|
|
|
540
553
|
log.info("Starting Telegram plugin...");
|
|
541
554
|
const bot = new TelegramBot({
|
|
542
555
|
token: cfg.botToken,
|
|
543
|
-
pollIntervalSec: cfg.pollIntervalSec,
|
|
556
|
+
pollIntervalSec: cfg.pollIntervalSec ?? 2,
|
|
544
557
|
allowedUsers: new Set((cfg.allowedUsers ?? []).map(String)),
|
|
545
558
|
allowedChats: new Set((cfg.allowedChats ?? []).map(String)),
|
|
546
559
|
bufferSize: 50,
|
|
@@ -555,7 +568,7 @@ var plugin = {
|
|
|
555
568
|
const sendTool = makeTelegramSendTool({
|
|
556
569
|
bot,
|
|
557
570
|
defaultChatId: cfg.notifyChatId,
|
|
558
|
-
maxMessageLength: cfg.maxMessageLength,
|
|
571
|
+
maxMessageLength: cfg.maxMessageLength ?? 4e3,
|
|
559
572
|
log
|
|
560
573
|
});
|
|
561
574
|
const readTool = makeTelegramReadTool({ bot });
|
|
@@ -601,7 +614,7 @@ var plugin = {
|
|
|
601
614
|
`Output: ${outputTokens} tokens`,
|
|
602
615
|
`Total: ${totalTokens} tokens`
|
|
603
616
|
].join("\n");
|
|
604
|
-
void bot.sendMessage(cfg.notifyChatId, msg).catch((err) => {
|
|
617
|
+
void bot.sendMessage(expectDefined2(cfg.notifyChatId), msg).catch((err) => {
|
|
605
618
|
log.warn(`Failed to send session end notification: ${err.message}`);
|
|
606
619
|
});
|
|
607
620
|
})
|
|
@@ -610,7 +623,7 @@ var plugin = {
|
|
|
610
623
|
if (cfg.longToolThresholdMs && cfg.longToolThresholdMs > 0 && cfg.notifyChatId) {
|
|
611
624
|
offs.push(
|
|
612
625
|
api.events.on("tool.executed", (event) => {
|
|
613
|
-
if (event.durationMs < cfg.longToolThresholdMs) return;
|
|
626
|
+
if (event.durationMs < expectDefined2(cfg.longToolThresholdMs)) return;
|
|
614
627
|
const sec = (event.durationMs / 1e3).toFixed(1);
|
|
615
628
|
const status = event.ok ? "\u2705" : "\u274C";
|
|
616
629
|
const preview = event.output ? truncateForTelegram(event.output, 500) : "(no output)";
|
|
@@ -619,7 +632,7 @@ var plugin = {
|
|
|
619
632
|
"",
|
|
620
633
|
preview
|
|
621
634
|
].join("\n");
|
|
622
|
-
void bot.sendMessage(cfg.notifyChatId, msg).catch((err) => {
|
|
635
|
+
void bot.sendMessage(expectDefined2(cfg.notifyChatId), msg).catch((err) => {
|
|
623
636
|
log.warn(`Failed to send tool notification: ${err.message}`);
|
|
624
637
|
});
|
|
625
638
|
})
|
|
@@ -632,7 +645,7 @@ var plugin = {
|
|
|
632
645
|
formatDelegateCompleted(event),
|
|
633
646
|
cfg.maxMessageLength
|
|
634
647
|
);
|
|
635
|
-
void bot.sendMessage(cfg.notifyChatId, msg).catch((err) => {
|
|
648
|
+
void bot.sendMessage(expectDefined2(cfg.notifyChatId), msg).catch((err) => {
|
|
636
649
|
log.warn(`Failed to send delegate notification: ${err.message}`);
|
|
637
650
|
});
|
|
638
651
|
})
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bot.ts","../src/config.ts","../src/format.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// Redaction helpers (for future use)\n// ---------------------------------------------------------------------------\n// If logging URLs that contain the bot token in the future, use:\n// function redactToken(url: string, token: string): string {\n// return url.replace(token, '[REDACTED]');\n// }\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 * Optional path to a file that stores the polling offset. When provided,\n * the offset is persisted on every successful poll and restored on startup,\n * preventing message replay after crashes or restarts.\n */\n offsetStoragePath?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Bot\n// ---------------------------------------------------------------------------\n\nexport class TelegramBot {\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 /** If set, the offset is persisted here after each successful poll. */\n private readonly offsetStoragePath?: string;\n\n // Circular buffer for incoming messages\n private readonly bufferMax: number;\n private readonly buffer: TelegramIncomingMessage[] = [];\n\n constructor(opts: TelegramBotOptions) {\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 this.offsetStoragePath = opts.offsetStoragePath;\n\n // Restore persisted offset so a crash/restart doesn't cause message replay.\n if (this.offsetStoragePath) {\n void this.loadOffset();\n }\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 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\n // Persist offset after each successful poll to prevent message replay\n // after crashes or restarts.\n if (this.offsetStoragePath && this.offset > 0) {\n void this.saveOffset();\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 private async loadOffset(): Promise<void> {\n if (!this.offsetStoragePath) return;\n try {\n const { readFileSync } = await import('node:fs');\n const raw = readFileSync(this.offsetStoragePath, 'utf8').trim();\n const n = Number.parseInt(raw, 10);\n if (Number.isFinite(n) && n >= 0) {\n this.offset = n;\n this.log.debug(`Telegram polling offset restored: ${this.offset}`);\n }\n } catch {\n // File doesn't exist yet — start from 0, which is correct.\n }\n }\n\n private async saveOffset(): Promise<void> {\n if (!this.offsetStoragePath) return;\n try {\n const { writeFileSync } = await import('node:fs');\n // Write atomically so a crash mid-write can't leave a corrupt file.\n writeFileSync(this.offsetStoragePath, String(this.offset), 'utf8');\n } catch (err) {\n this.log.warn(`Failed to persist Telegram offset: ${err}`);\n }\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 /** Notify (humanized) when a `delegate` subagent finishes. Default: true. */\r\n notifyOnDelegate?: boolean;\r\n /** Maximum message length for Telegram (Telegram caps at 4096). */\r\n maxMessageLength?: number;\r\n /**\r\n * Path to a file that stores the Telegram polling offset. When set,\r\n * the offset is persisted on every successful poll and restored on startup,\r\n * preventing message replay after crashes or restarts.\r\n * The directory must already exist and be writable.\r\n */\r\n offsetStoragePath?: string;\r\n}\r\n\r\nexport const DEFAULT_CONFIG: Required<Omit<TelegramPluginConfig, 'botToken' | 'notifyChatId' | 'offsetStoragePath'>> = {\r\n allowedUsers: [],\r\n allowedChats: [],\r\n pollIntervalSec: 2,\r\n notifyOnSessionEnd: false,\r\n longToolThresholdMs: 30_000,\r\n notifyOnDelegate: true,\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 notifyOnDelegate: { type: 'boolean' },\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' | 'offsetStoragePath'>> &\r\n Pick<TelegramPluginConfig, 'notifyChatId' | 'offsetStoragePath'> {\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","// ---------------------------------------------------------------------------\n// Humanizers for agent events forwarded to Telegram.\n//\n// The host emits rich structured events; this module turns them into short,\n// readable chat messages. Kept pure (no bot / IO) so it's trivially testable.\n// ---------------------------------------------------------------------------\n\n/** Subset of the core `delegate.completed` event payload we render. */\nexport interface DelegateCompletedLike {\n target: string;\n task: string;\n ok: boolean;\n status?: string;\n summary: string;\n durationMs: number;\n iterations: number;\n toolCalls: number;\n costUsd?: number;\n subagentId?: string;\n}\n\n/** Compact human duration: `42s`, `3m`, `1.5h`. */\nexport function fmtDuration(ms: number): string {\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;\n return `${(ms / 3_600_000).toFixed(1)}h`;\n}\n\n/**\n * Render a finished delegation as a readable Telegram message instead of the\n * raw, truncated JSON the generic `tool.executed` notifier would produce.\n *\n * Example:\n * ✅ Delegate → bug-hunter · success\n * Found 3 null-deref risks in auth.ts and patched the worst one…\n * ⏱ 3m · 4 iter · 37 tools · 💲0.0820\n */\nexport function formatDelegateCompleted(e: DelegateCompletedLike): string {\n const icon = e.ok ? '✅' : '❌';\n const status = e.status ?? (e.ok ? 'success' : 'failed');\n const task = e.task.length > 160 ? `${e.task.slice(0, 159)}…` : e.task;\n\n // Prefer the host's one-line summary; fall back to echoing the task when a\n // failure produced no summary.\n const body = e.summary?.trim() || `(no summary) — ${task}`;\n\n const stats = [\n `⏱ ${fmtDuration(e.durationMs)}`,\n `${e.iterations} iter`,\n `${e.toolCalls} tools`,\n ];\n if (typeof e.costUsd === 'number' && e.costUsd > 0) {\n stats.push(`💲${e.costUsd.toFixed(4)}`);\n }\n\n return [`${icon} Delegate → ${e.target} · ${status}`, body, stats.join(' · ')].join('\\n');\n}\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 { 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. */\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.',\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.',\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 // Truncate message to fit Telegram's 4096 char limit\n const truncated = truncateForTelegram(input.message, 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 { TelegramBot } from './bot.js';\nimport type { TelegramIncomingMessage } from './bot.js';\nimport { truncateForTelegram } from './bot.js';\nimport { PLUGIN_NAME, readTelegramConfig, telegramConfigSchema } from './config.js';\nimport { formatDelegateCompleted } from './format.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 offsetStoragePath: cfg.offsetStoragePath,\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 `✅ Session ended`,\n '',\n `Session: ${event.id.slice(0, 8)}`,\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(event.output, 500)\n : '(no output)';\n\n const msg = [\n `${status} ${event.name} completed in ${sec}s`,\n '',\n preview,\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 // Notify (humanized) when a delegated subagent finishes. The generic\n // `tool.executed` notifier would dump the delegate's truncated JSON\n // result; `delegate.completed` carries readable fields instead.\n if (cfg.notifyOnDelegate && cfg.notifyChatId) {\n offs.push(\n api.events.on('delegate.completed', (event) => {\n const msg = truncateForTelegram(\n formatDelegateCompleted(event),\n cfg.maxMessageLength,\n );\n void bot.sendMessage(cfg.notifyChatId!, msg).catch((err) => {\n log.warn(`Failed to send delegate 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/format.ts","../src/slash-commands/index.ts","../src/tools/telegram-read.ts","../src/tools/telegram-send.ts","../src/index.ts"],"names":["expectDefined"],"mappings":"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","file":"index.js","sourcesContent":["import type { Logger } from '@wrongstack/core';\n\n// ---------------------------------------------------------------------------\n// Redaction helpers (for future use)\n// ---------------------------------------------------------------------------\n// If logging URLs that contain the bot token in the future, use:\n// function redactToken(url: string, token: string): string {\n// return url.replace(token, '[REDACTED]');\n// }\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 | undefined;\n}\n\ninterface TgChat {\n id: number;\n type: 'private' | 'group' | 'supergroup' | 'channel';\n title?: string | undefined;\n username?: string | undefined;\n}\n\ninterface TgMessage {\n message_id: number;\n from?: TgUser | undefined;\n chat: TgChat;\n date: number;\n text?: string | undefined;\n}\n\ninterface TgUpdate {\n update_id: number;\n message?: TgMessage | undefined;\n edited_message?: TgMessage | undefined;\n}\n\ninterface TgResponse<T> {\n ok: boolean;\n result?: T | undefined;\n description?: string | undefined;\n error_code?: number | undefined;\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 | undefined;\n userName?: string | undefined;\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 * Optional path to a file that stores the polling offset. When provided,\n * the offset is persisted on every successful poll and restored on startup,\n * preventing message replay after crashes or restarts.\n */\n offsetStoragePath?: string | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Bot\n// ---------------------------------------------------------------------------\n\nexport class TelegramBot {\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 /** If set, the offset is persisted here after each successful poll. */\n private readonly offsetStoragePath?: string | undefined;\n\n // Circular buffer for incoming messages\n private readonly bufferMax: number;\n private readonly buffer: TelegramIncomingMessage[] = [];\n\n constructor(opts: TelegramBotOptions) {\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 this.offsetStoragePath = opts.offsetStoragePath;\n\n // Restore persisted offset so a crash/restart doesn't cause message replay.\n if (this.offsetStoragePath) {\n void this.loadOffset();\n }\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 | undefined; limit?: number | undefined }): 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 const buffered = this.buffer[i];\n if (buffered && buffered.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 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 | undefined; error?: string | undefined }> {\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\n // Persist offset after each successful poll to prevent message replay\n // after crashes or restarts.\n if (this.offsetStoragePath && this.offset > 0) {\n void this.saveOffset();\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 private async loadOffset(): Promise<void> {\n if (!this.offsetStoragePath) return;\n try {\n const { readFileSync } = await import('node:fs');\n const raw = readFileSync(this.offsetStoragePath, 'utf8').trim();\n const n = Number.parseInt(raw, 10);\n if (Number.isFinite(n) && n >= 0) {\n this.offset = n;\n this.log.debug(`Telegram polling offset restored: ${this.offset}`);\n }\n } catch {\n // File doesn't exist yet — start from 0, which is correct.\n }\n }\n\n private async saveOffset(): Promise<void> {\n if (!this.offsetStoragePath) return;\n try {\n const { writeFileSync } = await import('node:fs');\n // Write atomically so a crash mid-write can't leave a corrupt file.\n writeFileSync(this.offsetStoragePath, String(this.offset), 'utf8');\n } catch (err) {\n this.log.warn(`Failed to persist Telegram offset: ${err}`);\n }\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 | undefined;\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> | undefined;\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> | undefined;\r\n /** Polling interval in seconds (default: 2). */\r\n pollIntervalSec?: number | undefined;\r\n /** Notify on Telegram when a session ends. */\r\n notifyOnSessionEnd?: boolean | undefined;\r\n /** Notify when a tool runs longer than this threshold (ms). Set 0 to disable. */\r\n longToolThresholdMs?: number | undefined;\r\n /** Notify (humanized) when a `delegate` subagent finishes. Default: true. */\r\n notifyOnDelegate?: boolean | undefined;\r\n /** Maximum message length for Telegram (Telegram caps at 4096). */\r\n maxMessageLength?: number | undefined;\r\n /**\r\n * Path to a file that stores the Telegram polling offset. When set,\r\n * the offset is persisted on every successful poll and restored on startup,\r\n * preventing message replay after crashes or restarts.\r\n * The directory must already exist and be writable.\r\n */\r\n offsetStoragePath?: string | undefined;\r\n}\r\n\r\nexport const DEFAULT_CONFIG: Required<Omit<TelegramPluginConfig, 'botToken' | 'notifyChatId' | 'offsetStoragePath'>> = {\r\n allowedUsers: [],\r\n allowedChats: [],\r\n pollIntervalSec: 2,\r\n notifyOnSessionEnd: false,\r\n longToolThresholdMs: 30_000,\r\n notifyOnDelegate: true,\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 notifyOnDelegate: { type: 'boolean' },\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' | 'offsetStoragePath'>> &\r\n Pick<TelegramPluginConfig, 'notifyChatId' | 'offsetStoragePath'> {\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 | undefined }).name === '@wrongstack/telegram' ||\r\n (entry as { name?: unknown | undefined }).name === PLUGIN_NAME),\r\n ) as { name?: unknown | undefined; options?: unknown | undefined } | undefined;\r\n return found?.options && typeof found.options === 'object'\r\n ? (found.options as TelegramPluginConfig)\r\n : undefined;\r\n}\r\n","// ---------------------------------------------------------------------------\n// Humanizers for agent events forwarded to Telegram.\n//\n// The host emits rich structured events; this module turns them into short,\n// readable chat messages. Kept pure (no bot / IO) so it's trivially testable.\n// ---------------------------------------------------------------------------\n\n/** Subset of the core `delegate.completed` event payload we render. */\nexport interface DelegateCompletedLike {\n target: string;\n task: string;\n ok: boolean;\n status?: string | undefined;\n summary: string;\n durationMs: number;\n iterations: number;\n toolCalls: number;\n costUsd?: number | undefined;\n subagentId?: string | undefined;\n}\n\n/** Compact human duration: `42s`, `3m`, `1.5h`. */\nexport function fmtDuration(ms: number): string {\n if (ms < 60_000) return `${Math.round(ms / 1000)}s`;\n if (ms < 3_600_000) return `${Math.round(ms / 60_000)}m`;\n return `${(ms / 3_600_000).toFixed(1)}h`;\n}\n\n/**\n * Render a finished delegation as a readable Telegram message instead of the\n * raw, truncated JSON the generic `tool.executed` notifier would produce.\n *\n * Example:\n * ✅ Delegate → bug-hunter · success\n * Found 3 null-deref risks in auth.ts and patched the worst one…\n * ⏱ 3m · 4 iter · 37 tools · 💲0.0820\n */\nexport function formatDelegateCompleted(e: DelegateCompletedLike): string {\n const icon = e.ok ? '✅' : '❌';\n const status = e.status ?? (e.ok ? 'success' : 'failed');\n const task = e.task.length > 160 ? `${e.task.slice(0, 159)}…` : e.task;\n\n // Prefer the host's one-line summary; fall back to echoing the task when a\n // failure produced no summary.\n const body = e.summary?.trim() || `(no summary) — ${task}`;\n\n const stats = [\n `⏱ ${fmtDuration(e.durationMs)}`,\n `${e.iterations} iter`,\n `${e.toolCalls} tools`,\n ];\n if (typeof e.costUsd === 'number' && e.costUsd > 0) {\n stats.push(`💲${e.costUsd.toFixed(4)}`);\n }\n\n return [`${icon} Delegate → ${e.target} · ${status}`, body, stats.join(' · ')].join('\\n');\n}\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\n\nfunction expectDefined<T>(value: T | null | undefined): T {\n if (value === null || value === undefined) {\n throw new Error('Expected value to be defined');\n }\n return value;\n}\n\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(expectDefined(maybeId)) && parts.length > 1) {\r\n chatId = expectDefined(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 | undefined;\n /** Max messages to return (default: 10, max: 50). */\n limit?: number | undefined;\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 | undefined;\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 { 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 | undefined;\n /** Message text. */\n message: string;\n}\n\nexport function makeTelegramSendTool(opts: {\n bot: TelegramBot;\n defaultChatId?: string | number | undefined;\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.',\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.',\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 // Truncate message to fit Telegram's 4096 char limit\n const truncated = truncateForTelegram(input.message, 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 { TelegramBot } from './bot.js';\nimport type { TelegramIncomingMessage } from './bot.js';\nimport { truncateForTelegram } from './bot.js';\nimport { PLUGIN_NAME, readTelegramConfig, telegramConfigSchema } from './config.js';\nimport { formatDelegateCompleted } from './format.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\nfunction expectDefined<T>(value: T | null | undefined): T {\n if (value === null || value === undefined) {\n throw new Error('Expected value to be defined');\n }\n return value;\n}\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 ?? 2,\n allowedUsers: new Set((cfg.allowedUsers ?? []).map(String)),\n allowedChats: new Set((cfg.allowedChats ?? []).map(String)),\n bufferSize: 50,\n log,\n offsetStoragePath: cfg.offsetStoragePath,\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 ?? 4000,\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 `✅ Session ended`,\n '',\n `Session: ${event.id.slice(0, 8)}`,\n `Input: ${inputTokens} tokens`,\n `Output: ${outputTokens} tokens`,\n `Total: ${totalTokens} tokens`,\n ].join('\\n');\n\n void bot.sendMessage(expectDefined(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 < expectDefined(cfg.longToolThresholdMs)) return;\n const sec = (event.durationMs / 1000).toFixed(1);\n const status = event.ok ? '✅' : '❌';\n const preview = event.output\n ? truncateForTelegram(event.output, 500)\n : '(no output)';\n\n const msg = [\n `${status} ${event.name} completed in ${sec}s`,\n '',\n preview,\n ].join('\\n');\n\n void bot.sendMessage(expectDefined(cfg.notifyChatId), msg).catch((err) => {\n log.warn(`Failed to send tool notification: ${(err as Error).message}`);\n });\n }),\n );\n }\n\n // Notify (humanized) when a delegated subagent finishes. The generic\n // `tool.executed` notifier would dump the delegate's truncated JSON\n // result; `delegate.completed` carries readable fields instead.\n if (cfg.notifyOnDelegate && cfg.notifyChatId) {\n offs.push(\n api.events.on('delegate.completed', (event) => {\n const msg = truncateForTelegram(\n formatDelegateCompleted(event),\n cfg.maxMessageLength,\n );\n void bot.sendMessage(expectDefined(cfg.notifyChatId), msg).catch((err) => {\n log.warn(`Failed to send delegate 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.82.6",
|
|
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.
|
|
28
|
+
"@wrongstack/core": "0.82.6"
|
|
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.
|
|
34
|
+
"@wrongstack/core": "0.82.6"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|