@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/README.md +117 -78
- package/dist/access/access-control.js +9 -2
- package/dist/claude/cli-runner.js +79 -28
- package/dist/cli.js +102 -183
- package/dist/config.d.ts +16 -2
- package/dist/config.js +70 -7
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +5 -0
- package/dist/feishu/client.d.ts +5 -0
- package/dist/feishu/client.js +69 -0
- package/dist/feishu/event-handler.d.ts +8 -0
- package/dist/feishu/event-handler.js +255 -0
- package/dist/feishu/message-sender.d.ts +7 -0
- package/dist/feishu/message-sender.js +253 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +85 -69
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +164 -66
- package/dist/telegram/client.d.ts +2 -2
- package/dist/telegram/client.js +11 -22
- package/dist/telegram/event-handler.d.ts +3 -3
- package/dist/telegram/event-handler.js +84 -71
- package/dist/telegram/message-sender.d.ts +1 -1
- package/dist/telegram/message-sender.js +72 -89
- package/package.json +3 -3
- package/.env.example +0 -16
package/dist/index.js
CHANGED
|
@@ -1,49 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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
|
|
6
|
-
import { setupTelegramHandlers } from
|
|
7
|
-
import { sendTextReply } from
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
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(
|
|
19
|
-
const log = createLogger(
|
|
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
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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(
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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(
|
|
105
|
-
process.on(
|
|
106
|
-
//
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
133
|
+
console.error("Fatal error:", err);
|
|
118
134
|
closeLogger();
|
|
119
135
|
process.exit(1);
|
|
120
136
|
});
|
package/dist/setup.d.ts
CHANGED
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
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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(
|
|
11
|
-
console.log(
|
|
12
|
-
console.log(
|
|
13
|
-
console.log(
|
|
14
|
-
console.log(
|
|
15
|
-
console.log(
|
|
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
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
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(
|
|
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,
|
|
30
|
-
const forceManual = process.argv.includes(
|
|
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(
|
|
36
|
-
console.log(
|
|
37
|
-
console.log(
|
|
58
|
+
console.log("\n━━━ open-im 首次配置 ━━━\n");
|
|
59
|
+
console.log("配置将保存到:", configPath);
|
|
60
|
+
console.log("");
|
|
38
61
|
const onCancel = () => {
|
|
39
|
-
console.log(
|
|
62
|
+
console.log("\n已取消配置。");
|
|
40
63
|
process.exit(0);
|
|
41
64
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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:
|
|
51
|
-
name:
|
|
52
|
-
message:
|
|
53
|
-
initial:
|
|
126
|
+
type: "text",
|
|
127
|
+
name: "telegramAllowedUserIds",
|
|
128
|
+
message: "Telegram 白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
|
|
129
|
+
initial: "",
|
|
54
130
|
},
|
|
55
131
|
{
|
|
56
|
-
type:
|
|
57
|
-
name:
|
|
58
|
-
message:
|
|
59
|
-
initial:
|
|
132
|
+
type: "text",
|
|
133
|
+
name: "feishuAllowedUserIds",
|
|
134
|
+
message: "飞书白名单用户 ID(可选,逗号分隔,留空=所有人可访问)",
|
|
135
|
+
initial: "",
|
|
60
136
|
},
|
|
61
137
|
{
|
|
62
|
-
type:
|
|
63
|
-
name:
|
|
64
|
-
message:
|
|
138
|
+
type: "select",
|
|
139
|
+
name: "aiCommand",
|
|
140
|
+
message: "AI 工具(↑↓ 选择)",
|
|
65
141
|
choices: [
|
|
66
|
-
{ title:
|
|
67
|
-
{ title:
|
|
68
|
-
{ title:
|
|
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:
|
|
74
|
-
name:
|
|
75
|
-
message:
|
|
149
|
+
type: "text",
|
|
150
|
+
name: "workDir",
|
|
151
|
+
message: "工作目录",
|
|
76
152
|
initial: process.cwd(),
|
|
77
153
|
},
|
|
78
154
|
], { onCancel });
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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),
|
|
101
|
-
console.log(
|
|
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
|
|
2
|
-
import type { Config } from
|
|
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>;
|
package/dist/telegram/client.js
CHANGED
|
@@ -1,42 +1,31 @@
|
|
|
1
|
-
import { Telegraf } from
|
|
2
|
-
import { createLogger } from
|
|
3
|
-
|
|
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(
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
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(
|
|
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(
|
|
24
|
+
log.error("Telegram polling error:", err);
|
|
36
25
|
process.exit(1);
|
|
37
26
|
});
|
|
38
|
-
log.info(
|
|
27
|
+
log.info("Telegram bot launched");
|
|
39
28
|
}
|
|
40
29
|
export function stopTelegram() {
|
|
41
|
-
bot?.stop(
|
|
30
|
+
bot?.stop("SIGTERM");
|
|
42
31
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Telegraf } from
|
|
2
|
-
import type { Config } from
|
|
3
|
-
import type { SessionManager } from
|
|
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;
|