@wu529778790/open-im 1.0.3 → 1.1.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 CHANGED
@@ -1,10 +1,10 @@
1
1
  # open-im
2
2
 
3
- 多平台 IM 桥接,将 Telegram、飞书 (Feishu/Lark) 和微信连接到 AI CLI 工具(Claude Code、Codex、Cursor),实现移动端/远程访问 AI 编程助手。
3
+ 多平台 IM 桥接,将 Telegram、飞书 (Feishu/Lark)、企业微信和微信连接到 AI CLI 工具(Claude Code、Codex、Cursor),实现移动端/远程访问 AI 编程助手。
4
4
 
5
5
  ## 功能特性
6
6
 
7
- - **多平台**:支持 Telegram、飞书和微信,可同时启用
7
+ - **多平台**:支持 Telegram、飞书、企业微信和微信,可同时启用
8
8
  - **多 AI 工具**:通过配置切换 Claude Code / Codex / Cursor
9
9
  - **流式输出**:节流更新,实时展示 AI 回复
10
10
  - **会话管理**:每用户独立 session,`/new` 重置会话
@@ -71,6 +71,9 @@ npm run dev # 直接运行源码(tsx,无需 build)
71
71
  | `WECHAT_APP_ID` | 微信应用 App ID(AGP 协议) |
72
72
  | `WECHAT_APP_SECRET` | 微信应用 App Secret |
73
73
  | `WECHAT_WS_URL` | AGP WebSocket URL(可选,默认使用官方服务) |
74
+ | `WEWORK_CORP_ID` | 企业微信机器人 ID(Bot ID) |
75
+ | `WEWORK_SECRET` | 企业微信机器人 Secret |
76
+ | `WEWORK_WS_URL` | 企业微信 WebSocket URL(可选,默认官方) |
74
77
  | `ALLOWED_USER_IDS` | 白名单用户 ID(逗号分隔,空=所有人) |
75
78
  | `AI_COMMAND` | `claude` \| `codex` \| `cursor`,默认 `claude` |
76
79
  | `CLAUDE_CLI_PATH` | Claude CLI 路径,默认 `claude` |
@@ -86,10 +89,11 @@ npm run dev # 直接运行源码(tsx,无需 build)
86
89
 
87
90
  配置优先级:环境变量 > `~/.open-im/config.json` > 默认值。
88
91
 
89
- 至少需配置 **Telegram**、**飞书** 或 **微信** 其中一个:
92
+ 至少需配置 **Telegram**、**飞书**、**企业微信** 或 **微信** 其中一个:
90
93
 
91
94
  - **Telegram**:`TELEGRAM_BOT_TOKEN` 或 `telegramBotToken`
92
95
  - **飞书**:`FEISHU_APP_ID` + `FEISHU_APP_SECRET` 或 `feishuAppId` + `feishuAppSecret`
96
+ - **企业微信**:`WEWORK_CORP_ID` + `WEWORK_SECRET` 或 `platforms.wework.corpId` + `platforms.wework.secret`
93
97
  - **微信**:`WECHAT_APP_ID` + `WECHAT_APP_SECRET` 或 `wechatAppId` + `wechatAppSecret`
94
98
 
95
99
  ### 飞书配置说明
@@ -107,6 +111,28 @@ npm run dev # 直接运行源码(tsx,无需 build)
107
111
 
108
112
  **若点击 /mode 卡片按钮报错**:说明未配置卡片回调。配置较复杂时,可直接用 `/mode ask`、`/mode yolo` 等命令切换模式,无需卡片。
109
113
 
114
+ ### 企业微信配置说明
115
+
116
+ 1. 在 [企业微信管理后台](https://work.weixin.qq.com/) 创建企业自建应用
117
+ 2. 进入「应用管理」→ 选择你的应用 → 获取 **AgentId** 和 **Secret**
118
+ 3. 开启「智能机器人」能力,获取 **机器人 ID(Bot ID)** 和 **机器人 Secret**
119
+ 4. 配置到 `~/.open-im/config.json`:
120
+ ```json
121
+ {
122
+ "platforms": {
123
+ "wework": {
124
+ "enabled": true,
125
+ "corpId": "你的机器人ID",
126
+ "secret": "你的机器人Secret",
127
+ "allowedUserIds": []
128
+ }
129
+ }
130
+ }
131
+ ```
132
+ 5. 将机器人添加到目标群聊或发起私聊
133
+
134
+ **说明**:企业微信使用 WebSocket 长连接(`wss://openws.work.weixin.qq.com`),连接建立后会自动订阅,支持接收消息、回复消息和主动推送(如启动/关闭通知)。首次启动时,需用户先发一条消息,机器人才能向其推送启动通知。
135
+
110
136
  ## IM 内命令
111
137
 
112
138
  | 命令 | 说明 |
@@ -165,6 +191,12 @@ npm run dev # 直接运行源码(tsx,无需 build)
165
191
  "enabled": true,
166
192
  "botToken": "你的Bot Token",
167
193
  "allowedUserIds": ["你的Telegram用户ID"]
194
+ },
195
+ "wework": {
196
+ "enabled": true,
197
+ "corpId": "你的企业微信机器人ID",
198
+ "secret": "你的企业微信机器人Secret",
199
+ "allowedUserIds": []
168
200
  }
169
201
  },
170
202
  "claudeWorkDir": "$(pwd)",
@@ -247,3 +279,27 @@ open-im init
247
279
  4. 添加 **「卡片回传交互」**(`card.action.trigger`)— 若搜不到,可尝试搜「action」「trigger」或浏览分类
248
280
 
249
281
  **更简单**:直接用 `/mode ask`、`/mode yolo` 等命令切换模式,无需配置卡片。
282
+
283
+ ### Q: 企业微信 846609(aibot websocket not subscribed)?
284
+
285
+ 说明在订阅确认完成前就发送了主动消息。当前版本已修复:连接建立后会等待服务端订阅确认(`errcode: 0`)后再发送启动通知。若仍出现,请检查网络或重启服务。
286
+
287
+ ### Q: 企业微信收不到启动通知?
288
+
289
+ 启动通知需要用户先发过消息,系统才能获取到 chatId。请先向机器人发送任意消息(如「你好」),之后重启服务即可收到启动/关闭通知。
290
+
291
+ ### Q: 微信连接失败(错误 1006 或 500)?
292
+
293
+ 微信使用 AGP 协议连接,该协议服务器由第三方提供。如果出现连接失败,可能原因:
294
+
295
+ 1. **AGP 服务器限制**
296
+ - AGP 服务器使用了 Qclaw 通道,可能有白名单限制
297
+ - 独立客户端可能不在允许列表中
298
+ - token 或 guid 无效或已过期
299
+
300
+ 2. **建议**
301
+ - 确认 token 和 guid 是否正确
302
+ - 尝试更新 token/guid(如果提供商支持)
303
+ - 或暂时使用其他平台(Telegram/飞书/企业微信)
304
+
305
+ **注意**:这是 AGP 协议服务器的限制,非本项目的 bug。如果 AGP 服务器调整策略,微信功能可能恢复正常。
@@ -21,7 +21,7 @@ export type ClaudeRequestHandler = (userId: string, chatId: string, prompt: stri
21
21
  export declare class CommandHandler {
22
22
  private deps;
23
23
  constructor(deps: CommandHandlerDeps);
24
- dispatch(text: string, chatId: string, userId: string, platform: 'feishu' | 'telegram' | 'wechat', handleClaudeRequest: ClaudeRequestHandler): Promise<boolean>;
24
+ dispatch(text: string, chatId: string, userId: string, platform: 'feishu' | 'telegram' | 'wechat' | 'wework', handleClaudeRequest: ClaudeRequestHandler): Promise<boolean>;
25
25
  private handleMode;
26
26
  private getClearHistoryHint;
27
27
  private handleHelp;
package/dist/config.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { LogLevel } from './logger.js';
2
- export type Platform = 'feishu' | 'telegram' | 'wechat';
2
+ export type Platform = 'feishu' | 'telegram' | 'wechat' | 'wework';
3
3
  export type AiCommand = 'claude' | 'codex' | 'cursor';
4
4
  export interface Config {
5
5
  enabledPlatforms: Platform[];
@@ -8,11 +8,20 @@ export interface Config {
8
8
  feishuAppSecret?: string;
9
9
  wechatAppId?: string;
10
10
  wechatAppSecret?: string;
11
+ wechatToken?: string;
12
+ wechatJwtToken?: string;
13
+ wechatLoginKey?: string;
14
+ wechatGuid?: string;
15
+ wechatUserId?: string;
11
16
  wechatWsUrl?: string;
17
+ weworkCorpId?: string;
18
+ weworkSecret?: string;
19
+ weworkWsUrl?: string;
12
20
  allowedUserIds: string[];
13
21
  telegramAllowedUserIds: string[];
14
22
  feishuAllowedUserIds: string[];
15
23
  wechatAllowedUserIds: string[];
24
+ weworkAllowedUserIds: string[];
16
25
  aiCommand: AiCommand;
17
26
  claudeCliPath: string;
18
27
  claudeWorkDir: string;
@@ -37,6 +46,15 @@ export interface Config {
37
46
  wechat?: {
38
47
  enabled: boolean;
39
48
  wsUrl?: string;
49
+ token?: string;
50
+ jwtToken?: string;
51
+ loginKey?: string;
52
+ guid?: string;
53
+ userId?: string;
54
+ allowedUserIds: string[];
55
+ };
56
+ wework?: {
57
+ enabled: boolean;
40
58
  allowedUserIds: string[];
41
59
  };
42
60
  };
package/dist/config.js CHANGED
@@ -26,14 +26,22 @@ export function needsSetup() {
26
26
  return false;
27
27
  if (process.env.WECHAT_APP_ID && process.env.WECHAT_APP_SECRET)
28
28
  return false;
29
+ if (process.env.WECHAT_TOKEN && process.env.WECHAT_GUID && process.env.WECHAT_USER_ID)
30
+ return false;
31
+ if (process.env.WEWORK_CORP_ID && process.env.WEWORK_SECRET)
32
+ return false;
29
33
  const file = loadFileConfig();
30
34
  const tg = file.platforms?.telegram;
31
35
  const fs = file.platforms?.feishu;
32
36
  const wc = file.platforms?.wechat;
37
+ const ww = file.platforms?.wework;
33
38
  const hasTelegram = !!tg?.botToken;
34
39
  const hasFeishu = !!(fs?.appId && fs?.appSecret);
35
- const hasWechat = !!(wc?.appId && wc?.appSecret);
36
- return !hasTelegram && !hasFeishu && !hasWechat;
40
+ // 微信支持 AGP 协议(token + guid + userId)或标准协议(appId + appSecret
41
+ const hasWechat = !!(wc?.token && wc?.guid && wc?.userId) || !!(wc?.appId && wc?.appSecret);
42
+ // 企业微信只需要 corpId 和 secret
43
+ const hasWework = !!(ww?.corpId && ww?.secret);
44
+ return !hasTelegram && !hasFeishu && !hasWechat && !hasWework;
37
45
  }
38
46
  function parseCommaSeparated(value) {
39
47
  return value.split(',').map((s) => s.trim()).filter(Boolean);
@@ -43,6 +51,7 @@ export function loadConfig() {
43
51
  const fileTelegram = file.platforms?.telegram;
44
52
  const fileFeishu = file.platforms?.feishu;
45
53
  const fileWechat = file.platforms?.wechat;
54
+ const fileWework = file.platforms?.wework;
46
55
  // 1. 加载各平台凭证(env 优先,其次新结构,最后旧字段)
47
56
  const telegramBotToken = process.env.TELEGRAM_BOT_TOKEN ??
48
57
  fileTelegram?.botToken ??
@@ -53,28 +62,53 @@ export function loadConfig() {
53
62
  const feishuAppSecret = process.env.FEISHU_APP_SECRET ??
54
63
  fileFeishu?.appSecret ??
55
64
  file.feishuAppSecret;
65
+ // 微信支持两种协议:
66
+ // 1. AGP 协议:token + guid + userId(推荐)
67
+ // 2. 标准协议:appId + appSecret
68
+ const wechatToken = process.env.WECHAT_TOKEN ??
69
+ fileWechat?.token;
70
+ const wechatJwtToken = fileWechat?.jwtToken;
71
+ const wechatLoginKey = fileWechat?.loginKey;
72
+ const wechatGuid = process.env.WECHAT_GUID ??
73
+ fileWechat?.guid;
74
+ const wechatUserId = process.env.WECHAT_USER_ID ??
75
+ fileWechat?.userId;
56
76
  const wechatAppId = process.env.WECHAT_APP_ID ??
57
77
  fileWechat?.appId;
58
78
  const wechatAppSecret = process.env.WECHAT_APP_SECRET ??
59
79
  fileWechat?.appSecret;
60
80
  const wechatWsUrl = process.env.WECHAT_WS_URL ??
61
81
  fileWechat?.wsUrl;
82
+ const weworkCorpId = process.env.WEWORK_CORP_ID ??
83
+ fileWework?.corpId;
84
+ const weworkSecret = process.env.WEWORK_SECRET ??
85
+ fileWework?.secret;
86
+ const weworkWsUrl = process.env.WEWORK_WS_URL ??
87
+ fileWework?.wsUrl;
62
88
  // 2. 计算启用平台
63
89
  const enabledPlatforms = [];
64
90
  const telegramEnabledFlag = fileTelegram?.enabled;
65
91
  const feishuEnabledFlag = fileFeishu?.enabled;
66
92
  const wechatEnabledFlag = fileWechat?.enabled;
93
+ const weworkEnabledFlag = fileWework?.enabled;
67
94
  const telegramEnabled = !!telegramBotToken && (telegramEnabledFlag !== false);
68
95
  const feishuEnabled = !!(feishuAppId && feishuAppSecret) && (feishuEnabledFlag !== false);
69
- const wechatEnabled = !!(wechatAppId && wechatAppSecret) && (wechatEnabledFlag !== false);
96
+ // 微信启用条件:AGP 协议凭证 标准协议凭证
97
+ const hasWechatAGPCreds = !!(wechatToken && wechatGuid && wechatUserId);
98
+ const hasWechatStandardCreds = !!(wechatAppId && wechatAppSecret);
99
+ const wechatEnabled = (hasWechatAGPCreds || hasWechatStandardCreds) && (wechatEnabledFlag !== false);
100
+ // 企业微信只需要 corpId (botId) 和 secret
101
+ const weworkEnabled = !!(weworkCorpId && weworkSecret) && (weworkEnabledFlag !== false);
70
102
  if (telegramEnabled)
71
103
  enabledPlatforms.push('telegram');
72
104
  if (feishuEnabled)
73
105
  enabledPlatforms.push('feishu');
74
106
  if (wechatEnabled)
75
107
  enabledPlatforms.push('wechat');
108
+ if (weworkEnabled)
109
+ enabledPlatforms.push('wework');
76
110
  if (enabledPlatforms.length === 0) {
77
- throw new Error('至少需要配置 Telegram、Feishu 或 WeChat 其中一个平台(可以通过环境变量或 config.json)');
111
+ throw new Error('至少需要配置 Telegram、Feishu、WeChatWeWork 其中一个平台(可以通过环境变量或 config.json)');
78
112
  }
79
113
  // 3. 全局白名单(旧字段,向后兼容,主要用于作为 per-platform 的兜底)
80
114
  const allowedUserIds = process.env.ALLOWED_USER_IDS !== undefined
@@ -90,6 +124,9 @@ export function loadConfig() {
90
124
  const wechatAllowedUserIds = process.env.WECHAT_ALLOWED_USER_IDS !== undefined
91
125
  ? parseCommaSeparated(process.env.WECHAT_ALLOWED_USER_IDS)
92
126
  : fileWechat?.allowedUserIds ?? allowedUserIds;
127
+ const weworkAllowedUserIds = process.env.WEWORK_ALLOWED_USER_IDS !== undefined
128
+ ? parseCommaSeparated(process.env.WEWORK_ALLOWED_USER_IDS)
129
+ : fileWework?.allowedUserIds ?? allowedUserIds;
93
130
  // 5. AI / 工作目录 / 安全配置
94
131
  const aiCommand = (process.env.AI_COMMAND ?? file.aiCommand ?? 'claude');
95
132
  const claudeCliPath = process.env.CLAUDE_CLI_PATH ?? file.claudeCliPath ?? 'claude';
@@ -176,13 +213,32 @@ export function loadConfig() {
176
213
  ? {
177
214
  enabled: true,
178
215
  wsUrl: wechatWsUrl,
216
+ token: wechatToken,
217
+ jwtToken: wechatJwtToken,
218
+ loginKey: wechatLoginKey,
219
+ guid: wechatGuid,
220
+ userId: wechatUserId,
179
221
  allowedUserIds: wechatAllowedUserIds,
180
222
  }
181
223
  : {
182
224
  enabled: false,
183
225
  wsUrl: wechatWsUrl,
226
+ token: wechatToken,
227
+ jwtToken: wechatJwtToken,
228
+ loginKey: wechatLoginKey,
229
+ guid: wechatGuid,
230
+ userId: wechatUserId,
184
231
  allowedUserIds: wechatAllowedUserIds,
185
232
  },
233
+ wework: weworkEnabled
234
+ ? {
235
+ enabled: true,
236
+ allowedUserIds: weworkAllowedUserIds,
237
+ }
238
+ : {
239
+ enabled: false,
240
+ allowedUserIds: weworkAllowedUserIds,
241
+ },
186
242
  };
187
243
  return {
188
244
  enabledPlatforms,
@@ -191,11 +247,20 @@ export function loadConfig() {
191
247
  feishuAppSecret: feishuAppSecret ?? '',
192
248
  wechatAppId: wechatAppId ?? '',
193
249
  wechatAppSecret: wechatAppSecret ?? '',
250
+ wechatToken: wechatToken,
251
+ wechatJwtToken: wechatJwtToken,
252
+ wechatLoginKey: wechatLoginKey,
253
+ wechatGuid: wechatGuid,
254
+ wechatUserId: wechatUserId,
194
255
  wechatWsUrl: wechatWsUrl,
256
+ weworkCorpId: weworkCorpId ?? '',
257
+ weworkSecret: weworkSecret ?? '',
258
+ weworkWsUrl: weworkWsUrl,
195
259
  allowedUserIds,
196
260
  telegramAllowedUserIds,
197
261
  feishuAllowedUserIds,
198
262
  wechatAllowedUserIds,
263
+ weworkAllowedUserIds,
199
264
  aiCommand,
200
265
  claudeCliPath,
201
266
  claudeWorkDir,
@@ -11,6 +11,8 @@ export declare const FEISHU_THROTTLE_MS = 200;
11
11
  export declare const TELEGRAM_THROTTLE_MS = 200;
12
12
  /** WeChat 流式更新节流:1000ms(AGP 协议建议值) */
13
13
  export declare const WECHAT_THROTTLE_MS = 1000;
14
+ export declare const WEWORK_THROTTLE_MS = 500;
14
15
  export declare const MAX_TELEGRAM_MESSAGE_LENGTH = 4000;
15
16
  export declare const MAX_FEISHU_MESSAGE_LENGTH = 4000;
16
17
  export declare const MAX_WECHAT_MESSAGE_LENGTH = 2048;
18
+ export declare const MAX_WEWORK_MESSAGE_LENGTH = 2048;
package/dist/constants.js CHANGED
@@ -40,6 +40,8 @@ export const FEISHU_THROTTLE_MS = 200;
40
40
  export const TELEGRAM_THROTTLE_MS = 200;
41
41
  /** WeChat 流式更新节流:1000ms(AGP 协议建议值) */
42
42
  export const WECHAT_THROTTLE_MS = 1000;
43
+ export const WEWORK_THROTTLE_MS = 500;
43
44
  export const MAX_TELEGRAM_MESSAGE_LENGTH = 4000;
44
45
  export const MAX_FEISHU_MESSAGE_LENGTH = 4000;
45
46
  export const MAX_WECHAT_MESSAGE_LENGTH = 2048;
47
+ export const MAX_WEWORK_MESSAGE_LENGTH = 2048;
package/dist/index.js CHANGED
@@ -14,6 +14,9 @@ import { sendTextReply as sendFeishuTextReply } from "./feishu/message-sender.js
14
14
  import { initWeChat, stopWeChat } from "./wechat/client.js";
15
15
  import { setupWeChatHandlers } from "./wechat/event-handler.js";
16
16
  import { sendTextReply as sendWeChatTextReply } from "./wechat/message-sender.js";
17
+ import { initWeWork, stopWeWork } from "./wework/client.js";
18
+ import { setupWeWorkHandlers } from "./wework/event-handler.js";
19
+ import { sendProactiveTextReply as sendWeWorkTextReply } from "./wework/message-sender.js";
17
20
  import { initAdapters, cleanupAdapters } from "./adapters/registry.js";
18
21
  import { SessionManager } from "./session/session-manager.js";
19
22
  import { loadActiveChats, getActiveChatId, flushActiveChats, } from "./shared/active-chats.js";
@@ -29,6 +32,7 @@ async function sendLifecycleNotification(platform, message) {
29
32
  const telegramChatId = getActiveChatId("telegram");
30
33
  const feishuChatId = getActiveChatId("feishu");
31
34
  const wechatChatId = getActiveChatId("wechat");
35
+ const weworkChatId = getActiveChatId("wework");
32
36
  const sendPromises = [];
33
37
  if (platform === "telegram" && telegramChatId) {
34
38
  sendPromises.push(sendTelegramTextReply(telegramChatId, message).catch((err) => {
@@ -45,6 +49,11 @@ async function sendLifecycleNotification(platform, message) {
45
49
  log.debug("Failed to send WeChat notification:", err);
46
50
  }));
47
51
  }
52
+ if (platform === "wework" && weworkChatId) {
53
+ sendPromises.push(sendWeWorkTextReply(weworkChatId, message).catch((err) => {
54
+ log.debug("Failed to send WeWork notification:", err);
55
+ }));
56
+ }
48
57
  await Promise.all(sendPromises);
49
58
  }
50
59
  export async function main() {
@@ -72,30 +81,66 @@ export async function main() {
72
81
  let telegramHandle = null;
73
82
  let feishuHandle = null;
74
83
  let wechatHandle = null;
84
+ let weworkHandle = null;
85
+ // Track successfully initialized platforms
86
+ const successfulPlatforms = [];
75
87
  if (config.enabledPlatforms.includes("telegram")) {
76
- await initTelegram(config, (bot) => {
77
- telegramHandle = setupTelegramHandlers(bot, config, sessionManager);
78
- });
88
+ try {
89
+ await initTelegram(config, (bot) => {
90
+ telegramHandle = setupTelegramHandlers(bot, config, sessionManager);
91
+ });
92
+ successfulPlatforms.push("telegram");
93
+ }
94
+ catch (err) {
95
+ log.error("Failed to initialize Telegram:", err);
96
+ }
79
97
  }
80
98
  if (config.enabledPlatforms.includes("feishu")) {
81
- feishuHandle = setupFeishuHandlers(config, sessionManager);
82
- await initFeishu(config, feishuHandle.handleEvent);
99
+ try {
100
+ feishuHandle = setupFeishuHandlers(config, sessionManager);
101
+ await initFeishu(config, feishuHandle.handleEvent);
102
+ successfulPlatforms.push("feishu");
103
+ }
104
+ catch (err) {
105
+ log.error("Failed to initialize Feishu:", err);
106
+ }
83
107
  }
84
108
  if (config.enabledPlatforms.includes("wechat")) {
85
- wechatHandle = setupWeChatHandlers(config, sessionManager);
86
- await initWeChat(config, wechatHandle.handleEvent);
109
+ try {
110
+ wechatHandle = setupWeChatHandlers(config, sessionManager);
111
+ await initWeChat(config, wechatHandle.handleEvent);
112
+ successfulPlatforms.push("wechat");
113
+ }
114
+ catch (err) {
115
+ log.error("Failed to initialize WeChat:", err);
116
+ }
117
+ }
118
+ if (config.enabledPlatforms.includes("wework")) {
119
+ try {
120
+ weworkHandle = setupWeWorkHandlers(config, sessionManager);
121
+ await initWeWork(config, weworkHandle.handleEvent);
122
+ successfulPlatforms.push("wework");
123
+ }
124
+ catch (err) {
125
+ log.error("Failed to initialize WeWork:", err);
126
+ }
127
+ }
128
+ // Require at least one platform to start successfully
129
+ if (successfulPlatforms.length === 0) {
130
+ throw new Error("No platforms initialized successfully. Service cannot start.");
87
131
  }
88
132
  log.info("Service is running. Press Ctrl+C to stop.");
133
+ log.info(`Successfully initialized platforms: ${successfulPlatforms.join(", ")}`);
89
134
  const startupMsg = [
90
135
  `🟢 open-im v${APP_VERSION} 服务已启动`,
91
136
  "",
92
137
  `AI 工具: ${config.aiCommand}`,
93
138
  `工作目录: ${config.claudeWorkDir}`,
94
139
  `默认权限模式: ${defaultModeLabel} (${config.defaultPermissionMode})`,
95
- `启用平台: ${config.enabledPlatforms.join(", ")}`,
140
+ `成功启动平台: ${successfulPlatforms.join(", ")}`,
96
141
  ].join("\n");
97
- // Send notification to all enabled platforms
98
- for (const platform of config.enabledPlatforms) {
142
+ // Send notification only to successfully initialized platforms
143
+ for (const platform of successfulPlatforms) {
99
144
  await sendLifecycleNotification(platform, startupMsg).catch(() => { });
100
145
  }
101
146
  const startedAt = Date.now();
@@ -106,8 +151,8 @@ export async function main() {
106
151
  const uptimeSec = Math.floor((Date.now() - startedAt) / 1000);
107
152
  const m = Math.floor(uptimeSec / 60);
108
153
  const shutdownMsg = `🔴 open-im 服务正在关闭...\n运行时长: ${m}分钟`;
109
- // Send notification to all enabled platforms
110
- for (const platform of config.enabledPlatforms) {
154
+ // Send notification only to successfully initialized platforms
155
+ for (const platform of successfulPlatforms) {
111
156
  await sendLifecycleNotification(platform, shutdownMsg).catch(() => { });
112
157
  }
113
158
  shutdownServer?.close();
@@ -125,6 +170,8 @@ export async function main() {
125
170
  stopFeishu();
126
171
  wechatHandle?.stop();
127
172
  stopWeChat();
173
+ weworkHandle?.stop();
174
+ stopWeWork();
128
175
  stopPermissionServer();
129
176
  sessionManager.destroy();
130
177
  cleanupAdapters();