@dingtalk-real-ai/dingtalk-connector 0.8.8 → 0.8.9
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/CHANGELOG.md +38 -0
- package/openclaw.plugin.json +2 -7
- package/package.json +1 -1
- package/src/channel.ts +25 -50
- package/src/config/schema.ts +8 -4
- package/src/core/connection.ts +25 -0
- package/src/core/message-handler.ts +465 -73
- package/src/reply-dispatcher.ts +11 -26
- package/src/sdk/types.ts +0 -2
- package/src/services/media/chunk-upload.ts +3 -2
- package/src/services/media/common.ts +2 -1
- package/src/services/media/image.ts +33 -27
- package/src/services/media.ts +3 -2
- package/src/services/messaging.ts +22 -2
- package/skills/dws/SKILL.md +0 -124
- package/skills/dws/references/error-codes.md +0 -93
- package/skills/dws/references/field-rules.md +0 -105
- package/skills/dws/references/global-reference.md +0 -36
- package/skills/dws/references/intent-guide.md +0 -179
- package/skills/dws/references/products/aiapp.md +0 -412
- package/skills/dws/references/products/aitable-record-ops.md +0 -135
- package/skills/dws/references/products/aitable.md +0 -511
- package/skills/dws/references/products/attendance.md +0 -93
- package/skills/dws/references/products/calendar.md +0 -217
- package/skills/dws/references/products/chat.md +0 -297
- package/skills/dws/references/products/contact.md +0 -108
- package/skills/dws/references/products/ding.md +0 -57
- package/skills/dws/references/products/doc.md +0 -371
- package/skills/dws/references/products/drive.md +0 -140
- package/skills/dws/references/products/mail.md +0 -109
- package/skills/dws/references/products/minutes.md +0 -204
- package/skills/dws/references/products/oa.md +0 -180
- package/skills/dws/references/products/report.md +0 -164
- package/skills/dws/references/products/simple.md +0 -110
- package/skills/dws/references/products/todo.md +0 -146
- package/skills/dws/references/products/workbench.md +0 -39
- package/skills/dws/references/url-patterns.md +0 -12
- package/skills/dws/scripts/aiapp_create_and_poll.py +0 -138
- package/skills/dws/scripts/attendance_my_record.py +0 -91
- package/skills/dws/scripts/attendance_team_shift.py +0 -89
- package/skills/dws/scripts/bot_broadcast.py +0 -112
- package/skills/dws/scripts/bulk_add_fields.py +0 -250
- package/skills/dws/scripts/calendar_free_slot_finder.py +0 -195
- package/skills/dws/scripts/calendar_schedule_meeting.py +0 -159
- package/skills/dws/scripts/calendar_today_agenda.py +0 -132
- package/skills/dws/scripts/chat_export_messages.py +0 -136
- package/skills/dws/scripts/chat_history_with_user.py +0 -142
- package/skills/dws/scripts/contact_dept_members.py +0 -110
- package/skills/dws/scripts/doc_create_and_write.py +0 -112
- package/skills/dws/scripts/drive_tree_list.py +0 -124
- package/skills/dws/scripts/finance_daily_cashflow.py +0 -70
- package/skills/dws/scripts/finance_expense_flow.py +0 -128
- package/skills/dws/scripts/import_records.py +0 -330
- package/skills/dws/scripts/mail_send_with_cc.py +0 -122
- package/skills/dws/scripts/mail_unread_summary.py +0 -114
- package/skills/dws/scripts/minutes_extract_todos.py +0 -110
- package/skills/dws/scripts/minutes_recent_summary.py +0 -114
- package/skills/dws/scripts/oa_batch_approve.py +0 -136
- package/skills/dws/scripts/oa_pending_review.py +0 -118
- package/skills/dws/scripts/report_inbox_today.py +0 -114
- package/skills/dws/scripts/todo_batch_create.py +0 -159
- package/skills/dws/scripts/todo_daily_summary.py +0 -169
- package/skills/dws/scripts/todo_overdue_check.py +0 -122
- package/skills/dws/scripts/upload_attachment.py +0 -190
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,44 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.8.9] - 2026-03-31
|
|
9
|
+
|
|
10
|
+
### 新增 / Added
|
|
11
|
+
- ✨ **引用消息完整解析** - 新增 `extractQuotedMsgText` 递归解析引用消息(最多 3 层嵌套),支持 text、richText、picture、video、audio、file、markdown、interactiveCard 等消息类型,自动提取引用中的媒体附件和链接
|
|
12
|
+
**Quoted message full parsing** - Added recursive quoted message parsing (up to 3 levels) with media attachment and URL extraction
|
|
13
|
+
|
|
14
|
+
- ✨ **新增配置项 asyncMode / ackText / endpoint / debug** - `configSchema` 新增四个配置字段
|
|
15
|
+
**New config options** - Added `asyncMode`, `ackText`, `endpoint`, `debug` to configSchema
|
|
16
|
+
|
|
17
|
+
- ✨ **普通消息本地图片后处理** - `sendNormalToUser` 和 `sendNormalToGroup` 新增本地图片上传后处理,发送普通消息时自动替换本地图片路径为 media_id
|
|
18
|
+
**Local image post-processing for normal messages** - Added automatic local image upload and replacement in `sendNormalToUser` and `sendNormalToGroup`
|
|
19
|
+
|
|
20
|
+
### 修复 / Fixes
|
|
21
|
+
- 🐛 **macOS LaunchAgent 环境 WebSocket 连接失败** - 修复 macOS LaunchAgent/daemon 环境下 fd 0/1/2 无效(EBADF)导致 TCP 连接创建失败的问题
|
|
22
|
+
**WebSocket connection failure on macOS LaunchAgent** - Fixed EBADF errors on macOS LaunchAgent environments by redirecting invalid file descriptors to `/dev/null`
|
|
23
|
+
|
|
24
|
+
- 🐛 **AI Card 流式关闭竞争条件** - 修复 `closeStreaming` 被 `onIdle` 和 `onError` 同时触发时的竞争条件,采用 snapshot 模式防止并发崩溃
|
|
25
|
+
**AI Card streaming close race condition** - Fixed race condition in `closeStreaming` using snapshot pattern to prevent concurrent crashes
|
|
26
|
+
|
|
27
|
+
- 🐛 **FormData CJS 互操作问题** - 将 `form-data` 从动态 import 改为静态 import,修复 jiti/ESM 环境下 `.default` 偶发为 undefined 的问题
|
|
28
|
+
**FormData CJS interop issue** - Changed `form-data` from dynamic to static import, fixing intermittent `.default` undefined errors in jiti/ESM
|
|
29
|
+
|
|
30
|
+
- 🐛 **纯文本图片路径误转换** - 禁用纯文本中本地图片路径自动转换为图片语法的行为,避免影响用户展示路径文本的场景
|
|
31
|
+
**Bare image path false conversion** - Disabled automatic conversion of bare local image paths to image syntax
|
|
32
|
+
|
|
33
|
+
### 改进 / Improvements
|
|
34
|
+
- ✅ **Zod Schema 拆分兼容 Web UI** - 将 `DingtalkConfigSchema` 拆分为 `DingtalkConfigBaseSchema` 和带 `superRefine` 的完整 Schema,解决 JSON Schema 生成兼容性问题
|
|
35
|
+
**Zod Schema split for Web UI compatibility** - Split schema to fix `buildChannelConfigSchema` JSON Schema generation
|
|
36
|
+
|
|
37
|
+
- ✅ **configSchema 类型简化** - 将 `clientId`、`clientSecret` 等字段从 `oneOf` 联合类型简化为单一 `string` 类型
|
|
38
|
+
**configSchema type simplification** - Simplified JSON Schema from `oneOf` union types to single `string` type
|
|
39
|
+
|
|
40
|
+
- ✅ **reply-dispatcher logger 统一** - 替换手动构建的 log 对象为 `createLoggerFromConfig`
|
|
41
|
+
**reply-dispatcher logger unification** - Replaced manual log object with `createLoggerFromConfig`
|
|
42
|
+
|
|
43
|
+
- ✅ **锁定 axios 版本到 1.6.0** - 避免自动升级引入不兼容变更
|
|
44
|
+
**Pin axios to 1.6.0** - Prevent automatic upgrades from introducing incompatible changes
|
|
45
|
+
|
|
8
46
|
## [0.8.8] - 2026-03-29
|
|
9
47
|
|
|
10
48
|
### 修复 / Fixes
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dingtalk-connector",
|
|
3
3
|
"name": "DingTalk Channel",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.9",
|
|
5
5
|
"description": "DingTalk (钉钉) messaging channel via Stream mode with AI Card streaming",
|
|
6
6
|
"author": "DingTalk Real Team",
|
|
7
7
|
"main": "index.ts",
|
|
@@ -11,11 +11,6 @@
|
|
|
11
11
|
"configSchema": {
|
|
12
12
|
"type": "object",
|
|
13
13
|
"additionalProperties": false,
|
|
14
|
-
"properties": {
|
|
15
|
-
"enabled": {
|
|
16
|
-
"type": "boolean",
|
|
17
|
-
"default": true
|
|
18
|
-
}
|
|
19
|
-
}
|
|
14
|
+
"properties": {}
|
|
20
15
|
}
|
|
21
16
|
}
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
ChannelMeta,
|
|
3
2
|
ChannelPlugin,
|
|
4
3
|
ClawdbotConfig,
|
|
5
4
|
} from "openclaw/plugin-sdk";
|
|
@@ -30,33 +29,17 @@ import { monitorDingtalkProvider } from "./core/provider.ts";
|
|
|
30
29
|
import { sendTextToDingTalk, sendMediaToDingTalk } from "./services/messaging/index.ts";
|
|
31
30
|
import type { ResolvedDingtalkAccount, DingtalkConfig } from "./types/index.ts";
|
|
32
31
|
|
|
33
|
-
const meta
|
|
32
|
+
const meta = {
|
|
34
33
|
id: "dingtalk-connector",
|
|
35
34
|
label: "DingTalk",
|
|
36
35
|
selectionLabel: "DingTalk (钉钉)",
|
|
37
36
|
docsPath: "/channels/dingtalk-connector",
|
|
38
37
|
docsLabel: "dingtalk-connector",
|
|
39
38
|
blurb: "钉钉企业内部机器人,使用 Stream 模式,无需公网 IP,支持 AI Card 流式响应。",
|
|
40
|
-
aliases: ["dd", "ding"],
|
|
39
|
+
aliases: ["dd", "ding"] as string[],
|
|
41
40
|
order: 70,
|
|
42
41
|
};
|
|
43
42
|
|
|
44
|
-
const secretInputJsonSchema = {
|
|
45
|
-
oneOf: [
|
|
46
|
-
{ type: "string" },
|
|
47
|
-
{
|
|
48
|
-
type: "object",
|
|
49
|
-
additionalProperties: false,
|
|
50
|
-
required: ["source", "provider", "id"],
|
|
51
|
-
properties: {
|
|
52
|
-
source: { type: "string", enum: ["env", "file", "exec"] },
|
|
53
|
-
provider: { type: "string", minLength: 1 },
|
|
54
|
-
id: { type: "string", minLength: 1 },
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
} as const;
|
|
59
|
-
|
|
60
43
|
export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
61
44
|
id: "dingtalk-connector",
|
|
62
45
|
meta: {
|
|
@@ -100,30 +83,27 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
|
100
83
|
properties: {
|
|
101
84
|
enabled: { type: "boolean" },
|
|
102
85
|
defaultAccount: { type: "string" },
|
|
103
|
-
clientId: {
|
|
104
|
-
clientSecret:
|
|
86
|
+
clientId: { type: "string" },
|
|
87
|
+
clientSecret: { type: "string" },
|
|
105
88
|
enableMediaUpload: { type: "boolean" },
|
|
106
89
|
systemPrompt: { type: "string" },
|
|
107
90
|
dmPolicy: { type: "string", enum: ["open", "pairing", "allowlist"] },
|
|
108
|
-
allowFrom: { type: "array", items: {
|
|
91
|
+
allowFrom: { type: "array", items: { type: "string" } },
|
|
109
92
|
groupPolicy: { type: "string", enum: ["open", "allowlist", "disabled"] },
|
|
110
|
-
groupAllowFrom: {
|
|
111
|
-
type: "array",
|
|
112
|
-
items: { oneOf: [{ type: "string" }, { type: "number" }] },
|
|
113
|
-
},
|
|
93
|
+
groupAllowFrom: { type: "array", items: { type: "string" } },
|
|
114
94
|
requireMention: { type: "boolean" },
|
|
115
|
-
groupSessionScope: {
|
|
116
|
-
type: "string",
|
|
117
|
-
enum: ["group", "group_sender"],
|
|
118
|
-
},
|
|
95
|
+
groupSessionScope: { type: "string", enum: ["group", "group_sender"] },
|
|
119
96
|
separateSessionByConversation: { type: "boolean" },
|
|
120
97
|
sharedMemoryAcrossConversations: { type: "boolean" },
|
|
121
98
|
historyLimit: { type: "integer", minimum: 0 },
|
|
122
|
-
dmHistoryLimit: { type: "integer", minimum: 0 },
|
|
123
99
|
textChunkLimit: { type: "integer", minimum: 1 },
|
|
124
100
|
mediaMaxMb: { type: "number", minimum: 0 },
|
|
125
101
|
typingIndicator: { type: "boolean" },
|
|
126
102
|
resolveSenderNames: { type: "boolean" },
|
|
103
|
+
asyncMode: { type: "boolean" },
|
|
104
|
+
ackText: { type: "string" },
|
|
105
|
+
endpoint: { type: "string" },
|
|
106
|
+
debug: { type: "boolean" },
|
|
127
107
|
tools: {
|
|
128
108
|
type: "object",
|
|
129
109
|
additionalProperties: false,
|
|
@@ -146,12 +126,9 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
|
146
126
|
},
|
|
147
127
|
},
|
|
148
128
|
enabled: { type: "boolean" },
|
|
149
|
-
allowFrom: { type: "array", items: {
|
|
129
|
+
allowFrom: { type: "array", items: { type: "string" } },
|
|
150
130
|
systemPrompt: { type: "string" },
|
|
151
|
-
groupSessionScope: {
|
|
152
|
-
type: "string",
|
|
153
|
-
enum: ["group", "group_sender"],
|
|
154
|
-
},
|
|
131
|
+
groupSessionScope: { type: "string", enum: ["group", "group_sender"] },
|
|
155
132
|
},
|
|
156
133
|
},
|
|
157
134
|
},
|
|
@@ -162,28 +139,26 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
|
162
139
|
properties: {
|
|
163
140
|
enabled: { type: "boolean" },
|
|
164
141
|
name: { type: "string" },
|
|
165
|
-
clientId: {
|
|
166
|
-
clientSecret:
|
|
142
|
+
clientId: { type: "string" },
|
|
143
|
+
clientSecret: { type: "string" },
|
|
167
144
|
enableMediaUpload: { type: "boolean" },
|
|
168
145
|
systemPrompt: { type: "string" },
|
|
169
146
|
dmPolicy: { type: "string", enum: ["open", "pairing", "allowlist"] },
|
|
170
|
-
allowFrom: { type: "array", items: {
|
|
147
|
+
allowFrom: { type: "array", items: { type: "string" } },
|
|
171
148
|
groupPolicy: { type: "string", enum: ["open", "allowlist", "disabled"] },
|
|
172
|
-
groupAllowFrom: {
|
|
173
|
-
type: "array",
|
|
174
|
-
items: { oneOf: [{ type: "string" }, { type: "number" }] },
|
|
175
|
-
},
|
|
149
|
+
groupAllowFrom: { type: "array", items: { type: "string" } },
|
|
176
150
|
requireMention: { type: "boolean" },
|
|
177
|
-
groupSessionScope: {
|
|
178
|
-
type: "string",
|
|
179
|
-
enum: ["group", "group_sender"],
|
|
180
|
-
},
|
|
151
|
+
groupSessionScope: { type: "string", enum: ["group", "group_sender"] },
|
|
181
152
|
separateSessionByConversation: { type: "boolean" },
|
|
182
153
|
sharedMemoryAcrossConversations: { type: "boolean" },
|
|
183
154
|
historyLimit: { type: "integer", minimum: 0 },
|
|
184
155
|
textChunkLimit: { type: "integer", minimum: 1 },
|
|
185
156
|
mediaMaxMb: { type: "number", minimum: 0 },
|
|
186
157
|
typingIndicator: { type: "boolean" },
|
|
158
|
+
asyncMode: { type: "boolean" },
|
|
159
|
+
ackText: { type: "string" },
|
|
160
|
+
endpoint: { type: "string" },
|
|
161
|
+
debug: { type: "boolean" },
|
|
187
162
|
tools: {
|
|
188
163
|
type: "object",
|
|
189
164
|
additionalProperties: false,
|
|
@@ -342,7 +317,7 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
|
342
317
|
};
|
|
343
318
|
},
|
|
344
319
|
},
|
|
345
|
-
|
|
320
|
+
setupWizard: dingtalkOnboardingAdapter as any,
|
|
346
321
|
messaging: {
|
|
347
322
|
normalizeTarget: (raw) => normalizeDingtalkTarget(raw) ?? undefined,
|
|
348
323
|
targetResolver: {
|
|
@@ -465,7 +440,7 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
|
465
440
|
},
|
|
466
441
|
},
|
|
467
442
|
status: {
|
|
468
|
-
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID, { port: null }),
|
|
443
|
+
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID, { port: null }) as any,
|
|
469
444
|
buildChannelSummary: ({ snapshot }) => ({
|
|
470
445
|
// 只返回 probe 相关字段,不透传运行时字段(running/lastStartAt 等)。
|
|
471
446
|
// 运行时状态由框架从 store.runtimes 自动维护,buildChannelSummary 在 probe
|
|
@@ -572,7 +547,7 @@ export const dingtalkPlugin: ChannelPlugin<ResolvedDingtalkAccount> = {
|
|
|
572
547
|
});
|
|
573
548
|
} catch (err: any) {
|
|
574
549
|
// 打印真实错误到 stderr,绕过框架 log 系统(框架的 runtime.log 可能未初始化)
|
|
575
|
-
ctx.log?.error(`[dingtalk-connector][${ctx.accountId}] startAccount error
|
|
550
|
+
ctx.log?.error(`[dingtalk-connector][${ctx.accountId}] startAccount error: ${err?.message ?? err}\n${err?.stack ?? ''}`);
|
|
576
551
|
throw err;
|
|
577
552
|
}
|
|
578
553
|
},
|
package/src/config/schema.ts
CHANGED
|
@@ -54,7 +54,6 @@ const DingtalkSharedConfigShape = {
|
|
|
54
54
|
requireMention: z.boolean().optional(),
|
|
55
55
|
groups: z.record(z.string(), DingtalkGroupSchema.optional()).optional(),
|
|
56
56
|
historyLimit: z.number().int().min(0).optional(),
|
|
57
|
-
dmHistoryLimit: z.number().int().min(0).optional(),
|
|
58
57
|
textChunkLimit: z.number().int().positive().optional(),
|
|
59
58
|
mediaMaxMb: z.number().positive().optional(),
|
|
60
59
|
tools: DingtalkToolsConfigSchema,
|
|
@@ -83,7 +82,11 @@ export const DingtalkAccountConfigSchema = z
|
|
|
83
82
|
})
|
|
84
83
|
.strict();
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Base schema (ZodObject) without superRefine, used for JSON Schema generation (Web UI).
|
|
87
|
+
* superRefine turns the schema into ZodEffects which is not compatible with buildChannelConfigSchema.
|
|
88
|
+
*/
|
|
89
|
+
export const DingtalkConfigBaseSchema = z
|
|
87
90
|
.object({
|
|
88
91
|
enabled: z.boolean().optional(),
|
|
89
92
|
defaultAccount: z.string().optional(),
|
|
@@ -102,8 +105,9 @@ export const DingtalkConfigSchema = z
|
|
|
102
105
|
// Multi-account configuration
|
|
103
106
|
accounts: z.record(z.string(), DingtalkAccountConfigSchema.optional()).optional(),
|
|
104
107
|
})
|
|
105
|
-
.strict()
|
|
106
|
-
|
|
108
|
+
.strict();
|
|
109
|
+
|
|
110
|
+
export const DingtalkConfigSchema = DingtalkConfigBaseSchema.superRefine((value, ctx) => {
|
|
107
111
|
const defaultAccount = value.defaultAccount?.trim();
|
|
108
112
|
if (defaultAccount && value.accounts && Object.keys(value.accounts).length > 0) {
|
|
109
113
|
const normalizedDefaultAccount = normalizeAccountId(defaultAccount);
|
package/src/core/connection.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* - 详细的消息接收日志(三阶段:接收、解析、处理)
|
|
13
13
|
* - 连接统计和监控(每分钟输出)
|
|
14
14
|
*/
|
|
15
|
+
import * as fs from 'fs';
|
|
15
16
|
import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
|
|
16
17
|
import type { ResolvedDingtalkAccount } from "../types/index.ts";
|
|
17
18
|
import {
|
|
@@ -101,6 +102,30 @@ export async function monitorSingleAccount(
|
|
|
101
102
|
);
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
// ============ 修复 macOS LaunchAgent 环境下的文件描述符问题 ============
|
|
106
|
+
//
|
|
107
|
+
// 在 macOS LaunchAgent/daemon 环境下,进程启动时 stdin/stdout/stderr(fd 0/1/2)
|
|
108
|
+
// 可能无效(EBADF),导致 Node.js 的 net.Socket 在创建 TCP 连接时出现 EBADF 错误。
|
|
109
|
+
// 通过打开 /dev/null 来确保 fd 0/1/2 有效,避免 socket 创建时使用无效的 fd。
|
|
110
|
+
//
|
|
111
|
+
// 参考:OpenClaw issue #8021 (spawn EBADF on macOS with Node.js 22+)
|
|
112
|
+
if (process.platform === 'darwin') {
|
|
113
|
+
for (const stdioFd of [0, 1, 2]) {
|
|
114
|
+
try {
|
|
115
|
+
fs.fstatSync(stdioFd);
|
|
116
|
+
} catch (fdError: any) {
|
|
117
|
+
if (fdError.code === 'EBADF') {
|
|
118
|
+
logger.warn(`[LaunchAgent] 检测到 fd ${stdioFd} 无效(EBADF),重定向到 /dev/null 以防止 TCP socket 创建失败`);
|
|
119
|
+
try {
|
|
120
|
+
fs.openSync('/dev/null', stdioFd === 0 ? 'r' : 'w');
|
|
121
|
+
} catch (openError: any) {
|
|
122
|
+
logger.warn(`[LaunchAgent] 无法修复 fd ${stdioFd}: ${openError.message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
104
129
|
logger.info(`Starting DingTalk Stream client...`);
|
|
105
130
|
logger.info(`Initializing with clientId: ${clientIdStr.substring(0, 8)}...`);
|
|
106
131
|
logger.info(`WebSocket keepAlive: false (using application-layer heartbeat)`);
|