@rozek/nanoclaw 0.0.22 → 0.0.25
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/container/Dockerfile +1 -1
- package/container/agent-runner/src/index.ts +72 -0
- package/container/agent-runner/src/ipc-mcp-stdio.ts +4 -0
- package/dist/channels/telegram.d.ts +20 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +226 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/telegram.test.d.ts +2 -0
- package/dist/channels/telegram.test.d.ts.map +1 -0
- package/dist/channels/telegram.test.js +624 -0
- package/dist/channels/telegram.test.js.map +1 -0
- package/dist/channels/web.js +89 -49
- package/dist/channels/web.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -5
- package/dist/config.js.map +1 -1
- package/dist/container-runner.d.ts +2 -0
- package/dist/container-runner.d.ts.map +1 -1
- package/dist/container-runner.js +16 -20
- package/dist/container-runner.js.map +1 -1
- package/dist/container-runner.test.js +4 -10
- package/dist/container-runner.test.js.map +1 -1
- package/dist/container-runtime.d.ts +9 -0
- package/dist/container-runtime.d.ts.map +1 -1
- package/dist/container-runtime.js +27 -0
- package/dist/container-runtime.js.map +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +14 -3
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -21
- package/dist/index.js.map +1 -1
- package/dist/ipc.d.ts +1 -0
- package/dist/ipc.d.ts.map +1 -1
- package/dist/ipc.js +3 -0
- package/dist/ipc.js.map +1 -1
- package/dist/task-scheduler.d.ts.map +1 -1
- package/dist/task-scheduler.js +2 -0
- package/dist/task-scheduler.js.map +1 -1
- package/dist/timezone.d.ts +10 -0
- package/dist/timezone.d.ts.map +1 -1
- package/dist/timezone.js +21 -1
- package/dist/timezone.js.map +1 -1
- package/dist/timezone.test.js +33 -1
- package/dist/timezone.test.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/setup/index.ts +1 -0
- package/setup/register.test.ts +209 -2
- package/setup/register.ts +29 -4
- package/setup/timezone.ts +67 -0
package/container/Dockerfile
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import fs from 'fs';
|
|
18
18
|
import path from 'path';
|
|
19
|
+
import { execFile } from 'child_process';
|
|
19
20
|
import { query, HookCallback, PreCompactHookInput } from '@anthropic-ai/claude-agent-sdk';
|
|
20
21
|
import { fileURLToPath } from 'url';
|
|
21
22
|
|
|
@@ -27,6 +28,7 @@ interface ContainerInput {
|
|
|
27
28
|
isMain: boolean;
|
|
28
29
|
isScheduledTask?: boolean;
|
|
29
30
|
assistantName?: string;
|
|
31
|
+
script?: string;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
interface ContainerOutput {
|
|
@@ -578,6 +580,55 @@ async function runQuery(
|
|
|
578
580
|
return { newSessionId, lastAssistantUuid, closedDuringQuery };
|
|
579
581
|
}
|
|
580
582
|
|
|
583
|
+
interface ScriptResult {
|
|
584
|
+
wakeAgent: boolean;
|
|
585
|
+
data?: unknown;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const SCRIPT_TIMEOUT_MS = 30_000;
|
|
589
|
+
|
|
590
|
+
async function runScript(script: string): Promise<ScriptResult | null> {
|
|
591
|
+
const scriptPath = '/tmp/task-script.sh';
|
|
592
|
+
fs.writeFileSync(scriptPath, script, { mode: 0o755 });
|
|
593
|
+
|
|
594
|
+
return new Promise((resolve) => {
|
|
595
|
+
execFile('bash', [scriptPath], {
|
|
596
|
+
timeout: SCRIPT_TIMEOUT_MS,
|
|
597
|
+
maxBuffer: 1024 * 1024,
|
|
598
|
+
env: process.env,
|
|
599
|
+
}, (error, stdout, stderr) => {
|
|
600
|
+
if (stderr) {
|
|
601
|
+
log(`Script stderr: ${stderr.slice(0, 500)}`);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (error) {
|
|
605
|
+
log(`Script error: ${error.message}`);
|
|
606
|
+
return resolve(null);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Parse last non-empty line of stdout as JSON
|
|
610
|
+
const lines = stdout.trim().split('\n');
|
|
611
|
+
const lastLine = lines[lines.length - 1];
|
|
612
|
+
if (!lastLine) {
|
|
613
|
+
log('Script produced no output');
|
|
614
|
+
return resolve(null);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
try {
|
|
618
|
+
const result = JSON.parse(lastLine);
|
|
619
|
+
if (typeof result.wakeAgent !== 'boolean') {
|
|
620
|
+
log(`Script output missing wakeAgent boolean: ${lastLine.slice(0, 200)}`);
|
|
621
|
+
return resolve(null);
|
|
622
|
+
}
|
|
623
|
+
resolve(result as ScriptResult);
|
|
624
|
+
} catch {
|
|
625
|
+
log(`Script output is not valid JSON: ${lastLine.slice(0, 200)}`);
|
|
626
|
+
resolve(null);
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
581
632
|
async function main(): Promise<void> {
|
|
582
633
|
let containerInput: ContainerInput;
|
|
583
634
|
|
|
@@ -718,6 +769,27 @@ async function main(): Promise<void> {
|
|
|
718
769
|
return;
|
|
719
770
|
}
|
|
720
771
|
// --- End slash command handling ---
|
|
772
|
+
|
|
773
|
+
// Script phase: run script before waking agent
|
|
774
|
+
if (containerInput.script && containerInput.isScheduledTask) {
|
|
775
|
+
log('Running task script...');
|
|
776
|
+
const scriptResult = await runScript(containerInput.script);
|
|
777
|
+
|
|
778
|
+
if (!scriptResult || !scriptResult.wakeAgent) {
|
|
779
|
+
const reason = scriptResult ? 'wakeAgent=false' : 'script error/no output';
|
|
780
|
+
log(`Script decided not to wake agent: ${reason}`);
|
|
781
|
+
writeOutput({
|
|
782
|
+
status: 'success',
|
|
783
|
+
result: null,
|
|
784
|
+
});
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Script says wake agent — enrich prompt with script data
|
|
789
|
+
log(`Script wakeAgent=true, enriching prompt with data`);
|
|
790
|
+
prompt = `[SCHEDULED TASK]\n\nScript output:\n${JSON.stringify(scriptResult.data, null, 2)}\n\nInstructions:\n${containerInput.prompt}`;
|
|
791
|
+
}
|
|
792
|
+
|
|
721
793
|
|
|
722
794
|
// Query loop: run query → wait for IPC message → run new query → repeat
|
|
723
795
|
let resumeAt: string | undefined;
|
|
@@ -91,6 +91,7 @@ SCHEDULE VALUE FORMAT (all times are LOCAL timezone):
|
|
|
91
91
|
schedule_value: z.string().describe('cron: "*/5 * * * *" | interval: milliseconds like "300000" | once: local timestamp like "2026-02-01T15:30:00" (no Z suffix!)'),
|
|
92
92
|
context_mode: z.enum(['group', 'isolated']).default('group').describe('group=runs with chat history and memory, isolated=fresh session (include context in prompt)'),
|
|
93
93
|
target_group_jid: z.string().optional().describe('(Main group only) JID of the group to schedule the task for. Defaults to the current group.'),
|
|
94
|
+
script: z.string().optional().describe('Optional bash script to run before waking the agent. Script must output JSON on the last line of stdout: { "wakeAgent": boolean, "data"?: any }. If wakeAgent is false, the agent is not called. Test your script with bash -c "..." before scheduling.'),
|
|
94
95
|
},
|
|
95
96
|
async (args) => {
|
|
96
97
|
// Validate schedule_value before writing IPC
|
|
@@ -136,6 +137,7 @@ SCHEDULE VALUE FORMAT (all times are LOCAL timezone):
|
|
|
136
137
|
type: 'schedule_task',
|
|
137
138
|
taskId,
|
|
138
139
|
prompt: args.prompt,
|
|
140
|
+
script: args.script || undefined,
|
|
139
141
|
schedule_type: args.schedule_type,
|
|
140
142
|
schedule_value: args.schedule_value,
|
|
141
143
|
context_mode: args.context_mode || 'group',
|
|
@@ -255,6 +257,7 @@ server.tool(
|
|
|
255
257
|
prompt: z.string().optional().describe('New prompt for the task'),
|
|
256
258
|
schedule_type: z.enum(['cron', 'interval', 'once']).optional().describe('New schedule type'),
|
|
257
259
|
schedule_value: z.string().optional().describe('New schedule value (see schedule_task for format)'),
|
|
260
|
+
script: z.string().optional().describe('New script for the task. Set to empty string to remove the script.'),
|
|
258
261
|
},
|
|
259
262
|
async (args) => {
|
|
260
263
|
// Validate schedule_value if provided
|
|
@@ -288,6 +291,7 @@ server.tool(
|
|
|
288
291
|
timestamp: new Date().toISOString(),
|
|
289
292
|
};
|
|
290
293
|
if (args.prompt !== undefined) data.prompt = args.prompt;
|
|
294
|
+
if (args.script !== undefined) data.script = args.script;
|
|
291
295
|
if (args.schedule_type !== undefined) data.schedule_type = args.schedule_type;
|
|
292
296
|
if (args.schedule_value !== undefined) data.schedule_value = args.schedule_value;
|
|
293
297
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Channel, OnChatMetadata, OnInboundMessage, RegisteredGroup } from '../types.js';
|
|
2
|
+
export interface TelegramChannelOpts {
|
|
3
|
+
onMessage: OnInboundMessage;
|
|
4
|
+
onChatMetadata: OnChatMetadata;
|
|
5
|
+
registeredGroups: () => Record<string, RegisteredGroup>;
|
|
6
|
+
}
|
|
7
|
+
export declare class TelegramChannel implements Channel {
|
|
8
|
+
name: string;
|
|
9
|
+
private bot;
|
|
10
|
+
private opts;
|
|
11
|
+
private botToken;
|
|
12
|
+
constructor(botToken: string, opts: TelegramChannelOpts);
|
|
13
|
+
connect(): Promise<void>;
|
|
14
|
+
sendMessage(jid: string, text: string): Promise<void>;
|
|
15
|
+
isConnected(): boolean;
|
|
16
|
+
ownsJid(jid: string): boolean;
|
|
17
|
+
disconnect(): Promise<void>;
|
|
18
|
+
setTyping(jid: string, isTyping: boolean): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,OAAO,EACP,cAAc,EACd,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,gBAAgB,CAAC;IAC5B,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CACzD;AAyBD,qBAAa,eAAgB,YAAW,OAAO;IAC7C,IAAI,SAAc;IAElB,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB;IAKjD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwLxB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B3D,WAAW,IAAI,OAAO;IAItB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAS/D"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import { Bot } from 'grammy';
|
|
3
|
+
import { ASSISTANT_NAME, TRIGGER_PATTERN } from '../config.js';
|
|
4
|
+
import { readEnvFile } from '../env.js';
|
|
5
|
+
import { logger } from '../logger.js';
|
|
6
|
+
import { registerChannel } from './registry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Send a message with Telegram Markdown parse mode, falling back to plain text.
|
|
9
|
+
* Claude's output naturally matches Telegram's Markdown v1 format:
|
|
10
|
+
* *bold*, _italic_, `code`, ```code blocks```, [links](url)
|
|
11
|
+
*/
|
|
12
|
+
async function sendTelegramMessage(api, chatId, text, options = {}) {
|
|
13
|
+
try {
|
|
14
|
+
await api.sendMessage(chatId, text, {
|
|
15
|
+
...options,
|
|
16
|
+
parse_mode: 'Markdown',
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
// Fallback: send as plain text if Markdown parsing fails
|
|
21
|
+
logger.debug({ err }, 'Markdown send failed, falling back to plain text');
|
|
22
|
+
await api.sendMessage(chatId, text, options);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class TelegramChannel {
|
|
26
|
+
name = 'telegram';
|
|
27
|
+
bot = null;
|
|
28
|
+
opts;
|
|
29
|
+
botToken;
|
|
30
|
+
constructor(botToken, opts) {
|
|
31
|
+
this.botToken = botToken;
|
|
32
|
+
this.opts = opts;
|
|
33
|
+
}
|
|
34
|
+
async connect() {
|
|
35
|
+
this.bot = new Bot(this.botToken, {
|
|
36
|
+
client: {
|
|
37
|
+
baseFetchConfig: { agent: https.globalAgent, compress: true },
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
// Command to get chat ID (useful for registration)
|
|
41
|
+
this.bot.command('chatid', (ctx) => {
|
|
42
|
+
const chatId = ctx.chat.id;
|
|
43
|
+
const chatType = ctx.chat.type;
|
|
44
|
+
const chatName = chatType === 'private'
|
|
45
|
+
? ctx.from?.first_name || 'Private'
|
|
46
|
+
: ctx.chat.title || 'Unknown';
|
|
47
|
+
ctx.reply(`Chat ID: \`tg:${chatId}\`\nName: ${chatName}\nType: ${chatType}`, { parse_mode: 'Markdown' });
|
|
48
|
+
});
|
|
49
|
+
// Command to check bot status
|
|
50
|
+
this.bot.command('ping', (ctx) => {
|
|
51
|
+
ctx.reply(`${ASSISTANT_NAME} is online.`);
|
|
52
|
+
});
|
|
53
|
+
// Telegram bot commands handled above — skip them in the general handler
|
|
54
|
+
// so they don't also get stored as messages. All other /commands flow through.
|
|
55
|
+
const TELEGRAM_BOT_COMMANDS = new Set(['chatid', 'ping']);
|
|
56
|
+
this.bot.on('message:text', async (ctx) => {
|
|
57
|
+
if (ctx.message.text.startsWith('/')) {
|
|
58
|
+
const cmd = ctx.message.text.slice(1).split(/[\s@]/)[0].toLowerCase();
|
|
59
|
+
if (TELEGRAM_BOT_COMMANDS.has(cmd))
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const chatJid = `tg:${ctx.chat.id}`;
|
|
63
|
+
let content = ctx.message.text;
|
|
64
|
+
const timestamp = new Date(ctx.message.date * 1000).toISOString();
|
|
65
|
+
const senderName = ctx.from?.first_name ||
|
|
66
|
+
ctx.from?.username ||
|
|
67
|
+
ctx.from?.id.toString() ||
|
|
68
|
+
'Unknown';
|
|
69
|
+
const sender = ctx.from?.id.toString() || '';
|
|
70
|
+
const msgId = ctx.message.message_id.toString();
|
|
71
|
+
// Determine chat name
|
|
72
|
+
const chatName = ctx.chat.type === 'private'
|
|
73
|
+
? senderName
|
|
74
|
+
: ctx.chat.title || chatJid;
|
|
75
|
+
// Translate Telegram @bot_username mentions into TRIGGER_PATTERN format.
|
|
76
|
+
// Telegram @mentions (e.g., @andy_ai_bot) won't match TRIGGER_PATTERN
|
|
77
|
+
// (e.g., ^@Andy\b), so we prepend the trigger when the bot is @mentioned.
|
|
78
|
+
const botUsername = ctx.me?.username?.toLowerCase();
|
|
79
|
+
if (botUsername) {
|
|
80
|
+
const entities = ctx.message.entities || [];
|
|
81
|
+
const isBotMentioned = entities.some((entity) => {
|
|
82
|
+
if (entity.type === 'mention') {
|
|
83
|
+
const mentionText = content
|
|
84
|
+
.substring(entity.offset, entity.offset + entity.length)
|
|
85
|
+
.toLowerCase();
|
|
86
|
+
return mentionText === `@${botUsername}`;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
});
|
|
90
|
+
if (isBotMentioned && !TRIGGER_PATTERN.test(content)) {
|
|
91
|
+
content = `@${ASSISTANT_NAME} ${content}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Store chat metadata for discovery
|
|
95
|
+
const isGroup = ctx.chat.type === 'group' || ctx.chat.type === 'supergroup';
|
|
96
|
+
this.opts.onChatMetadata(chatJid, timestamp, chatName, 'telegram', isGroup);
|
|
97
|
+
// Only deliver full message for registered groups
|
|
98
|
+
const group = this.opts.registeredGroups()[chatJid];
|
|
99
|
+
if (!group) {
|
|
100
|
+
logger.debug({ chatJid, chatName }, 'Message from unregistered Telegram chat');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Deliver message — startMessageLoop() will pick it up
|
|
104
|
+
this.opts.onMessage(chatJid, {
|
|
105
|
+
id: msgId,
|
|
106
|
+
chat_jid: chatJid,
|
|
107
|
+
sender,
|
|
108
|
+
sender_name: senderName,
|
|
109
|
+
content,
|
|
110
|
+
timestamp,
|
|
111
|
+
is_from_me: false,
|
|
112
|
+
});
|
|
113
|
+
logger.info({ chatJid, chatName, sender: senderName }, 'Telegram message stored');
|
|
114
|
+
});
|
|
115
|
+
// Handle non-text messages with placeholders so the agent knows something was sent
|
|
116
|
+
const storeNonText = (ctx, placeholder) => {
|
|
117
|
+
const chatJid = `tg:${ctx.chat.id}`;
|
|
118
|
+
const group = this.opts.registeredGroups()[chatJid];
|
|
119
|
+
if (!group)
|
|
120
|
+
return;
|
|
121
|
+
const timestamp = new Date(ctx.message.date * 1000).toISOString();
|
|
122
|
+
const senderName = ctx.from?.first_name ||
|
|
123
|
+
ctx.from?.username ||
|
|
124
|
+
ctx.from?.id?.toString() ||
|
|
125
|
+
'Unknown';
|
|
126
|
+
const caption = ctx.message.caption ? ` ${ctx.message.caption}` : '';
|
|
127
|
+
const isGroup = ctx.chat.type === 'group' || ctx.chat.type === 'supergroup';
|
|
128
|
+
this.opts.onChatMetadata(chatJid, timestamp, undefined, 'telegram', isGroup);
|
|
129
|
+
this.opts.onMessage(chatJid, {
|
|
130
|
+
id: ctx.message.message_id.toString(),
|
|
131
|
+
chat_jid: chatJid,
|
|
132
|
+
sender: ctx.from?.id?.toString() || '',
|
|
133
|
+
sender_name: senderName,
|
|
134
|
+
content: `${placeholder}${caption}`,
|
|
135
|
+
timestamp,
|
|
136
|
+
is_from_me: false,
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
this.bot.on('message:photo', (ctx) => storeNonText(ctx, '[Photo]'));
|
|
140
|
+
this.bot.on('message:video', (ctx) => storeNonText(ctx, '[Video]'));
|
|
141
|
+
this.bot.on('message:voice', (ctx) => storeNonText(ctx, '[Voice message]'));
|
|
142
|
+
this.bot.on('message:audio', (ctx) => storeNonText(ctx, '[Audio]'));
|
|
143
|
+
this.bot.on('message:document', (ctx) => {
|
|
144
|
+
const name = ctx.message.document?.file_name || 'file';
|
|
145
|
+
storeNonText(ctx, `[Document: ${name}]`);
|
|
146
|
+
});
|
|
147
|
+
this.bot.on('message:sticker', (ctx) => {
|
|
148
|
+
const emoji = ctx.message.sticker?.emoji || '';
|
|
149
|
+
storeNonText(ctx, `[Sticker ${emoji}]`);
|
|
150
|
+
});
|
|
151
|
+
this.bot.on('message:location', (ctx) => storeNonText(ctx, '[Location]'));
|
|
152
|
+
this.bot.on('message:contact', (ctx) => storeNonText(ctx, '[Contact]'));
|
|
153
|
+
// Handle errors gracefully
|
|
154
|
+
this.bot.catch((err) => {
|
|
155
|
+
logger.error({ err: err.message }, 'Telegram bot error');
|
|
156
|
+
});
|
|
157
|
+
// Start polling — returns a Promise that resolves when started
|
|
158
|
+
return new Promise((resolve) => {
|
|
159
|
+
this.bot.start({
|
|
160
|
+
onStart: (botInfo) => {
|
|
161
|
+
logger.info({ username: botInfo.username, id: botInfo.id }, 'Telegram bot connected');
|
|
162
|
+
console.log(`\n Telegram bot: @${botInfo.username}`);
|
|
163
|
+
console.log(` Send /chatid to the bot to get a chat's registration ID\n`);
|
|
164
|
+
resolve();
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async sendMessage(jid, text) {
|
|
170
|
+
if (!this.bot) {
|
|
171
|
+
logger.warn('Telegram bot not initialized');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const numericId = jid.replace(/^tg:/, '');
|
|
176
|
+
// Telegram has a 4096 character limit per message — split if needed
|
|
177
|
+
const MAX_LENGTH = 4096;
|
|
178
|
+
if (text.length <= MAX_LENGTH) {
|
|
179
|
+
await sendTelegramMessage(this.bot.api, numericId, text);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
for (let i = 0; i < text.length; i += MAX_LENGTH) {
|
|
183
|
+
await sendTelegramMessage(this.bot.api, numericId, text.slice(i, i + MAX_LENGTH));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
logger.info({ jid, length: text.length }, 'Telegram message sent');
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
logger.error({ jid, err }, 'Failed to send Telegram message');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
isConnected() {
|
|
193
|
+
return this.bot !== null;
|
|
194
|
+
}
|
|
195
|
+
ownsJid(jid) {
|
|
196
|
+
return jid.startsWith('tg:');
|
|
197
|
+
}
|
|
198
|
+
async disconnect() {
|
|
199
|
+
if (this.bot) {
|
|
200
|
+
this.bot.stop();
|
|
201
|
+
this.bot = null;
|
|
202
|
+
logger.info('Telegram bot stopped');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async setTyping(jid, isTyping) {
|
|
206
|
+
if (!this.bot || !isTyping)
|
|
207
|
+
return;
|
|
208
|
+
try {
|
|
209
|
+
const numericId = jid.replace(/^tg:/, '');
|
|
210
|
+
await this.bot.api.sendChatAction(numericId, 'typing');
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
logger.debug({ jid, err }, 'Failed to send Telegram typing indicator');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
registerChannel('telegram', (opts) => {
|
|
218
|
+
const envVars = readEnvFile(['TELEGRAM_BOT_TOKEN']);
|
|
219
|
+
const token = process.env.TELEGRAM_BOT_TOKEN || envVars.TELEGRAM_BOT_TOKEN || '';
|
|
220
|
+
if (!token) {
|
|
221
|
+
logger.warn('Telegram: TELEGRAM_BOT_TOKEN not set');
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
return new TelegramChannel(token, opts);
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.test.d.ts","sourceRoot":"","sources":["../../src/channels/telegram.test.ts"],"names":[],"mappings":""}
|