@ebowwa/glm-daemon 0.4.5 → 0.4.7
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/bin/discord-cli.js +375 -1
- package/dist/bin/telegram-cli.js +375 -1
- package/dist/index.js +375 -0
- package/package.json +5 -5
- package/src/channels/telegram.ts +105 -0
package/dist/bin/discord-cli.js
CHANGED
|
@@ -92156,7 +92156,86 @@ var require_src2 = __commonJS((exports) => {
|
|
|
92156
92156
|
__exportStar(require_dist3(), exports);
|
|
92157
92157
|
__exportStar(require_dist11(), exports);
|
|
92158
92158
|
});
|
|
92159
|
-
|
|
92159
|
+
// ../channel-types/dist/plugins/registry.js
|
|
92160
|
+
class PluginRegistryImpl {
|
|
92161
|
+
channels = new Map;
|
|
92162
|
+
channelOrder = [];
|
|
92163
|
+
registerChannel(registration) {
|
|
92164
|
+
const id = registration.plugin.id;
|
|
92165
|
+
if (typeof id !== "string") {
|
|
92166
|
+
throw new Error("Channel plugin id must be a string");
|
|
92167
|
+
}
|
|
92168
|
+
const normalizedId = id.trim().toLowerCase();
|
|
92169
|
+
if (this.channels.has(normalizedId)) {
|
|
92170
|
+
console.warn(`[PluginRegistry] Channel "${normalizedId}" already registered, replacing`);
|
|
92171
|
+
}
|
|
92172
|
+
this.channels.set(normalizedId, registration);
|
|
92173
|
+
if (!this.channelOrder.includes(normalizedId)) {
|
|
92174
|
+
this.channelOrder.push(normalizedId);
|
|
92175
|
+
}
|
|
92176
|
+
console.log(`[PluginRegistry] Registered channel: ${normalizedId} (source: ${registration.source})`);
|
|
92177
|
+
}
|
|
92178
|
+
unregisterChannel(channelId) {
|
|
92179
|
+
const normalizedId = channelId.trim().toLowerCase();
|
|
92180
|
+
const existed = this.channels.delete(normalizedId);
|
|
92181
|
+
if (existed) {
|
|
92182
|
+
this.channelOrder = this.channelOrder.filter((id) => id !== normalizedId);
|
|
92183
|
+
}
|
|
92184
|
+
return existed;
|
|
92185
|
+
}
|
|
92186
|
+
getChannel(channelId) {
|
|
92187
|
+
const normalizedId = this.normalizeChannelId(channelId);
|
|
92188
|
+
const registration = this.channels.get(normalizedId);
|
|
92189
|
+
return registration?.plugin;
|
|
92190
|
+
}
|
|
92191
|
+
getChannelRegistration(channelId) {
|
|
92192
|
+
const normalizedId = this.normalizeChannelId(channelId);
|
|
92193
|
+
return this.channels.get(normalizedId);
|
|
92194
|
+
}
|
|
92195
|
+
getChannels() {
|
|
92196
|
+
return this.channelOrder.map((id) => this.channels.get(id)?.plugin).filter((p) => p !== undefined);
|
|
92197
|
+
}
|
|
92198
|
+
getChannelRegistrations() {
|
|
92199
|
+
return this.channelOrder.map((id) => this.channels.get(id)).filter((r) => r !== undefined);
|
|
92200
|
+
}
|
|
92201
|
+
getChannelOrder() {
|
|
92202
|
+
return [...this.channelOrder];
|
|
92203
|
+
}
|
|
92204
|
+
setChannelOrder(order) {
|
|
92205
|
+
this.channelOrder = order.map((id) => id.toLowerCase().trim());
|
|
92206
|
+
}
|
|
92207
|
+
getChannelsByCapability(capability) {
|
|
92208
|
+
return this.getChannels().filter((plugin) => plugin.capabilities.supports[capability] === true);
|
|
92209
|
+
}
|
|
92210
|
+
getChannelsByChatType(chatType) {
|
|
92211
|
+
return this.getChannels().filter((plugin) => plugin.capabilities.chatTypes?.includes(chatType));
|
|
92212
|
+
}
|
|
92213
|
+
hasChannel(channelId) {
|
|
92214
|
+
return this.channels.has(this.normalizeChannelId(channelId));
|
|
92215
|
+
}
|
|
92216
|
+
normalizeChannelId(channelId) {
|
|
92217
|
+
const id = channelId.trim().toLowerCase();
|
|
92218
|
+
const aliases = {
|
|
92219
|
+
tg: "telegram",
|
|
92220
|
+
imsg: "imessage",
|
|
92221
|
+
wa: "whatsapp",
|
|
92222
|
+
dc: "discord",
|
|
92223
|
+
sl: "slack"
|
|
92224
|
+
};
|
|
92225
|
+
return aliases[id] || id;
|
|
92226
|
+
}
|
|
92227
|
+
clear() {
|
|
92228
|
+
this.channels.clear();
|
|
92229
|
+
this.channelOrder = [];
|
|
92230
|
+
}
|
|
92231
|
+
getStats() {
|
|
92232
|
+
return {
|
|
92233
|
+
channelCount: this.channels.size,
|
|
92234
|
+
channels: this.getChannelOrder()
|
|
92235
|
+
};
|
|
92236
|
+
}
|
|
92237
|
+
}
|
|
92238
|
+
var pluginRegistry = new PluginRegistryImpl;
|
|
92160
92239
|
// ../channel-types/dist/index.js
|
|
92161
92240
|
function createChannelId(platform, accountId, instanceId) {
|
|
92162
92241
|
return { platform, accountId, instanceId };
|
|
@@ -98838,6 +98917,266 @@ function registerAllCommands(bot, memory, tools) {
|
|
|
98838
98917
|
registerInnerthoughtsCommand(bot, memory, tools);
|
|
98839
98918
|
register(bot, tools);
|
|
98840
98919
|
}
|
|
98920
|
+
|
|
98921
|
+
// ../channel-telegram/dist/plugin.js
|
|
98922
|
+
var telegramMeta = {
|
|
98923
|
+
label: "Telegram",
|
|
98924
|
+
blurb: "Telegram Bot API for direct and group chats",
|
|
98925
|
+
icon: "\uD83D\uDCF1",
|
|
98926
|
+
docsPath: "/docs/channels/telegram",
|
|
98927
|
+
quickstartAllowFrom: true
|
|
98928
|
+
};
|
|
98929
|
+
var telegramConfigAdapter = {
|
|
98930
|
+
listAccountIds: async (config) => {
|
|
98931
|
+
const botToken = config.botToken;
|
|
98932
|
+
if (!botToken)
|
|
98933
|
+
return [];
|
|
98934
|
+
return ["default"];
|
|
98935
|
+
},
|
|
98936
|
+
resolveAccount: async (config, accountId) => {
|
|
98937
|
+
return {
|
|
98938
|
+
botToken: config.botToken,
|
|
98939
|
+
allowedUsers: config.allowedUsers,
|
|
98940
|
+
allowedChats: config.allowedChats,
|
|
98941
|
+
pollingInterval: config.pollingInterval || 1000
|
|
98942
|
+
};
|
|
98943
|
+
},
|
|
98944
|
+
validateAccount: async (account) => {
|
|
98945
|
+
if (!account.botToken)
|
|
98946
|
+
return false;
|
|
98947
|
+
return true;
|
|
98948
|
+
}
|
|
98949
|
+
};
|
|
98950
|
+
var createOutboundAdapter = (getBot) => ({
|
|
98951
|
+
deliveryMode: "direct",
|
|
98952
|
+
textChunkLimit: 4096,
|
|
98953
|
+
chunker: (text, limit) => {
|
|
98954
|
+
const chunks = [];
|
|
98955
|
+
for (let i = 0;i < text.length; i += limit) {
|
|
98956
|
+
chunks.push(text.slice(i, i + limit));
|
|
98957
|
+
}
|
|
98958
|
+
return { chunks, totalChunks: chunks.length };
|
|
98959
|
+
},
|
|
98960
|
+
sendText: async ({ to, text, accountId, account, replyToId, threadId }) => {
|
|
98961
|
+
const bot = getBot();
|
|
98962
|
+
if (!bot) {
|
|
98963
|
+
return { success: false, error: "Bot not initialized", timestamp: new Date };
|
|
98964
|
+
}
|
|
98965
|
+
try {
|
|
98966
|
+
const chatId = parseInt(to, 10);
|
|
98967
|
+
const options = {
|
|
98968
|
+
parse_mode: "Markdown"
|
|
98969
|
+
};
|
|
98970
|
+
if (replyToId) {
|
|
98971
|
+
options.reply_to_message_id = parseInt(replyToId, 10);
|
|
98972
|
+
}
|
|
98973
|
+
if (threadId) {
|
|
98974
|
+
options.message_thread_id = parseInt(threadId, 10);
|
|
98975
|
+
}
|
|
98976
|
+
const result = await bot.sendMessage(chatId, text, options);
|
|
98977
|
+
return {
|
|
98978
|
+
success: true,
|
|
98979
|
+
messageId: result.message_id.toString(),
|
|
98980
|
+
timestamp: new Date
|
|
98981
|
+
};
|
|
98982
|
+
} catch (error) {
|
|
98983
|
+
return {
|
|
98984
|
+
success: false,
|
|
98985
|
+
error: error.message,
|
|
98986
|
+
timestamp: new Date
|
|
98987
|
+
};
|
|
98988
|
+
}
|
|
98989
|
+
},
|
|
98990
|
+
sendMedia: async ({ to, text, mediaUrl, mediaType, accountId, account }) => {
|
|
98991
|
+
const bot = getBot();
|
|
98992
|
+
if (!bot) {
|
|
98993
|
+
return { success: false, error: "Bot not initialized", timestamp: new Date };
|
|
98994
|
+
}
|
|
98995
|
+
try {
|
|
98996
|
+
const chatId = parseInt(to, 10);
|
|
98997
|
+
let result;
|
|
98998
|
+
if (mediaType === "image") {
|
|
98999
|
+
result = await bot.sendPhoto(chatId, mediaUrl, { caption: text });
|
|
99000
|
+
} else if (mediaType === "video") {
|
|
99001
|
+
result = await bot.sendVideo(chatId, mediaUrl, { caption: text });
|
|
99002
|
+
} else if (mediaType === "audio") {
|
|
99003
|
+
result = await bot.sendAudio(chatId, mediaUrl, { caption: text });
|
|
99004
|
+
} else {
|
|
99005
|
+
result = await bot.sendDocument(chatId, mediaUrl, { caption: text });
|
|
99006
|
+
}
|
|
99007
|
+
return {
|
|
99008
|
+
success: true,
|
|
99009
|
+
messageId: result.message_id.toString(),
|
|
99010
|
+
timestamp: new Date
|
|
99011
|
+
};
|
|
99012
|
+
} catch (error) {
|
|
99013
|
+
return {
|
|
99014
|
+
success: false,
|
|
99015
|
+
error: error.message,
|
|
99016
|
+
timestamp: new Date
|
|
99017
|
+
};
|
|
99018
|
+
}
|
|
99019
|
+
}
|
|
99020
|
+
});
|
|
99021
|
+
var telegramThreadingAdapter = {
|
|
99022
|
+
replyModes: ["quote", "thread"],
|
|
99023
|
+
defaultReplyMode: "quote"
|
|
99024
|
+
};
|
|
99025
|
+
var createGatewayAdapter = (createBot) => {
|
|
99026
|
+
const activeBots = new Map;
|
|
99027
|
+
const messageHandlers = new Map;
|
|
99028
|
+
return {
|
|
99029
|
+
startAccount: async ({ accountId, account, onMessage }) => {
|
|
99030
|
+
const bot = createBot(account.botToken);
|
|
99031
|
+
const handler = (msg) => {
|
|
99032
|
+
if (account.allowedUsers?.length && !account.allowedUsers.includes(msg.from?.id || 0)) {
|
|
99033
|
+
return;
|
|
99034
|
+
}
|
|
99035
|
+
if (account.allowedChats?.length && !account.allowedChats.includes(msg.chat.id)) {
|
|
99036
|
+
return;
|
|
99037
|
+
}
|
|
99038
|
+
const channelId = {
|
|
99039
|
+
platform: "telegram",
|
|
99040
|
+
accountId: msg.chat.id.toString()
|
|
99041
|
+
};
|
|
99042
|
+
const channelMessage = {
|
|
99043
|
+
messageId: msg.message_id.toString(),
|
|
99044
|
+
channelId,
|
|
99045
|
+
timestamp: new Date(msg.date * 1000),
|
|
99046
|
+
sender: {
|
|
99047
|
+
id: msg.from?.id.toString() || "unknown",
|
|
99048
|
+
username: msg.from?.username,
|
|
99049
|
+
displayName: msg.from?.first_name,
|
|
99050
|
+
isBot: msg.from?.is_bot || false
|
|
99051
|
+
},
|
|
99052
|
+
text: msg.text || "",
|
|
99053
|
+
context: {
|
|
99054
|
+
isDM: msg.chat.type === "private",
|
|
99055
|
+
groupName: msg.chat.title,
|
|
99056
|
+
threadId: msg.message_thread_id?.toString()
|
|
99057
|
+
},
|
|
99058
|
+
replyTo: msg.reply_to_message ? {
|
|
99059
|
+
messageId: msg.reply_to_message.message_id.toString(),
|
|
99060
|
+
channelId
|
|
99061
|
+
} : undefined
|
|
99062
|
+
};
|
|
99063
|
+
onMessage(channelMessage);
|
|
99064
|
+
};
|
|
99065
|
+
bot.on("message", handler);
|
|
99066
|
+
activeBots.set(accountId, bot);
|
|
99067
|
+
messageHandlers.set(accountId, handler);
|
|
99068
|
+
},
|
|
99069
|
+
stopAccount: async ({ accountId, account }) => {
|
|
99070
|
+
const bot = activeBots.get(accountId);
|
|
99071
|
+
const handler = messageHandlers.get(accountId);
|
|
99072
|
+
if (bot && handler) {
|
|
99073
|
+
bot.off("message", handler);
|
|
99074
|
+
if (bot.isPolling()) {
|
|
99075
|
+
await bot.stopPolling();
|
|
99076
|
+
}
|
|
99077
|
+
activeBots.delete(accountId);
|
|
99078
|
+
messageHandlers.delete(accountId);
|
|
99079
|
+
}
|
|
99080
|
+
},
|
|
99081
|
+
isAccountActive: (accountId) => {
|
|
99082
|
+
return activeBots.has(accountId);
|
|
99083
|
+
}
|
|
99084
|
+
};
|
|
99085
|
+
};
|
|
99086
|
+
function createTelegramPlugin(config = {}, TelegramBotClass) {
|
|
99087
|
+
let bot = null;
|
|
99088
|
+
const createBot = (token) => {
|
|
99089
|
+
if (!TelegramBotClass) {
|
|
99090
|
+
throw new Error("TelegramBot class not provided");
|
|
99091
|
+
}
|
|
99092
|
+
return new TelegramBotClass(token, { polling: true });
|
|
99093
|
+
};
|
|
99094
|
+
return {
|
|
99095
|
+
id: "telegram",
|
|
99096
|
+
meta: telegramMeta,
|
|
99097
|
+
capabilities: {
|
|
99098
|
+
chatTypes: ["direct", "group", "channel", "thread"],
|
|
99099
|
+
supports: {
|
|
99100
|
+
text: true,
|
|
99101
|
+
media: true,
|
|
99102
|
+
replies: true,
|
|
99103
|
+
threads: true,
|
|
99104
|
+
reactions: true,
|
|
99105
|
+
editing: true,
|
|
99106
|
+
streaming: false,
|
|
99107
|
+
buttons: true
|
|
99108
|
+
},
|
|
99109
|
+
nativeCommands: true,
|
|
99110
|
+
rateLimits: {
|
|
99111
|
+
messagesPerMinute: 30,
|
|
99112
|
+
charactersPerMessage: 4096
|
|
99113
|
+
},
|
|
99114
|
+
media: {
|
|
99115
|
+
maxFileSize: 50 * 1024 * 1024,
|
|
99116
|
+
supportedMimeTypes: ["image/*", "video/*", "audio/*", "application/pdf"]
|
|
99117
|
+
}
|
|
99118
|
+
},
|
|
99119
|
+
config: telegramConfigAdapter,
|
|
99120
|
+
outbound: createOutboundAdapter(() => bot),
|
|
99121
|
+
gateway: createGatewayAdapter((token) => {
|
|
99122
|
+
bot = createBot(token);
|
|
99123
|
+
return bot;
|
|
99124
|
+
}),
|
|
99125
|
+
threading: telegramThreadingAdapter
|
|
99126
|
+
};
|
|
99127
|
+
}
|
|
99128
|
+
var telegramPlugin = createTelegramPlugin();
|
|
99129
|
+
if (process.env.TELEGRAM_BOT_TOKEN) {
|
|
99130
|
+
pluginRegistry.registerChannel({
|
|
99131
|
+
pluginId: "telegram",
|
|
99132
|
+
plugin: telegramPlugin,
|
|
99133
|
+
source: "core"
|
|
99134
|
+
});
|
|
99135
|
+
}
|
|
99136
|
+
// ../channel-telegram/dist/utils/normalize.js
|
|
99137
|
+
function normalizeTelegramMessagingTarget(raw) {
|
|
99138
|
+
const trimmed = raw.trim();
|
|
99139
|
+
if (!trimmed)
|
|
99140
|
+
return;
|
|
99141
|
+
let normalized = trimmed;
|
|
99142
|
+
if (normalized.startsWith("telegram:")) {
|
|
99143
|
+
normalized = normalized.slice("telegram:".length).trim();
|
|
99144
|
+
} else if (normalized.startsWith("tg:")) {
|
|
99145
|
+
normalized = normalized.slice("tg:".length).trim();
|
|
99146
|
+
}
|
|
99147
|
+
if (!normalized)
|
|
99148
|
+
return;
|
|
99149
|
+
const tmeMatch = /^https?:\/\/t\.me\/([A-Za-z0-9_]+)$/i.exec(normalized) ?? /^t\.me\/([A-Za-z0-9_]+)$/i.exec(normalized);
|
|
99150
|
+
if (tmeMatch?.[1]) {
|
|
99151
|
+
normalized = `@${tmeMatch[1]}`;
|
|
99152
|
+
}
|
|
99153
|
+
if (!normalized)
|
|
99154
|
+
return;
|
|
99155
|
+
return `telegram:${normalized}`.toLowerCase();
|
|
99156
|
+
}
|
|
99157
|
+
function looksLikeTelegramTargetId(raw) {
|
|
99158
|
+
const trimmed = raw.trim();
|
|
99159
|
+
if (!trimmed)
|
|
99160
|
+
return false;
|
|
99161
|
+
if (/^(telegram|tg):/i.test(trimmed))
|
|
99162
|
+
return true;
|
|
99163
|
+
if (trimmed.startsWith("@"))
|
|
99164
|
+
return true;
|
|
99165
|
+
return /^-?\d{6,}$/.test(trimmed);
|
|
99166
|
+
}
|
|
99167
|
+
function extractRawTarget(normalized) {
|
|
99168
|
+
const trimmed = normalized.trim();
|
|
99169
|
+
if (!trimmed.startsWith("telegram:"))
|
|
99170
|
+
return;
|
|
99171
|
+
const raw = trimmed.slice("telegram:".length);
|
|
99172
|
+
return raw || undefined;
|
|
99173
|
+
}
|
|
99174
|
+
function isNumericIdTarget(normalized) {
|
|
99175
|
+
const raw = extractRawTarget(normalized);
|
|
99176
|
+
if (!raw)
|
|
99177
|
+
return false;
|
|
99178
|
+
return /^-?\d+$/.test(raw);
|
|
99179
|
+
}
|
|
98841
99180
|
// ../channel-telegram/dist/index.js
|
|
98842
99181
|
class TelegramChannel {
|
|
98843
99182
|
id;
|
|
@@ -99202,6 +99541,41 @@ class GLMTelegramChannel extends BaseChannel {
|
|
|
99202
99541
|
isAllowed(userId, chatId) {
|
|
99203
99542
|
return this.protocolAdapter.isAllowed(userId, chatId);
|
|
99204
99543
|
}
|
|
99544
|
+
normalizeTarget(raw) {
|
|
99545
|
+
return normalizeTelegramMessagingTarget(raw);
|
|
99546
|
+
}
|
|
99547
|
+
isValidTarget(raw) {
|
|
99548
|
+
return looksLikeTelegramTargetId(raw);
|
|
99549
|
+
}
|
|
99550
|
+
parseTargetFromInput(input) {
|
|
99551
|
+
const words = input.split(/\s+/);
|
|
99552
|
+
for (const word of words) {
|
|
99553
|
+
if (looksLikeTelegramTargetId(word)) {
|
|
99554
|
+
const normalized = normalizeTelegramMessagingTarget(word);
|
|
99555
|
+
if (normalized) {
|
|
99556
|
+
return extractRawTarget(normalized);
|
|
99557
|
+
}
|
|
99558
|
+
}
|
|
99559
|
+
}
|
|
99560
|
+
return;
|
|
99561
|
+
}
|
|
99562
|
+
async sendToTarget(target, text) {
|
|
99563
|
+
const normalized = normalizeTelegramMessagingTarget(target);
|
|
99564
|
+
if (!normalized) {
|
|
99565
|
+
throw new Error(`Invalid Telegram target: ${target}`);
|
|
99566
|
+
}
|
|
99567
|
+
const rawTarget = extractRawTarget(normalized);
|
|
99568
|
+
if (!rawTarget) {
|
|
99569
|
+
throw new Error(`Failed to extract target from: ${normalized}`);
|
|
99570
|
+
}
|
|
99571
|
+
let chatId;
|
|
99572
|
+
if (isNumericIdTarget(normalized)) {
|
|
99573
|
+
chatId = parseInt(rawTarget, 10);
|
|
99574
|
+
} else {
|
|
99575
|
+
throw new Error(`Username targets require resolution. Use numeric chat ID instead, or implement username resolution. Target: ${rawTarget}`);
|
|
99576
|
+
}
|
|
99577
|
+
await this.sendMessage(chatId, text);
|
|
99578
|
+
}
|
|
99205
99579
|
}
|
|
99206
99580
|
// src/channels/discord.ts
|
|
99207
99581
|
var import_discord = __toESM(require_src2(), 1);
|
package/dist/bin/telegram-cli.js
CHANGED
|
@@ -92156,7 +92156,86 @@ var require_src2 = __commonJS((exports) => {
|
|
|
92156
92156
|
__exportStar(require_dist3(), exports);
|
|
92157
92157
|
__exportStar(require_dist11(), exports);
|
|
92158
92158
|
});
|
|
92159
|
-
|
|
92159
|
+
// ../channel-types/dist/plugins/registry.js
|
|
92160
|
+
class PluginRegistryImpl {
|
|
92161
|
+
channels = new Map;
|
|
92162
|
+
channelOrder = [];
|
|
92163
|
+
registerChannel(registration) {
|
|
92164
|
+
const id = registration.plugin.id;
|
|
92165
|
+
if (typeof id !== "string") {
|
|
92166
|
+
throw new Error("Channel plugin id must be a string");
|
|
92167
|
+
}
|
|
92168
|
+
const normalizedId = id.trim().toLowerCase();
|
|
92169
|
+
if (this.channels.has(normalizedId)) {
|
|
92170
|
+
console.warn(`[PluginRegistry] Channel "${normalizedId}" already registered, replacing`);
|
|
92171
|
+
}
|
|
92172
|
+
this.channels.set(normalizedId, registration);
|
|
92173
|
+
if (!this.channelOrder.includes(normalizedId)) {
|
|
92174
|
+
this.channelOrder.push(normalizedId);
|
|
92175
|
+
}
|
|
92176
|
+
console.log(`[PluginRegistry] Registered channel: ${normalizedId} (source: ${registration.source})`);
|
|
92177
|
+
}
|
|
92178
|
+
unregisterChannel(channelId) {
|
|
92179
|
+
const normalizedId = channelId.trim().toLowerCase();
|
|
92180
|
+
const existed = this.channels.delete(normalizedId);
|
|
92181
|
+
if (existed) {
|
|
92182
|
+
this.channelOrder = this.channelOrder.filter((id) => id !== normalizedId);
|
|
92183
|
+
}
|
|
92184
|
+
return existed;
|
|
92185
|
+
}
|
|
92186
|
+
getChannel(channelId) {
|
|
92187
|
+
const normalizedId = this.normalizeChannelId(channelId);
|
|
92188
|
+
const registration = this.channels.get(normalizedId);
|
|
92189
|
+
return registration?.plugin;
|
|
92190
|
+
}
|
|
92191
|
+
getChannelRegistration(channelId) {
|
|
92192
|
+
const normalizedId = this.normalizeChannelId(channelId);
|
|
92193
|
+
return this.channels.get(normalizedId);
|
|
92194
|
+
}
|
|
92195
|
+
getChannels() {
|
|
92196
|
+
return this.channelOrder.map((id) => this.channels.get(id)?.plugin).filter((p) => p !== undefined);
|
|
92197
|
+
}
|
|
92198
|
+
getChannelRegistrations() {
|
|
92199
|
+
return this.channelOrder.map((id) => this.channels.get(id)).filter((r) => r !== undefined);
|
|
92200
|
+
}
|
|
92201
|
+
getChannelOrder() {
|
|
92202
|
+
return [...this.channelOrder];
|
|
92203
|
+
}
|
|
92204
|
+
setChannelOrder(order) {
|
|
92205
|
+
this.channelOrder = order.map((id) => id.toLowerCase().trim());
|
|
92206
|
+
}
|
|
92207
|
+
getChannelsByCapability(capability) {
|
|
92208
|
+
return this.getChannels().filter((plugin) => plugin.capabilities.supports[capability] === true);
|
|
92209
|
+
}
|
|
92210
|
+
getChannelsByChatType(chatType) {
|
|
92211
|
+
return this.getChannels().filter((plugin) => plugin.capabilities.chatTypes?.includes(chatType));
|
|
92212
|
+
}
|
|
92213
|
+
hasChannel(channelId) {
|
|
92214
|
+
return this.channels.has(this.normalizeChannelId(channelId));
|
|
92215
|
+
}
|
|
92216
|
+
normalizeChannelId(channelId) {
|
|
92217
|
+
const id = channelId.trim().toLowerCase();
|
|
92218
|
+
const aliases = {
|
|
92219
|
+
tg: "telegram",
|
|
92220
|
+
imsg: "imessage",
|
|
92221
|
+
wa: "whatsapp",
|
|
92222
|
+
dc: "discord",
|
|
92223
|
+
sl: "slack"
|
|
92224
|
+
};
|
|
92225
|
+
return aliases[id] || id;
|
|
92226
|
+
}
|
|
92227
|
+
clear() {
|
|
92228
|
+
this.channels.clear();
|
|
92229
|
+
this.channelOrder = [];
|
|
92230
|
+
}
|
|
92231
|
+
getStats() {
|
|
92232
|
+
return {
|
|
92233
|
+
channelCount: this.channels.size,
|
|
92234
|
+
channels: this.getChannelOrder()
|
|
92235
|
+
};
|
|
92236
|
+
}
|
|
92237
|
+
}
|
|
92238
|
+
var pluginRegistry = new PluginRegistryImpl;
|
|
92160
92239
|
// ../channel-types/dist/index.js
|
|
92161
92240
|
function createChannelId(platform, accountId, instanceId) {
|
|
92162
92241
|
return { platform, accountId, instanceId };
|
|
@@ -98838,6 +98917,266 @@ function registerAllCommands(bot, memory, tools) {
|
|
|
98838
98917
|
registerInnerthoughtsCommand(bot, memory, tools);
|
|
98839
98918
|
register(bot, tools);
|
|
98840
98919
|
}
|
|
98920
|
+
|
|
98921
|
+
// ../channel-telegram/dist/plugin.js
|
|
98922
|
+
var telegramMeta = {
|
|
98923
|
+
label: "Telegram",
|
|
98924
|
+
blurb: "Telegram Bot API for direct and group chats",
|
|
98925
|
+
icon: "\uD83D\uDCF1",
|
|
98926
|
+
docsPath: "/docs/channels/telegram",
|
|
98927
|
+
quickstartAllowFrom: true
|
|
98928
|
+
};
|
|
98929
|
+
var telegramConfigAdapter = {
|
|
98930
|
+
listAccountIds: async (config) => {
|
|
98931
|
+
const botToken = config.botToken;
|
|
98932
|
+
if (!botToken)
|
|
98933
|
+
return [];
|
|
98934
|
+
return ["default"];
|
|
98935
|
+
},
|
|
98936
|
+
resolveAccount: async (config, accountId) => {
|
|
98937
|
+
return {
|
|
98938
|
+
botToken: config.botToken,
|
|
98939
|
+
allowedUsers: config.allowedUsers,
|
|
98940
|
+
allowedChats: config.allowedChats,
|
|
98941
|
+
pollingInterval: config.pollingInterval || 1000
|
|
98942
|
+
};
|
|
98943
|
+
},
|
|
98944
|
+
validateAccount: async (account) => {
|
|
98945
|
+
if (!account.botToken)
|
|
98946
|
+
return false;
|
|
98947
|
+
return true;
|
|
98948
|
+
}
|
|
98949
|
+
};
|
|
98950
|
+
var createOutboundAdapter = (getBot) => ({
|
|
98951
|
+
deliveryMode: "direct",
|
|
98952
|
+
textChunkLimit: 4096,
|
|
98953
|
+
chunker: (text, limit) => {
|
|
98954
|
+
const chunks = [];
|
|
98955
|
+
for (let i = 0;i < text.length; i += limit) {
|
|
98956
|
+
chunks.push(text.slice(i, i + limit));
|
|
98957
|
+
}
|
|
98958
|
+
return { chunks, totalChunks: chunks.length };
|
|
98959
|
+
},
|
|
98960
|
+
sendText: async ({ to, text, accountId, account, replyToId, threadId }) => {
|
|
98961
|
+
const bot = getBot();
|
|
98962
|
+
if (!bot) {
|
|
98963
|
+
return { success: false, error: "Bot not initialized", timestamp: new Date };
|
|
98964
|
+
}
|
|
98965
|
+
try {
|
|
98966
|
+
const chatId = parseInt(to, 10);
|
|
98967
|
+
const options = {
|
|
98968
|
+
parse_mode: "Markdown"
|
|
98969
|
+
};
|
|
98970
|
+
if (replyToId) {
|
|
98971
|
+
options.reply_to_message_id = parseInt(replyToId, 10);
|
|
98972
|
+
}
|
|
98973
|
+
if (threadId) {
|
|
98974
|
+
options.message_thread_id = parseInt(threadId, 10);
|
|
98975
|
+
}
|
|
98976
|
+
const result = await bot.sendMessage(chatId, text, options);
|
|
98977
|
+
return {
|
|
98978
|
+
success: true,
|
|
98979
|
+
messageId: result.message_id.toString(),
|
|
98980
|
+
timestamp: new Date
|
|
98981
|
+
};
|
|
98982
|
+
} catch (error) {
|
|
98983
|
+
return {
|
|
98984
|
+
success: false,
|
|
98985
|
+
error: error.message,
|
|
98986
|
+
timestamp: new Date
|
|
98987
|
+
};
|
|
98988
|
+
}
|
|
98989
|
+
},
|
|
98990
|
+
sendMedia: async ({ to, text, mediaUrl, mediaType, accountId, account }) => {
|
|
98991
|
+
const bot = getBot();
|
|
98992
|
+
if (!bot) {
|
|
98993
|
+
return { success: false, error: "Bot not initialized", timestamp: new Date };
|
|
98994
|
+
}
|
|
98995
|
+
try {
|
|
98996
|
+
const chatId = parseInt(to, 10);
|
|
98997
|
+
let result;
|
|
98998
|
+
if (mediaType === "image") {
|
|
98999
|
+
result = await bot.sendPhoto(chatId, mediaUrl, { caption: text });
|
|
99000
|
+
} else if (mediaType === "video") {
|
|
99001
|
+
result = await bot.sendVideo(chatId, mediaUrl, { caption: text });
|
|
99002
|
+
} else if (mediaType === "audio") {
|
|
99003
|
+
result = await bot.sendAudio(chatId, mediaUrl, { caption: text });
|
|
99004
|
+
} else {
|
|
99005
|
+
result = await bot.sendDocument(chatId, mediaUrl, { caption: text });
|
|
99006
|
+
}
|
|
99007
|
+
return {
|
|
99008
|
+
success: true,
|
|
99009
|
+
messageId: result.message_id.toString(),
|
|
99010
|
+
timestamp: new Date
|
|
99011
|
+
};
|
|
99012
|
+
} catch (error) {
|
|
99013
|
+
return {
|
|
99014
|
+
success: false,
|
|
99015
|
+
error: error.message,
|
|
99016
|
+
timestamp: new Date
|
|
99017
|
+
};
|
|
99018
|
+
}
|
|
99019
|
+
}
|
|
99020
|
+
});
|
|
99021
|
+
var telegramThreadingAdapter = {
|
|
99022
|
+
replyModes: ["quote", "thread"],
|
|
99023
|
+
defaultReplyMode: "quote"
|
|
99024
|
+
};
|
|
99025
|
+
var createGatewayAdapter = (createBot) => {
|
|
99026
|
+
const activeBots = new Map;
|
|
99027
|
+
const messageHandlers = new Map;
|
|
99028
|
+
return {
|
|
99029
|
+
startAccount: async ({ accountId, account, onMessage }) => {
|
|
99030
|
+
const bot = createBot(account.botToken);
|
|
99031
|
+
const handler = (msg) => {
|
|
99032
|
+
if (account.allowedUsers?.length && !account.allowedUsers.includes(msg.from?.id || 0)) {
|
|
99033
|
+
return;
|
|
99034
|
+
}
|
|
99035
|
+
if (account.allowedChats?.length && !account.allowedChats.includes(msg.chat.id)) {
|
|
99036
|
+
return;
|
|
99037
|
+
}
|
|
99038
|
+
const channelId = {
|
|
99039
|
+
platform: "telegram",
|
|
99040
|
+
accountId: msg.chat.id.toString()
|
|
99041
|
+
};
|
|
99042
|
+
const channelMessage = {
|
|
99043
|
+
messageId: msg.message_id.toString(),
|
|
99044
|
+
channelId,
|
|
99045
|
+
timestamp: new Date(msg.date * 1000),
|
|
99046
|
+
sender: {
|
|
99047
|
+
id: msg.from?.id.toString() || "unknown",
|
|
99048
|
+
username: msg.from?.username,
|
|
99049
|
+
displayName: msg.from?.first_name,
|
|
99050
|
+
isBot: msg.from?.is_bot || false
|
|
99051
|
+
},
|
|
99052
|
+
text: msg.text || "",
|
|
99053
|
+
context: {
|
|
99054
|
+
isDM: msg.chat.type === "private",
|
|
99055
|
+
groupName: msg.chat.title,
|
|
99056
|
+
threadId: msg.message_thread_id?.toString()
|
|
99057
|
+
},
|
|
99058
|
+
replyTo: msg.reply_to_message ? {
|
|
99059
|
+
messageId: msg.reply_to_message.message_id.toString(),
|
|
99060
|
+
channelId
|
|
99061
|
+
} : undefined
|
|
99062
|
+
};
|
|
99063
|
+
onMessage(channelMessage);
|
|
99064
|
+
};
|
|
99065
|
+
bot.on("message", handler);
|
|
99066
|
+
activeBots.set(accountId, bot);
|
|
99067
|
+
messageHandlers.set(accountId, handler);
|
|
99068
|
+
},
|
|
99069
|
+
stopAccount: async ({ accountId, account }) => {
|
|
99070
|
+
const bot = activeBots.get(accountId);
|
|
99071
|
+
const handler = messageHandlers.get(accountId);
|
|
99072
|
+
if (bot && handler) {
|
|
99073
|
+
bot.off("message", handler);
|
|
99074
|
+
if (bot.isPolling()) {
|
|
99075
|
+
await bot.stopPolling();
|
|
99076
|
+
}
|
|
99077
|
+
activeBots.delete(accountId);
|
|
99078
|
+
messageHandlers.delete(accountId);
|
|
99079
|
+
}
|
|
99080
|
+
},
|
|
99081
|
+
isAccountActive: (accountId) => {
|
|
99082
|
+
return activeBots.has(accountId);
|
|
99083
|
+
}
|
|
99084
|
+
};
|
|
99085
|
+
};
|
|
99086
|
+
function createTelegramPlugin(config = {}, TelegramBotClass) {
|
|
99087
|
+
let bot = null;
|
|
99088
|
+
const createBot = (token) => {
|
|
99089
|
+
if (!TelegramBotClass) {
|
|
99090
|
+
throw new Error("TelegramBot class not provided");
|
|
99091
|
+
}
|
|
99092
|
+
return new TelegramBotClass(token, { polling: true });
|
|
99093
|
+
};
|
|
99094
|
+
return {
|
|
99095
|
+
id: "telegram",
|
|
99096
|
+
meta: telegramMeta,
|
|
99097
|
+
capabilities: {
|
|
99098
|
+
chatTypes: ["direct", "group", "channel", "thread"],
|
|
99099
|
+
supports: {
|
|
99100
|
+
text: true,
|
|
99101
|
+
media: true,
|
|
99102
|
+
replies: true,
|
|
99103
|
+
threads: true,
|
|
99104
|
+
reactions: true,
|
|
99105
|
+
editing: true,
|
|
99106
|
+
streaming: false,
|
|
99107
|
+
buttons: true
|
|
99108
|
+
},
|
|
99109
|
+
nativeCommands: true,
|
|
99110
|
+
rateLimits: {
|
|
99111
|
+
messagesPerMinute: 30,
|
|
99112
|
+
charactersPerMessage: 4096
|
|
99113
|
+
},
|
|
99114
|
+
media: {
|
|
99115
|
+
maxFileSize: 50 * 1024 * 1024,
|
|
99116
|
+
supportedMimeTypes: ["image/*", "video/*", "audio/*", "application/pdf"]
|
|
99117
|
+
}
|
|
99118
|
+
},
|
|
99119
|
+
config: telegramConfigAdapter,
|
|
99120
|
+
outbound: createOutboundAdapter(() => bot),
|
|
99121
|
+
gateway: createGatewayAdapter((token) => {
|
|
99122
|
+
bot = createBot(token);
|
|
99123
|
+
return bot;
|
|
99124
|
+
}),
|
|
99125
|
+
threading: telegramThreadingAdapter
|
|
99126
|
+
};
|
|
99127
|
+
}
|
|
99128
|
+
var telegramPlugin = createTelegramPlugin();
|
|
99129
|
+
if (process.env.TELEGRAM_BOT_TOKEN) {
|
|
99130
|
+
pluginRegistry.registerChannel({
|
|
99131
|
+
pluginId: "telegram",
|
|
99132
|
+
plugin: telegramPlugin,
|
|
99133
|
+
source: "core"
|
|
99134
|
+
});
|
|
99135
|
+
}
|
|
99136
|
+
// ../channel-telegram/dist/utils/normalize.js
|
|
99137
|
+
function normalizeTelegramMessagingTarget(raw) {
|
|
99138
|
+
const trimmed = raw.trim();
|
|
99139
|
+
if (!trimmed)
|
|
99140
|
+
return;
|
|
99141
|
+
let normalized = trimmed;
|
|
99142
|
+
if (normalized.startsWith("telegram:")) {
|
|
99143
|
+
normalized = normalized.slice("telegram:".length).trim();
|
|
99144
|
+
} else if (normalized.startsWith("tg:")) {
|
|
99145
|
+
normalized = normalized.slice("tg:".length).trim();
|
|
99146
|
+
}
|
|
99147
|
+
if (!normalized)
|
|
99148
|
+
return;
|
|
99149
|
+
const tmeMatch = /^https?:\/\/t\.me\/([A-Za-z0-9_]+)$/i.exec(normalized) ?? /^t\.me\/([A-Za-z0-9_]+)$/i.exec(normalized);
|
|
99150
|
+
if (tmeMatch?.[1]) {
|
|
99151
|
+
normalized = `@${tmeMatch[1]}`;
|
|
99152
|
+
}
|
|
99153
|
+
if (!normalized)
|
|
99154
|
+
return;
|
|
99155
|
+
return `telegram:${normalized}`.toLowerCase();
|
|
99156
|
+
}
|
|
99157
|
+
function looksLikeTelegramTargetId(raw) {
|
|
99158
|
+
const trimmed = raw.trim();
|
|
99159
|
+
if (!trimmed)
|
|
99160
|
+
return false;
|
|
99161
|
+
if (/^(telegram|tg):/i.test(trimmed))
|
|
99162
|
+
return true;
|
|
99163
|
+
if (trimmed.startsWith("@"))
|
|
99164
|
+
return true;
|
|
99165
|
+
return /^-?\d{6,}$/.test(trimmed);
|
|
99166
|
+
}
|
|
99167
|
+
function extractRawTarget(normalized) {
|
|
99168
|
+
const trimmed = normalized.trim();
|
|
99169
|
+
if (!trimmed.startsWith("telegram:"))
|
|
99170
|
+
return;
|
|
99171
|
+
const raw = trimmed.slice("telegram:".length);
|
|
99172
|
+
return raw || undefined;
|
|
99173
|
+
}
|
|
99174
|
+
function isNumericIdTarget(normalized) {
|
|
99175
|
+
const raw = extractRawTarget(normalized);
|
|
99176
|
+
if (!raw)
|
|
99177
|
+
return false;
|
|
99178
|
+
return /^-?\d+$/.test(raw);
|
|
99179
|
+
}
|
|
98841
99180
|
// ../channel-telegram/dist/index.js
|
|
98842
99181
|
class TelegramChannel {
|
|
98843
99182
|
id;
|
|
@@ -99202,6 +99541,41 @@ class GLMTelegramChannel extends BaseChannel {
|
|
|
99202
99541
|
isAllowed(userId, chatId) {
|
|
99203
99542
|
return this.protocolAdapter.isAllowed(userId, chatId);
|
|
99204
99543
|
}
|
|
99544
|
+
normalizeTarget(raw) {
|
|
99545
|
+
return normalizeTelegramMessagingTarget(raw);
|
|
99546
|
+
}
|
|
99547
|
+
isValidTarget(raw) {
|
|
99548
|
+
return looksLikeTelegramTargetId(raw);
|
|
99549
|
+
}
|
|
99550
|
+
parseTargetFromInput(input) {
|
|
99551
|
+
const words = input.split(/\s+/);
|
|
99552
|
+
for (const word of words) {
|
|
99553
|
+
if (looksLikeTelegramTargetId(word)) {
|
|
99554
|
+
const normalized = normalizeTelegramMessagingTarget(word);
|
|
99555
|
+
if (normalized) {
|
|
99556
|
+
return extractRawTarget(normalized);
|
|
99557
|
+
}
|
|
99558
|
+
}
|
|
99559
|
+
}
|
|
99560
|
+
return;
|
|
99561
|
+
}
|
|
99562
|
+
async sendToTarget(target, text) {
|
|
99563
|
+
const normalized = normalizeTelegramMessagingTarget(target);
|
|
99564
|
+
if (!normalized) {
|
|
99565
|
+
throw new Error(`Invalid Telegram target: ${target}`);
|
|
99566
|
+
}
|
|
99567
|
+
const rawTarget = extractRawTarget(normalized);
|
|
99568
|
+
if (!rawTarget) {
|
|
99569
|
+
throw new Error(`Failed to extract target from: ${normalized}`);
|
|
99570
|
+
}
|
|
99571
|
+
let chatId;
|
|
99572
|
+
if (isNumericIdTarget(normalized)) {
|
|
99573
|
+
chatId = parseInt(rawTarget, 10);
|
|
99574
|
+
} else {
|
|
99575
|
+
throw new Error(`Username targets require resolution. Use numeric chat ID instead, or implement username resolution. Target: ${rawTarget}`);
|
|
99576
|
+
}
|
|
99577
|
+
await this.sendMessage(chatId, text);
|
|
99578
|
+
}
|
|
99205
99579
|
}
|
|
99206
99580
|
// src/channels/discord.ts
|
|
99207
99581
|
var import_discord = __toESM(require_src2(), 1);
|
package/dist/index.js
CHANGED
|
@@ -97992,6 +97992,86 @@ class StringConversationMemory extends ConversationMemory {
|
|
|
97992
97992
|
super(config);
|
|
97993
97993
|
}
|
|
97994
97994
|
}
|
|
97995
|
+
// ../channel-types/dist/plugins/registry.js
|
|
97996
|
+
class PluginRegistryImpl {
|
|
97997
|
+
channels = new Map;
|
|
97998
|
+
channelOrder = [];
|
|
97999
|
+
registerChannel(registration) {
|
|
98000
|
+
const id = registration.plugin.id;
|
|
98001
|
+
if (typeof id !== "string") {
|
|
98002
|
+
throw new Error("Channel plugin id must be a string");
|
|
98003
|
+
}
|
|
98004
|
+
const normalizedId = id.trim().toLowerCase();
|
|
98005
|
+
if (this.channels.has(normalizedId)) {
|
|
98006
|
+
console.warn(`[PluginRegistry] Channel "${normalizedId}" already registered, replacing`);
|
|
98007
|
+
}
|
|
98008
|
+
this.channels.set(normalizedId, registration);
|
|
98009
|
+
if (!this.channelOrder.includes(normalizedId)) {
|
|
98010
|
+
this.channelOrder.push(normalizedId);
|
|
98011
|
+
}
|
|
98012
|
+
console.log(`[PluginRegistry] Registered channel: ${normalizedId} (source: ${registration.source})`);
|
|
98013
|
+
}
|
|
98014
|
+
unregisterChannel(channelId) {
|
|
98015
|
+
const normalizedId = channelId.trim().toLowerCase();
|
|
98016
|
+
const existed = this.channels.delete(normalizedId);
|
|
98017
|
+
if (existed) {
|
|
98018
|
+
this.channelOrder = this.channelOrder.filter((id) => id !== normalizedId);
|
|
98019
|
+
}
|
|
98020
|
+
return existed;
|
|
98021
|
+
}
|
|
98022
|
+
getChannel(channelId) {
|
|
98023
|
+
const normalizedId = this.normalizeChannelId(channelId);
|
|
98024
|
+
const registration = this.channels.get(normalizedId);
|
|
98025
|
+
return registration?.plugin;
|
|
98026
|
+
}
|
|
98027
|
+
getChannelRegistration(channelId) {
|
|
98028
|
+
const normalizedId = this.normalizeChannelId(channelId);
|
|
98029
|
+
return this.channels.get(normalizedId);
|
|
98030
|
+
}
|
|
98031
|
+
getChannels() {
|
|
98032
|
+
return this.channelOrder.map((id) => this.channels.get(id)?.plugin).filter((p) => p !== undefined);
|
|
98033
|
+
}
|
|
98034
|
+
getChannelRegistrations() {
|
|
98035
|
+
return this.channelOrder.map((id) => this.channels.get(id)).filter((r) => r !== undefined);
|
|
98036
|
+
}
|
|
98037
|
+
getChannelOrder() {
|
|
98038
|
+
return [...this.channelOrder];
|
|
98039
|
+
}
|
|
98040
|
+
setChannelOrder(order) {
|
|
98041
|
+
this.channelOrder = order.map((id) => id.toLowerCase().trim());
|
|
98042
|
+
}
|
|
98043
|
+
getChannelsByCapability(capability) {
|
|
98044
|
+
return this.getChannels().filter((plugin) => plugin.capabilities.supports[capability] === true);
|
|
98045
|
+
}
|
|
98046
|
+
getChannelsByChatType(chatType) {
|
|
98047
|
+
return this.getChannels().filter((plugin) => plugin.capabilities.chatTypes?.includes(chatType));
|
|
98048
|
+
}
|
|
98049
|
+
hasChannel(channelId) {
|
|
98050
|
+
return this.channels.has(this.normalizeChannelId(channelId));
|
|
98051
|
+
}
|
|
98052
|
+
normalizeChannelId(channelId) {
|
|
98053
|
+
const id = channelId.trim().toLowerCase();
|
|
98054
|
+
const aliases = {
|
|
98055
|
+
tg: "telegram",
|
|
98056
|
+
imsg: "imessage",
|
|
98057
|
+
wa: "whatsapp",
|
|
98058
|
+
dc: "discord",
|
|
98059
|
+
sl: "slack"
|
|
98060
|
+
};
|
|
98061
|
+
return aliases[id] || id;
|
|
98062
|
+
}
|
|
98063
|
+
clear() {
|
|
98064
|
+
this.channels.clear();
|
|
98065
|
+
this.channelOrder = [];
|
|
98066
|
+
}
|
|
98067
|
+
getStats() {
|
|
98068
|
+
return {
|
|
98069
|
+
channelCount: this.channels.size,
|
|
98070
|
+
channels: this.getChannelOrder()
|
|
98071
|
+
};
|
|
98072
|
+
}
|
|
98073
|
+
}
|
|
98074
|
+
var pluginRegistry = new PluginRegistryImpl;
|
|
97995
98075
|
// ../channel-types/dist/index.js
|
|
97996
98076
|
function createChannelId(platform, accountId, instanceId) {
|
|
97997
98077
|
return { platform, accountId, instanceId };
|
|
@@ -99032,6 +99112,266 @@ function registerAllCommands(bot, memory, tools) {
|
|
|
99032
99112
|
registerInnerthoughtsCommand(bot, memory, tools);
|
|
99033
99113
|
register(bot, tools);
|
|
99034
99114
|
}
|
|
99115
|
+
|
|
99116
|
+
// ../channel-telegram/dist/plugin.js
|
|
99117
|
+
var telegramMeta = {
|
|
99118
|
+
label: "Telegram",
|
|
99119
|
+
blurb: "Telegram Bot API for direct and group chats",
|
|
99120
|
+
icon: "\uD83D\uDCF1",
|
|
99121
|
+
docsPath: "/docs/channels/telegram",
|
|
99122
|
+
quickstartAllowFrom: true
|
|
99123
|
+
};
|
|
99124
|
+
var telegramConfigAdapter = {
|
|
99125
|
+
listAccountIds: async (config) => {
|
|
99126
|
+
const botToken = config.botToken;
|
|
99127
|
+
if (!botToken)
|
|
99128
|
+
return [];
|
|
99129
|
+
return ["default"];
|
|
99130
|
+
},
|
|
99131
|
+
resolveAccount: async (config, accountId) => {
|
|
99132
|
+
return {
|
|
99133
|
+
botToken: config.botToken,
|
|
99134
|
+
allowedUsers: config.allowedUsers,
|
|
99135
|
+
allowedChats: config.allowedChats,
|
|
99136
|
+
pollingInterval: config.pollingInterval || 1000
|
|
99137
|
+
};
|
|
99138
|
+
},
|
|
99139
|
+
validateAccount: async (account) => {
|
|
99140
|
+
if (!account.botToken)
|
|
99141
|
+
return false;
|
|
99142
|
+
return true;
|
|
99143
|
+
}
|
|
99144
|
+
};
|
|
99145
|
+
var createOutboundAdapter = (getBot) => ({
|
|
99146
|
+
deliveryMode: "direct",
|
|
99147
|
+
textChunkLimit: 4096,
|
|
99148
|
+
chunker: (text, limit) => {
|
|
99149
|
+
const chunks = [];
|
|
99150
|
+
for (let i = 0;i < text.length; i += limit) {
|
|
99151
|
+
chunks.push(text.slice(i, i + limit));
|
|
99152
|
+
}
|
|
99153
|
+
return { chunks, totalChunks: chunks.length };
|
|
99154
|
+
},
|
|
99155
|
+
sendText: async ({ to, text, accountId, account, replyToId, threadId }) => {
|
|
99156
|
+
const bot = getBot();
|
|
99157
|
+
if (!bot) {
|
|
99158
|
+
return { success: false, error: "Bot not initialized", timestamp: new Date };
|
|
99159
|
+
}
|
|
99160
|
+
try {
|
|
99161
|
+
const chatId = parseInt(to, 10);
|
|
99162
|
+
const options = {
|
|
99163
|
+
parse_mode: "Markdown"
|
|
99164
|
+
};
|
|
99165
|
+
if (replyToId) {
|
|
99166
|
+
options.reply_to_message_id = parseInt(replyToId, 10);
|
|
99167
|
+
}
|
|
99168
|
+
if (threadId) {
|
|
99169
|
+
options.message_thread_id = parseInt(threadId, 10);
|
|
99170
|
+
}
|
|
99171
|
+
const result = await bot.sendMessage(chatId, text, options);
|
|
99172
|
+
return {
|
|
99173
|
+
success: true,
|
|
99174
|
+
messageId: result.message_id.toString(),
|
|
99175
|
+
timestamp: new Date
|
|
99176
|
+
};
|
|
99177
|
+
} catch (error) {
|
|
99178
|
+
return {
|
|
99179
|
+
success: false,
|
|
99180
|
+
error: error.message,
|
|
99181
|
+
timestamp: new Date
|
|
99182
|
+
};
|
|
99183
|
+
}
|
|
99184
|
+
},
|
|
99185
|
+
sendMedia: async ({ to, text, mediaUrl, mediaType, accountId, account }) => {
|
|
99186
|
+
const bot = getBot();
|
|
99187
|
+
if (!bot) {
|
|
99188
|
+
return { success: false, error: "Bot not initialized", timestamp: new Date };
|
|
99189
|
+
}
|
|
99190
|
+
try {
|
|
99191
|
+
const chatId = parseInt(to, 10);
|
|
99192
|
+
let result;
|
|
99193
|
+
if (mediaType === "image") {
|
|
99194
|
+
result = await bot.sendPhoto(chatId, mediaUrl, { caption: text });
|
|
99195
|
+
} else if (mediaType === "video") {
|
|
99196
|
+
result = await bot.sendVideo(chatId, mediaUrl, { caption: text });
|
|
99197
|
+
} else if (mediaType === "audio") {
|
|
99198
|
+
result = await bot.sendAudio(chatId, mediaUrl, { caption: text });
|
|
99199
|
+
} else {
|
|
99200
|
+
result = await bot.sendDocument(chatId, mediaUrl, { caption: text });
|
|
99201
|
+
}
|
|
99202
|
+
return {
|
|
99203
|
+
success: true,
|
|
99204
|
+
messageId: result.message_id.toString(),
|
|
99205
|
+
timestamp: new Date
|
|
99206
|
+
};
|
|
99207
|
+
} catch (error) {
|
|
99208
|
+
return {
|
|
99209
|
+
success: false,
|
|
99210
|
+
error: error.message,
|
|
99211
|
+
timestamp: new Date
|
|
99212
|
+
};
|
|
99213
|
+
}
|
|
99214
|
+
}
|
|
99215
|
+
});
|
|
99216
|
+
var telegramThreadingAdapter = {
|
|
99217
|
+
replyModes: ["quote", "thread"],
|
|
99218
|
+
defaultReplyMode: "quote"
|
|
99219
|
+
};
|
|
99220
|
+
var createGatewayAdapter = (createBot) => {
|
|
99221
|
+
const activeBots = new Map;
|
|
99222
|
+
const messageHandlers = new Map;
|
|
99223
|
+
return {
|
|
99224
|
+
startAccount: async ({ accountId, account, onMessage }) => {
|
|
99225
|
+
const bot = createBot(account.botToken);
|
|
99226
|
+
const handler = (msg) => {
|
|
99227
|
+
if (account.allowedUsers?.length && !account.allowedUsers.includes(msg.from?.id || 0)) {
|
|
99228
|
+
return;
|
|
99229
|
+
}
|
|
99230
|
+
if (account.allowedChats?.length && !account.allowedChats.includes(msg.chat.id)) {
|
|
99231
|
+
return;
|
|
99232
|
+
}
|
|
99233
|
+
const channelId = {
|
|
99234
|
+
platform: "telegram",
|
|
99235
|
+
accountId: msg.chat.id.toString()
|
|
99236
|
+
};
|
|
99237
|
+
const channelMessage = {
|
|
99238
|
+
messageId: msg.message_id.toString(),
|
|
99239
|
+
channelId,
|
|
99240
|
+
timestamp: new Date(msg.date * 1000),
|
|
99241
|
+
sender: {
|
|
99242
|
+
id: msg.from?.id.toString() || "unknown",
|
|
99243
|
+
username: msg.from?.username,
|
|
99244
|
+
displayName: msg.from?.first_name,
|
|
99245
|
+
isBot: msg.from?.is_bot || false
|
|
99246
|
+
},
|
|
99247
|
+
text: msg.text || "",
|
|
99248
|
+
context: {
|
|
99249
|
+
isDM: msg.chat.type === "private",
|
|
99250
|
+
groupName: msg.chat.title,
|
|
99251
|
+
threadId: msg.message_thread_id?.toString()
|
|
99252
|
+
},
|
|
99253
|
+
replyTo: msg.reply_to_message ? {
|
|
99254
|
+
messageId: msg.reply_to_message.message_id.toString(),
|
|
99255
|
+
channelId
|
|
99256
|
+
} : undefined
|
|
99257
|
+
};
|
|
99258
|
+
onMessage(channelMessage);
|
|
99259
|
+
};
|
|
99260
|
+
bot.on("message", handler);
|
|
99261
|
+
activeBots.set(accountId, bot);
|
|
99262
|
+
messageHandlers.set(accountId, handler);
|
|
99263
|
+
},
|
|
99264
|
+
stopAccount: async ({ accountId, account }) => {
|
|
99265
|
+
const bot = activeBots.get(accountId);
|
|
99266
|
+
const handler = messageHandlers.get(accountId);
|
|
99267
|
+
if (bot && handler) {
|
|
99268
|
+
bot.off("message", handler);
|
|
99269
|
+
if (bot.isPolling()) {
|
|
99270
|
+
await bot.stopPolling();
|
|
99271
|
+
}
|
|
99272
|
+
activeBots.delete(accountId);
|
|
99273
|
+
messageHandlers.delete(accountId);
|
|
99274
|
+
}
|
|
99275
|
+
},
|
|
99276
|
+
isAccountActive: (accountId) => {
|
|
99277
|
+
return activeBots.has(accountId);
|
|
99278
|
+
}
|
|
99279
|
+
};
|
|
99280
|
+
};
|
|
99281
|
+
function createTelegramPlugin(config = {}, TelegramBotClass) {
|
|
99282
|
+
let bot = null;
|
|
99283
|
+
const createBot = (token) => {
|
|
99284
|
+
if (!TelegramBotClass) {
|
|
99285
|
+
throw new Error("TelegramBot class not provided");
|
|
99286
|
+
}
|
|
99287
|
+
return new TelegramBotClass(token, { polling: true });
|
|
99288
|
+
};
|
|
99289
|
+
return {
|
|
99290
|
+
id: "telegram",
|
|
99291
|
+
meta: telegramMeta,
|
|
99292
|
+
capabilities: {
|
|
99293
|
+
chatTypes: ["direct", "group", "channel", "thread"],
|
|
99294
|
+
supports: {
|
|
99295
|
+
text: true,
|
|
99296
|
+
media: true,
|
|
99297
|
+
replies: true,
|
|
99298
|
+
threads: true,
|
|
99299
|
+
reactions: true,
|
|
99300
|
+
editing: true,
|
|
99301
|
+
streaming: false,
|
|
99302
|
+
buttons: true
|
|
99303
|
+
},
|
|
99304
|
+
nativeCommands: true,
|
|
99305
|
+
rateLimits: {
|
|
99306
|
+
messagesPerMinute: 30,
|
|
99307
|
+
charactersPerMessage: 4096
|
|
99308
|
+
},
|
|
99309
|
+
media: {
|
|
99310
|
+
maxFileSize: 50 * 1024 * 1024,
|
|
99311
|
+
supportedMimeTypes: ["image/*", "video/*", "audio/*", "application/pdf"]
|
|
99312
|
+
}
|
|
99313
|
+
},
|
|
99314
|
+
config: telegramConfigAdapter,
|
|
99315
|
+
outbound: createOutboundAdapter(() => bot),
|
|
99316
|
+
gateway: createGatewayAdapter((token) => {
|
|
99317
|
+
bot = createBot(token);
|
|
99318
|
+
return bot;
|
|
99319
|
+
}),
|
|
99320
|
+
threading: telegramThreadingAdapter
|
|
99321
|
+
};
|
|
99322
|
+
}
|
|
99323
|
+
var telegramPlugin = createTelegramPlugin();
|
|
99324
|
+
if (process.env.TELEGRAM_BOT_TOKEN) {
|
|
99325
|
+
pluginRegistry.registerChannel({
|
|
99326
|
+
pluginId: "telegram",
|
|
99327
|
+
plugin: telegramPlugin,
|
|
99328
|
+
source: "core"
|
|
99329
|
+
});
|
|
99330
|
+
}
|
|
99331
|
+
// ../channel-telegram/dist/utils/normalize.js
|
|
99332
|
+
function normalizeTelegramMessagingTarget(raw) {
|
|
99333
|
+
const trimmed = raw.trim();
|
|
99334
|
+
if (!trimmed)
|
|
99335
|
+
return;
|
|
99336
|
+
let normalized = trimmed;
|
|
99337
|
+
if (normalized.startsWith("telegram:")) {
|
|
99338
|
+
normalized = normalized.slice("telegram:".length).trim();
|
|
99339
|
+
} else if (normalized.startsWith("tg:")) {
|
|
99340
|
+
normalized = normalized.slice("tg:".length).trim();
|
|
99341
|
+
}
|
|
99342
|
+
if (!normalized)
|
|
99343
|
+
return;
|
|
99344
|
+
const tmeMatch = /^https?:\/\/t\.me\/([A-Za-z0-9_]+)$/i.exec(normalized) ?? /^t\.me\/([A-Za-z0-9_]+)$/i.exec(normalized);
|
|
99345
|
+
if (tmeMatch?.[1]) {
|
|
99346
|
+
normalized = `@${tmeMatch[1]}`;
|
|
99347
|
+
}
|
|
99348
|
+
if (!normalized)
|
|
99349
|
+
return;
|
|
99350
|
+
return `telegram:${normalized}`.toLowerCase();
|
|
99351
|
+
}
|
|
99352
|
+
function looksLikeTelegramTargetId(raw) {
|
|
99353
|
+
const trimmed = raw.trim();
|
|
99354
|
+
if (!trimmed)
|
|
99355
|
+
return false;
|
|
99356
|
+
if (/^(telegram|tg):/i.test(trimmed))
|
|
99357
|
+
return true;
|
|
99358
|
+
if (trimmed.startsWith("@"))
|
|
99359
|
+
return true;
|
|
99360
|
+
return /^-?\d{6,}$/.test(trimmed);
|
|
99361
|
+
}
|
|
99362
|
+
function extractRawTarget(normalized) {
|
|
99363
|
+
const trimmed = normalized.trim();
|
|
99364
|
+
if (!trimmed.startsWith("telegram:"))
|
|
99365
|
+
return;
|
|
99366
|
+
const raw = trimmed.slice("telegram:".length);
|
|
99367
|
+
return raw || undefined;
|
|
99368
|
+
}
|
|
99369
|
+
function isNumericIdTarget(normalized) {
|
|
99370
|
+
const raw = extractRawTarget(normalized);
|
|
99371
|
+
if (!raw)
|
|
99372
|
+
return false;
|
|
99373
|
+
return /^-?\d+$/.test(raw);
|
|
99374
|
+
}
|
|
99035
99375
|
// ../channel-telegram/dist/index.js
|
|
99036
99376
|
class TelegramChannel {
|
|
99037
99377
|
id;
|
|
@@ -99396,6 +99736,41 @@ class GLMTelegramChannel extends BaseChannel {
|
|
|
99396
99736
|
isAllowed(userId, chatId) {
|
|
99397
99737
|
return this.protocolAdapter.isAllowed(userId, chatId);
|
|
99398
99738
|
}
|
|
99739
|
+
normalizeTarget(raw) {
|
|
99740
|
+
return normalizeTelegramMessagingTarget(raw);
|
|
99741
|
+
}
|
|
99742
|
+
isValidTarget(raw) {
|
|
99743
|
+
return looksLikeTelegramTargetId(raw);
|
|
99744
|
+
}
|
|
99745
|
+
parseTargetFromInput(input) {
|
|
99746
|
+
const words = input.split(/\s+/);
|
|
99747
|
+
for (const word of words) {
|
|
99748
|
+
if (looksLikeTelegramTargetId(word)) {
|
|
99749
|
+
const normalized = normalizeTelegramMessagingTarget(word);
|
|
99750
|
+
if (normalized) {
|
|
99751
|
+
return extractRawTarget(normalized);
|
|
99752
|
+
}
|
|
99753
|
+
}
|
|
99754
|
+
}
|
|
99755
|
+
return;
|
|
99756
|
+
}
|
|
99757
|
+
async sendToTarget(target, text) {
|
|
99758
|
+
const normalized = normalizeTelegramMessagingTarget(target);
|
|
99759
|
+
if (!normalized) {
|
|
99760
|
+
throw new Error(`Invalid Telegram target: ${target}`);
|
|
99761
|
+
}
|
|
99762
|
+
const rawTarget = extractRawTarget(normalized);
|
|
99763
|
+
if (!rawTarget) {
|
|
99764
|
+
throw new Error(`Failed to extract target from: ${normalized}`);
|
|
99765
|
+
}
|
|
99766
|
+
let chatId;
|
|
99767
|
+
if (isNumericIdTarget(normalized)) {
|
|
99768
|
+
chatId = parseInt(rawTarget, 10);
|
|
99769
|
+
} else {
|
|
99770
|
+
throw new Error(`Username targets require resolution. Use numeric chat ID instead, or implement username resolution. Target: ${rawTarget}`);
|
|
99771
|
+
}
|
|
99772
|
+
await this.sendMessage(chatId, text);
|
|
99773
|
+
}
|
|
99399
99774
|
}
|
|
99400
99775
|
// src/channels/discord.ts
|
|
99401
99776
|
var import_discord = __toESM(require_src2(), 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ebowwa/glm-daemon",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "Autonomous GLM 4.7 daemon with hooks, tools, teammates, and communication channels (Telegram, Discord)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -63,10 +63,10 @@
|
|
|
63
63
|
"zod": "^4.3.5"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@types/bun": "
|
|
67
|
-
"@types/node": "
|
|
68
|
-
"typescript": "
|
|
69
|
-
"bun-types": "
|
|
66
|
+
"@types/bun": "latest",
|
|
67
|
+
"@types/node": "latest",
|
|
68
|
+
"typescript": "latest",
|
|
69
|
+
"bun-types": "latest"
|
|
70
70
|
},
|
|
71
71
|
"files": [
|
|
72
72
|
"dist",
|
package/src/channels/telegram.ts
CHANGED
|
@@ -12,12 +12,27 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
TelegramChannel as TelegramProtocolAdapter,
|
|
14
14
|
type TelegramConfig as ProtocolConfig,
|
|
15
|
+
// Telegram target normalization utilities
|
|
16
|
+
normalizeTelegramMessagingTarget,
|
|
17
|
+
looksLikeTelegramTargetId,
|
|
18
|
+
extractRawTarget,
|
|
19
|
+
isUsernameTarget,
|
|
20
|
+
isNumericIdTarget,
|
|
15
21
|
} from "@ebowwa/channel-telegram";
|
|
16
22
|
import {
|
|
17
23
|
BaseChannel,
|
|
18
24
|
type GLMChannelConfig,
|
|
19
25
|
} from "./base.js";
|
|
20
26
|
|
|
27
|
+
// Re-export normalization utilities for consumers
|
|
28
|
+
export {
|
|
29
|
+
normalizeTelegramMessagingTarget,
|
|
30
|
+
looksLikeTelegramTargetId,
|
|
31
|
+
extractRawTarget,
|
|
32
|
+
isUsernameTarget,
|
|
33
|
+
isNumericIdTarget,
|
|
34
|
+
};
|
|
35
|
+
|
|
21
36
|
// ============================================================
|
|
22
37
|
// TELEGRAM CHANNEL CONFIG
|
|
23
38
|
// ============================================================
|
|
@@ -163,6 +178,96 @@ export class GLMTelegramChannel extends BaseChannel {
|
|
|
163
178
|
isAllowed(userId?: number, chatId?: number): boolean {
|
|
164
179
|
return this.protocolAdapter.isAllowed(userId, chatId);
|
|
165
180
|
}
|
|
181
|
+
|
|
182
|
+
// ============================================================
|
|
183
|
+
// Target Normalization Helpers
|
|
184
|
+
// ============================================================
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Normalize a Telegram target (username, URL, or ID) to standard format.
|
|
188
|
+
*
|
|
189
|
+
* @param raw - Raw input (@username, t.me/user, 123456, etc.)
|
|
190
|
+
* @returns Normalized target or undefined if invalid
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* channel.normalizeTarget("@durov") // "telegram:@durov"
|
|
194
|
+
* channel.normalizeTarget("t.me/durov") // "telegram:@durov"
|
|
195
|
+
* channel.normalizeTarget("123456") // "telegram:123456"
|
|
196
|
+
*/
|
|
197
|
+
normalizeTarget(raw: string): string | undefined {
|
|
198
|
+
return normalizeTelegramMessagingTarget(raw);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Check if a string looks like a Telegram target.
|
|
203
|
+
*
|
|
204
|
+
* @param raw - Raw input string
|
|
205
|
+
* @returns true if it looks like a Telegram target
|
|
206
|
+
*/
|
|
207
|
+
isValidTarget(raw: string): boolean {
|
|
208
|
+
return looksLikeTelegramTargetId(raw);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Parse a target from user input and extract the usable form.
|
|
213
|
+
*
|
|
214
|
+
* @param input - User input like "send to @user" or "dm t.me/user"
|
|
215
|
+
* @returns Extracted raw target (@username or numeric ID) or undefined
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* channel.parseTargetFromInput("send to @durov") // "@durov"
|
|
219
|
+
* channel.parseTargetFromInput("dm 123456") // "123456"
|
|
220
|
+
*/
|
|
221
|
+
parseTargetFromInput(input: string): string | undefined {
|
|
222
|
+
const words = input.split(/\s+/);
|
|
223
|
+
for (const word of words) {
|
|
224
|
+
if (looksLikeTelegramTargetId(word)) {
|
|
225
|
+
const normalized = normalizeTelegramMessagingTarget(word);
|
|
226
|
+
if (normalized) {
|
|
227
|
+
return extractRawTarget(normalized);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Send a message to a target (username or chat ID).
|
|
236
|
+
*
|
|
237
|
+
* @param target - Telegram target (@username, numeric ID, or normalized format)
|
|
238
|
+
* @param text - Message text
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* await channel.sendToTarget("@durov", "Hello!")
|
|
242
|
+
* await channel.sendToTarget("123456", "Hello!")
|
|
243
|
+
*/
|
|
244
|
+
async sendToTarget(target: string, text: string): Promise<void> {
|
|
245
|
+
const normalized = normalizeTelegramMessagingTarget(target);
|
|
246
|
+
if (!normalized) {
|
|
247
|
+
throw new Error(`Invalid Telegram target: ${target}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const rawTarget = extractRawTarget(normalized);
|
|
251
|
+
if (!rawTarget) {
|
|
252
|
+
throw new Error(`Failed to extract target from: ${normalized}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Parse chat ID (numeric or resolve username)
|
|
256
|
+
let chatId: number;
|
|
257
|
+
|
|
258
|
+
if (isNumericIdTarget(normalized)) {
|
|
259
|
+
chatId = parseInt(rawTarget, 10);
|
|
260
|
+
} else {
|
|
261
|
+
// Username target - need to resolve via bot API
|
|
262
|
+
// Note: This requires the bot to have seen the user/channel before
|
|
263
|
+
// For now, we'll try direct message with username (may fail if not cached)
|
|
264
|
+
throw new Error(
|
|
265
|
+
`Username targets require resolution. Use numeric chat ID instead, or implement username resolution. Target: ${rawTarget}`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
await this.sendMessage(chatId, text);
|
|
270
|
+
}
|
|
166
271
|
}
|
|
167
272
|
|
|
168
273
|
// ============================================================
|