@wu529778790/open-im 0.3.12 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,49 +1,40 @@
1
- import { loadConfig, needsSetup } from './config.js';
2
- import { runInteractiveSetup } from './setup.js';
1
+ import { createServer } from "node:http";
2
+ import { writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { loadConfig, needsSetup } from "./config.js";
5
+ import { runInteractiveSetup } from "./setup.js";
3
6
  // 导出供 cli.ts 使用
4
7
  export { needsSetup, runInteractiveSetup };
5
- import { initTelegram, stopTelegram } from './telegram/client.js';
6
- import { setupTelegramHandlers } from './telegram/event-handler.js';
7
- import { sendTextReply } from './telegram/message-sender.js';
8
- import { initAdapters } from './adapters/registry.js';
9
- import { SessionManager } from './session/session-manager.js';
10
- import { loadActiveChats, getActiveChatId, flushActiveChats } from './shared/active-chats.js';
11
- import { initLogger, createLogger, closeLogger } from './logger.js';
12
- import { createRequire } from 'node:module';
13
- import { join } from 'node:path';
14
- import { homedir } from 'node:os';
15
- import { rm } from 'node:fs/promises';
16
- import { existsSync } from 'node:fs';
8
+ import { initTelegram, stopTelegram } from "./telegram/client.js";
9
+ import { setupTelegramHandlers } from "./telegram/event-handler.js";
10
+ import { sendTextReply as sendTelegramTextReply } from "./telegram/message-sender.js";
11
+ import { initFeishu, stopFeishu } from "./feishu/client.js";
12
+ import { setupFeishuHandlers } from "./feishu/event-handler.js";
13
+ import { sendTextReply as sendFeishuTextReply } from "./feishu/message-sender.js";
14
+ import { initAdapters } from "./adapters/registry.js";
15
+ import { SessionManager } from "./session/session-manager.js";
16
+ import { loadActiveChats, getActiveChatId, flushActiveChats, } from "./shared/active-chats.js";
17
+ import { initLogger, createLogger, closeLogger } from "./logger.js";
18
+ import { APP_HOME, SHUTDOWN_PORT } from "./constants.js";
19
+ import { createRequire } from "node:module";
17
20
  const require = createRequire(import.meta.url);
18
- const { version: APP_VERSION } = require('../package.json');
19
- const log = createLogger('Main');
20
- // 停止标记文件路径
21
- const STOP_FILE = join(homedir(), '.open-im', 'stop.flag');
22
- // 检查是否收到停止信号
23
- function checkStopSignal() {
24
- return existsSync(STOP_FILE);
25
- }
26
- // 清理停止标记文件
27
- async function clearStopSignal() {
28
- try {
29
- if (existsSync(STOP_FILE)) {
30
- await rm(STOP_FILE);
31
- }
32
- }
33
- catch {
34
- // 忽略错误
35
- }
36
- }
21
+ const { version: APP_VERSION } = require("../package.json");
22
+ const log = createLogger("Main");
37
23
  async function sendLifecycleNotification(platform, message) {
38
- const chatId = getActiveChatId('telegram');
39
- if (!chatId)
40
- return;
41
- try {
42
- await sendTextReply(chatId, message);
24
+ const telegramChatId = getActiveChatId("telegram");
25
+ const feishuChatId = getActiveChatId("feishu");
26
+ const sendPromises = [];
27
+ if (platform === "telegram" && telegramChatId) {
28
+ sendPromises.push(sendTelegramTextReply(telegramChatId, message).catch((err) => {
29
+ log.debug("Failed to send Telegram notification:", err);
30
+ }));
43
31
  }
44
- catch (err) {
45
- log.debug('Failed to send lifecycle notification:', err);
32
+ if (platform === "feishu" && feishuChatId) {
33
+ sendPromises.push(sendFeishuTextReply(feishuChatId, message).catch((err) => {
34
+ log.debug("Failed to send Feishu notification:", err);
35
+ }));
46
36
  }
37
+ await Promise.all(sendPromises);
47
38
  }
48
39
  export async function main() {
49
40
  if (needsSetup()) {
@@ -55,66 +46,91 @@ export async function main() {
55
46
  initLogger(config.logDir, config.logLevel);
56
47
  loadActiveChats();
57
48
  initAdapters(config);
58
- log.info('Starting open-im bridge...');
49
+ log.info("Starting open-im bridge...");
59
50
  log.info(`AI 工具: ${config.aiCommand}`);
60
51
  log.info(`工作目录: ${config.claudeWorkDir}`);
52
+ log.info(`启用平台: ${config.enabledPlatforms.join(", ")}`);
61
53
  const sessionManager = new SessionManager(config.claudeWorkDir, config.allowedBaseDirs);
62
54
  let telegramHandle = null;
63
- if (config.enabledPlatforms.includes('telegram')) {
55
+ let feishuHandle = null;
56
+ if (config.enabledPlatforms.includes("telegram")) {
64
57
  await initTelegram(config, (bot) => {
65
58
  telegramHandle = setupTelegramHandlers(bot, config, sessionManager);
66
59
  });
67
60
  }
68
- log.info('Service is running. Press Ctrl+C to stop.');
61
+ if (config.enabledPlatforms.includes("feishu")) {
62
+ feishuHandle = setupFeishuHandlers(config, sessionManager);
63
+ await initFeishu(config, feishuHandle.handleEvent);
64
+ }
65
+ log.info("Service is running. Press Ctrl+C to stop.");
69
66
  const startupMsg = [
70
67
  `🟢 open-im v${APP_VERSION} 服务已启动`,
71
- '',
68
+ "",
72
69
  `AI 工具: ${config.aiCommand}`,
73
70
  `工作目录: ${config.claudeWorkDir}`,
74
- ].join('\n');
75
- await sendLifecycleNotification('telegram', startupMsg).catch(() => { });
71
+ `启用平台: ${config.enabledPlatforms.join(", ")}`,
72
+ ].join("\n");
73
+ // Send notification to all enabled platforms
74
+ for (const platform of config.enabledPlatforms) {
75
+ await sendLifecycleNotification(platform, startupMsg).catch(() => { });
76
+ }
76
77
  const startedAt = Date.now();
77
78
  // 防止重复发送关闭通知
78
79
  let shutdownNotificationSent = false;
79
80
  const shutdown = async () => {
80
- log.info('Shutting down...');
81
+ log.info("Shutting down...");
81
82
  const uptimeSec = Math.floor((Date.now() - startedAt) / 1000);
82
83
  const m = Math.floor(uptimeSec / 60);
83
- // 只发送一次通知
84
- if (!shutdownNotificationSent) {
85
- shutdownNotificationSent = true;
86
- try {
87
- await sendLifecycleNotification('telegram', `🔴 open-im 服务正在关闭...\n运行时长: ${m}分钟`);
88
- // 等待消息发送完成
89
- await new Promise(resolve => setTimeout(resolve, 500));
90
- }
91
- catch (err) {
92
- log.debug('Failed to send shutdown notification:', err);
93
- }
84
+ const shutdownMsg = `🔴 open-im 服务正在关闭...\n运行时长: ${m}分钟`;
85
+ // Send notification to all enabled platforms
86
+ for (const platform of config.enabledPlatforms) {
87
+ await sendLifecycleNotification(platform, shutdownMsg).catch(() => { });
88
+ }
89
+ shutdownServer?.close();
90
+ const portFile = join(APP_HOME, "open-im.port");
91
+ try {
92
+ if (existsSync(portFile))
93
+ unlinkSync(portFile);
94
+ }
95
+ catch {
96
+ /* ignore */
94
97
  }
95
- // 清理停止标记文件
96
- await clearStopSignal();
97
98
  telegramHandle?.stop();
98
99
  stopTelegram();
100
+ feishuHandle?.stop();
101
+ stopFeishu();
99
102
  sessionManager.destroy();
100
103
  flushActiveChats();
101
104
  closeLogger();
102
105
  process.exit(0);
103
106
  };
104
- process.on('SIGINT', () => shutdown().catch(() => process.exit(1)));
105
- process.on('SIGTERM', () => shutdown().catch(() => process.exit(1)));
106
- // 定期检查停止标记文件(用于 Windows 等无法发送信号的场景)
107
- const stopCheckInterval = setInterval(() => {
108
- if (checkStopSignal()) {
109
- clearInterval(stopCheckInterval);
107
+ process.on("SIGINT", () => shutdown().catch(() => process.exit(1)));
108
+ process.on("SIGTERM", () => shutdown().catch(() => process.exit(1)));
109
+ // 优雅关闭 HTTP 服务:stop 命令通过此端口触发 shutdown(Windows 下 SIGTERM 不可靠)
110
+ const shutdownServer = createServer((req, res) => {
111
+ if (req.url === "/shutdown" || req.url === "/") {
112
+ res.writeHead(200, { "Content-Type": "text/plain" });
113
+ res.end("ok");
110
114
  shutdown().catch(() => process.exit(1));
111
115
  }
112
- }, 1000);
116
+ else {
117
+ res.writeHead(404);
118
+ res.end();
119
+ }
120
+ });
121
+ shutdownServer.listen(SHUTDOWN_PORT, "127.0.0.1", () => {
122
+ const portFile = join(APP_HOME, "open-im.port");
123
+ const dir = dirname(portFile);
124
+ if (!existsSync(dir))
125
+ mkdirSync(dir, { recursive: true });
126
+ writeFileSync(portFile, String(SHUTDOWN_PORT), "utf-8");
127
+ });
113
128
  }
114
- const isEntry = process.argv[1]?.replace(/\\/g, '/').endsWith('/index.js') || process.argv[1]?.replace(/\\/g, '/').endsWith('/index.ts');
129
+ const isEntry = process.argv[1]?.replace(/\\/g, "/").endsWith("/index.js") ||
130
+ process.argv[1]?.replace(/\\/g, "/").endsWith("/index.ts");
115
131
  if (isEntry) {
116
132
  main().catch((err) => {
117
- console.error('Fatal error:', err);
133
+ console.error("Fatal error:", err);
118
134
  closeLogger();
119
135
  process.exit(1);
120
136
  });
package/dist/setup.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * 首次运行时的交互式配置引导
3
3
  * 使用 prompts 库,兼容 tsx watch、IDE 终端等环境
4
+ * Telegram Token 使用 readline 避免 Windows 终端 prompts 重绘问题
4
5
  */
5
6
  export declare function runInteractiveSetup(): Promise<boolean>;
package/dist/setup.js CHANGED
@@ -1,104 +1,202 @@
1
1
  /**
2
2
  * 首次运行时的交互式配置引导
3
3
  * 使用 prompts 库,兼容 tsx watch、IDE 终端等环境
4
+ * Telegram Token 使用 readline 避免 Windows 终端 prompts 重绘问题
4
5
  */
5
- import prompts from 'prompts';
6
- import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
7
- import { join, dirname } from 'node:path';
8
- import { APP_HOME } from './constants.js';
6
+ import prompts from "prompts";
7
+ import { createInterface } from "node:readline";
8
+ import { mkdirSync, writeFileSync, existsSync } from "node:fs";
9
+ import { join, dirname } from "node:path";
10
+ import { APP_HOME } from "./constants.js";
11
+ function question(prompt) {
12
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
13
+ return new Promise((resolve) => {
14
+ rl.question(prompt, (answer) => {
15
+ rl.close();
16
+ resolve(answer.trim());
17
+ });
18
+ });
19
+ }
9
20
  function printManualInstructions(configPath) {
10
- console.log('\n━━━ open-im 首次配置 ━━━\n');
11
- console.log('当前环境不支持交互输入,请手动创建配置文件:');
12
- console.log('');
13
- console.log(' 1. 创建目录:', dirname(configPath));
14
- console.log(' 2. 创建文件:', configPath);
15
- console.log(' 3. 填入以下内容(替换为你的 Token 和用户 ID):');
16
- console.log('');
21
+ console.log("\n━━━ open-im 首次配置 ━━━\n");
22
+ console.log("当前环境不支持交互输入,请手动创建配置文件:");
23
+ console.log("");
24
+ console.log(" 1. 创建目录:", dirname(configPath));
25
+ console.log(" 2. 创建文件:", configPath);
26
+ console.log(" 3. 填入以下内容(替换为你的 Token/App ID 和用户 ID):");
27
+ console.log("");
17
28
  console.log(`{
18
- "telegramBotToken": "你的Bot Token",
19
- "allowedUserIds": ["你的Telegram用户ID"],
20
- "claudeWorkDir": "${process.cwd().replace(/\\/g, '/')}",
29
+ "platforms": {
30
+ "telegram": {
31
+ "enabled": true,
32
+ "botToken": "你的 Telegram Bot Token(可选)",
33
+ "allowedUserIds": ["允许访问的 Telegram 用户 ID(可选)"]
34
+ },
35
+ "feishu": {
36
+ "enabled": false,
37
+ "appId": "你的飞书 App ID(可选)",
38
+ "appSecret": "你的飞书 App Secret(可选)",
39
+ "allowedUserIds": ["允许访问的飞书用户 ID(可选)"]
40
+ }
41
+ },
42
+ "claudeWorkDir": "${process.cwd().replace(/\\/g, "/")}",
21
43
  "claudeSkipPermissions": true,
22
44
  "aiCommand": "claude"
23
45
  }`);
24
- console.log('');
25
- console.log('或设置环境变量: TELEGRAM_BOT_TOKEN=xxx 后再运行');
26
- console.log('');
46
+ console.log("");
47
+ console.log("提示:至少需要配置 Telegram 或 Feishu 其中一个平台");
48
+ console.log("或设置环境变量: TELEGRAM_BOT_TOKEN=xxx 或 FEISHU_APP_ID=xxx 后再运行");
49
+ console.log("");
27
50
  }
28
51
  export async function runInteractiveSetup() {
29
- const configPath = join(APP_HOME, 'config.json');
30
- const forceManual = process.argv.includes('--manual') || process.argv.includes('-m');
52
+ const configPath = join(APP_HOME, "config.json");
53
+ const forceManual = process.argv.includes("--manual") || process.argv.includes("-m");
31
54
  if (forceManual || !process.stdin.isTTY) {
32
55
  printManualInstructions(configPath);
33
56
  return false;
34
57
  }
35
- console.log('\n━━━ open-im 首次配置 ━━━\n');
36
- console.log('配置将保存到:', configPath);
37
- console.log('');
58
+ console.log("\n━━━ open-im 首次配置 ━━━\n");
59
+ console.log("配置将保存到:", configPath);
60
+ console.log("");
38
61
  const onCancel = () => {
39
- console.log('\n已取消配置。');
62
+ console.log("\n已取消配置。");
40
63
  process.exit(0);
41
64
  };
42
- const response = await prompts([
43
- {
44
- type: 'text',
45
- name: 'telegramBotToken',
46
- message: 'Telegram Bot Token(必填,从 @BotFather 获取)',
47
- validate: (v) => (v.trim() ? true : 'Token 不能为空'),
48
- },
65
+ // 第一步:选择平台
66
+ const platformResp = await prompts({
67
+ type: "select",
68
+ name: "platform",
69
+ message: "选择要配置的平台(↑↓ 选择)",
70
+ choices: [
71
+ { title: "Telegram - 需要 Bot Token", value: "telegram" },
72
+ {
73
+ title: "飞书 (Feishu/Lark) - 需要 App ID 和 App Secret",
74
+ value: "feishu",
75
+ },
76
+ { title: "两者都配置", value: "both" },
77
+ ],
78
+ initial: 0,
79
+ }, { onCancel });
80
+ if (!platformResp.platform) {
81
+ return false;
82
+ }
83
+ const platform = platformResp.platform;
84
+ const config = { platforms: {} };
85
+ // 收集平台配置(Telegram 用 readline 避免 Windows 下 prompts 重绘/重复行问题)
86
+ if (platform === "telegram" || platform === "both") {
87
+ const token = await question("Telegram Bot Token(从 @BotFather 获取): ");
88
+ if (token) {
89
+ config.telegramBotToken = token;
90
+ }
91
+ else if (platform === "telegram") {
92
+ console.log("Token 不能为空");
93
+ return false;
94
+ }
95
+ }
96
+ if (platform === "feishu" || platform === "both") {
97
+ const feishuResp = await prompts([
98
+ {
99
+ type: "text",
100
+ name: "appId",
101
+ message: "飞书 App ID(从飞书开放平台获取)",
102
+ validate: (v) => (v.trim() ? true : "App ID 不能为空"),
103
+ },
104
+ {
105
+ type: "text",
106
+ name: "appSecret",
107
+ message: "飞书 App Secret(从飞书开放平台获取)",
108
+ validate: (v) => (v.trim() ? true : "App Secret 不能为空"),
109
+ },
110
+ ], { onCancel });
111
+ if (feishuResp.appId && feishuResp.appSecret) {
112
+ config.platforms.feishu = {
113
+ ...config.platforms.feishu,
114
+ enabled: true,
115
+ appId: feishuResp.appId.trim(),
116
+ appSecret: feishuResp.appSecret.trim(),
117
+ };
118
+ }
119
+ else if (platform === "feishu") {
120
+ return false;
121
+ }
122
+ }
123
+ // 通用配置
124
+ const commonResp = await prompts([
49
125
  {
50
- type: 'text',
51
- name: 'allowedUserIds',
52
- message: '白名单用户 ID(可选,逗号分隔,留空=所有人可访问)',
53
- initial: '',
126
+ type: "text",
127
+ name: "telegramAllowedUserIds",
128
+ message: "Telegram 白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
129
+ initial: "",
54
130
  },
55
131
  {
56
- type: 'text',
57
- name: 'proxy',
58
- message: '代理地址(可选,用于访问 Telegram,如: http://127.0.0.1:7890 或 socks5://127.0.0.1:1080)',
59
- initial: '',
132
+ type: "text",
133
+ name: "feishuAllowedUserIds",
134
+ message: "飞书白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
135
+ initial: "",
60
136
  },
61
137
  {
62
- type: 'select',
63
- name: 'aiCommand',
64
- message: 'AI 工具(↑↓ 选择)',
138
+ type: "select",
139
+ name: "aiCommand",
140
+ message: "AI 工具(↑↓ 选择)",
65
141
  choices: [
66
- { title: 'claude-code', value: 'claude' },
67
- { title: 'codex', value: 'codex' },
68
- { title: 'cursor', value: 'cursor' },
142
+ { title: "claude-code", value: "claude" },
143
+ { title: "codex", value: "codex" },
144
+ { title: "cursor", value: "cursor" },
69
145
  ],
70
146
  initial: 0,
71
147
  },
72
148
  {
73
- type: 'text',
74
- name: 'workDir',
75
- message: '工作目录',
149
+ type: "text",
150
+ name: "workDir",
151
+ message: "工作目录",
76
152
  initial: process.cwd(),
77
153
  },
78
154
  ], { onCancel });
79
- if (!response.telegramBotToken) {
80
- console.log('\n未输入 Token,取消配置。');
81
- return false;
155
+ const parseIds = (value) => value
156
+ ? value
157
+ .split(",")
158
+ .map((s) => s.trim())
159
+ .filter(Boolean)
160
+ : [];
161
+ // 分平台白名单
162
+ const telegramIds = parseIds(commonResp.telegramAllowedUserIds);
163
+ const feishuIds = parseIds(commonResp.feishuAllowedUserIds);
164
+ if (platform === "telegram" || platform === "both") {
165
+ config.platforms.telegram = {
166
+ ...config.platforms.telegram,
167
+ enabled: true,
168
+ botToken: config.telegramBotToken ?? undefined,
169
+ allowedUserIds: telegramIds,
170
+ };
82
171
  }
83
- const config = {
84
- telegramBotToken: response.telegramBotToken.trim(),
85
- allowedUserIds: response.allowedUserIds
86
- ? response.allowedUserIds
87
- .split(',')
88
- .map((s) => s.trim())
89
- .filter(Boolean)
90
- : [],
91
- proxy: response.proxy ? response.proxy.trim() : undefined,
92
- claudeWorkDir: (response.workDir || process.cwd()).trim(),
93
- claudeSkipPermissions: true,
94
- aiCommand: response.aiCommand ?? 'claude',
95
- };
172
+ else {
173
+ config.platforms.telegram = {
174
+ enabled: false,
175
+ allowedUserIds: telegramIds,
176
+ };
177
+ }
178
+ if (platform === "feishu" || platform === "both") {
179
+ config.platforms.feishu = {
180
+ ...config.platforms.feishu,
181
+ enabled: true,
182
+ allowedUserIds: feishuIds,
183
+ };
184
+ }
185
+ else {
186
+ config.platforms.feishu = {
187
+ enabled: false,
188
+ allowedUserIds: feishuIds,
189
+ };
190
+ }
191
+ config.claudeWorkDir = (commonResp.workDir || process.cwd()).trim();
192
+ config.claudeSkipPermissions = true;
193
+ config.aiCommand = commonResp.aiCommand ?? "claude";
96
194
  const dir = dirname(configPath);
97
195
  if (!existsSync(dir)) {
98
196
  mkdirSync(dir, { recursive: true });
99
197
  }
100
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
101
- console.log('\n✅ 配置已保存到', configPath);
102
- console.log('');
198
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
199
+ console.log("\n✅ 配置已保存到", configPath);
200
+ console.log("");
103
201
  return true;
104
202
  }
@@ -1,5 +1,5 @@
1
- import { Telegraf } from 'telegraf';
2
- import type { Config } from '../config.js';
1
+ import { Telegraf } from "telegraf";
2
+ import type { Config } from "../config.js";
3
3
  export declare function getBot(): Telegraf;
4
4
  export declare function getBotUsername(): string | undefined;
5
5
  export declare function initTelegram(config: Config, setupHandlers: (bot: Telegraf) => void): Promise<void>;
@@ -1,42 +1,31 @@
1
- import { Telegraf } from 'telegraf';
2
- import { createLogger } from '../logger.js';
3
- import { HttpsProxyAgent } from 'https-proxy-agent';
4
- const log = createLogger('Telegram');
1
+ import { Telegraf } from "telegraf";
2
+ import { createLogger } from "../logger.js";
3
+ const log = createLogger("Telegram");
5
4
  let bot;
6
5
  let botUsername;
7
6
  export function getBot() {
8
7
  if (!bot)
9
- throw new Error('Telegram bot not initialized');
8
+ throw new Error("Telegram bot not initialized");
10
9
  return bot;
11
10
  }
12
11
  export function getBotUsername() {
13
12
  return botUsername;
14
13
  }
15
14
  export async function initTelegram(config, setupHandlers) {
16
- const telegrafOptions = {};
17
- // 配置代理
18
- if (config.proxy) {
19
- try {
20
- const agent = new HttpsProxyAgent(config.proxy);
21
- telegrafOptions.telegram = {
22
- agent,
23
- };
24
- log.info(`Using proxy: ${config.proxy}`);
25
- }
26
- catch (err) {
27
- log.warn(`Failed to create proxy agent: ${err}. Continuing without proxy.`);
28
- }
15
+ const token = config.telegramBotToken ?? "";
16
+ if (!token) {
17
+ throw new Error("Telegram bot token is required");
29
18
  }
30
- bot = new Telegraf(config.telegramBotToken, telegrafOptions);
19
+ bot = new Telegraf(token);
31
20
  setupHandlers(bot);
32
21
  const me = (await bot.telegram.getMe());
33
22
  botUsername = me.username;
34
23
  bot.launch().catch((err) => {
35
- log.error('Telegram polling error:', err);
24
+ log.error("Telegram polling error:", err);
36
25
  process.exit(1);
37
26
  });
38
- log.info('Telegram bot launched');
27
+ log.info("Telegram bot launched");
39
28
  }
40
29
  export function stopTelegram() {
41
- bot?.stop('SIGTERM');
30
+ bot?.stop("SIGTERM");
42
31
  }
@@ -1,6 +1,6 @@
1
- import type { Telegraf } from 'telegraf';
2
- import type { Config } from '../config.js';
3
- import type { SessionManager } from '../session/session-manager.js';
1
+ import type { Telegraf } from "telegraf";
2
+ import type { Config } from "../config.js";
3
+ import type { SessionManager } from "../session/session-manager.js";
4
4
  export interface TelegramEventHandlerHandle {
5
5
  stop: () => void;
6
6
  getRunningTaskCount: () => number;