@jeik/dingtalk-connector 0.8.28 → 0.8.29

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +30 -31
  2. package/README.en.md +36 -71
  3. package/README.md +46 -74
  4. package/dist/{background-work-Cxb4b-91.mjs → background-work-DkaSDqWk.mjs} +12 -1
  5. package/dist/card-content-cache-C7-XHhHw.mjs +2 -0
  6. package/dist/{card-content-cache-bDQFz2u8.mjs → card-content-cache-DT_OYThh.mjs} +15 -1
  7. package/dist/chunk-upload-BKM1y4Ba.mjs +2 -0
  8. package/dist/{chunk-upload-BE71drPg.mjs → chunk-upload-CIU5G_ay.mjs} +1 -1
  9. package/dist/{common-BZiVgd3A.mjs → common-BfIYs1yC.mjs} +3 -3
  10. package/dist/{common-DgL28gCZ.mjs → common-C0Oaf0z-.mjs} +1 -1
  11. package/dist/{connection-CZ7ZoN5_.mjs → connection-obtrPkj4.mjs} +56 -65
  12. package/dist/entry-bundled.mjs +1 -1
  13. package/dist/{gateway-methods-kNX3qvqw.mjs → gateway-methods-BdcpfxEZ.mjs} +1 -1
  14. package/dist/gateway-methods-DQ6TwOAr.mjs +2 -0
  15. package/dist/index.mjs +2 -2
  16. package/dist/{logger-mZ9OSbmD.mjs → logger-CnBTcwyq.mjs} +16 -2
  17. package/dist/logger-D8H2IcYz.mjs +2 -0
  18. package/dist/{media-BqpUGCni.mjs → media-DDtX37T2.mjs} +1 -1
  19. package/dist/{media-DnQB2BrL.mjs → media-g8tJtpfU.mjs} +29 -20
  20. package/dist/{message-handler-B1usz1wb.mjs → message-handler-BrO2i7tg.mjs} +26 -30
  21. package/dist/{messaging-DVS3UKOp.mjs → messaging-CK0Wz3Ze.mjs} +18 -20
  22. package/dist/{runtime-A6G7WAWn.mjs → runtime-DbqGRyhI.mjs} +6 -5
  23. package/dist/{utils-Bjh4r_qS.mjs → utils-Bwz2Fls_.mjs} +1 -1
  24. package/docs/RELEASE_NOTES_V0.8.28.md +4 -4
  25. package/docs/RELEASE_NOTES_V0.8.29.md +57 -0
  26. package/openclaw.plugin.json +9 -5
  27. package/package.json +1 -1
  28. package/src/config/schema.ts +2 -1
  29. package/src/core/connection.ts +90 -113
  30. package/src/core/message-handler.ts +24 -16
  31. package/src/reply-dispatcher.ts +14 -20
  32. package/src/services/media.ts +60 -27
  33. package/src/services/messaging/card-content-cache.ts +11 -6
  34. package/src/services/messaging.ts +52 -38
  35. package/src/utils/background-work.ts +3 -1
  36. package/src/utils/logger.ts +23 -2
  37. package/dist/card-content-cache-c4Ls96eJ.mjs +0 -2
  38. package/dist/chunk-upload-PwhogwfE.mjs +0 -2
  39. package/dist/gateway-methods-BkI1gKaC.mjs +0 -2
  40. package/dist/logger-BmJkQkm1.mjs +0 -2
@@ -1,5 +1,5 @@
1
- import { c as logMediaIdTrace, d as processLocalImages, u as processImagesForOutbound, y as uploadMediaToDingTalk } from "./media-DnQB2BrL.mjs";
2
- import { n as createLoggerFromConfig } from "./logger-mZ9OSbmD.mjs";
1
+ import { c as logMediaIdTrace, d as processLocalImages, u as processImagesForOutbound, y as uploadMediaToDingTalk } from "./media-g8tJtpfU.mjs";
2
+ import { n as createLoggerFromConfig, r as isDingtalkDebug } from "./logger-CnBTcwyq.mjs";
3
3
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
4
4
  import { i as getOapiAccessToken, r as getAccessToken, t as DINGTALK_API } from "./utils-CIfI_3Jh.mjs";
5
5
  import { r as MEDIA_MSG_TYPES } from "./session-DJ4jYqPv.mjs";
@@ -371,7 +371,7 @@ async function finishAICard(card, content, config, log, contentVar, skipInputing
371
371
  const fixedContent = ensureTableBlankLines(cleanContent);
372
372
  log?.info?.(`[DingTalk][AICard] 开始 finish(一次性定稿,无流式回放),最终内容长度=${fixedContent.length}`);
373
373
  try {
374
- const { rememberCardContent } = await import("./card-content-cache-c4Ls96eJ.mjs");
374
+ const { rememberCardContent } = await import("./card-content-cache-C7-XHhHw.mjs");
375
375
  rememberCardContent({
376
376
  text: fixedContent,
377
377
  outTrackId: card.cardInstanceId,
@@ -821,7 +821,7 @@ function isImageMediaPath(mediaUrl) {
821
821
  async function downloadRemoteMediaToTemp(url, log) {
822
822
  const tag = "[DingTalk][RemoteMedia]";
823
823
  try {
824
- console.log(`${tag} 开始下载 | ${url}`);
824
+ if (isDingtalkDebug()) console.log(`${tag} 开始下载 | ${url}`);
825
825
  const res = await fetch(url, {
826
826
  redirect: "follow",
827
827
  signal: AbortSignal.timeout(6e4),
@@ -858,7 +858,7 @@ async function downloadRemoteMediaToTemp(url, log) {
858
858
  const { writeFileSync } = await import("node:fs");
859
859
  const tmp = path.join(os.tmpdir(), `dingtalk-remote-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);
860
860
  writeFileSync(tmp, buf);
861
- console.log(`${tag} 下载成功 | bytes=${buf.length} ct=${ct || "-"} tmp=${tmp}`);
861
+ if (isDingtalkDebug()) console.log(`${tag} 下载成功 | bytes=${buf.length} ct=${ct || "-"} tmp=${tmp}`);
862
862
  return tmp;
863
863
  } catch (err) {
864
864
  console.warn(`${tag} 下载异常 | ${err?.message || err}`);
@@ -876,7 +876,7 @@ async function resolveMediaSourceToLocalFile(mediaUrl, mediaLocalRoots, log) {
876
876
  cleanup: tmp
877
877
  };
878
878
  }
879
- const { toLocalPath } = await import("./media-BqpUGCni.mjs");
879
+ const { toLocalPath } = await import("./media-DDtX37T2.mjs");
880
880
  const _fs = await import("fs");
881
881
  const _path = await import("path");
882
882
  let resolved = toLocalPath(mediaUrl);
@@ -911,24 +911,22 @@ async function sendTextToDingTalk(params) {
911
911
  };
912
912
  }
913
913
  const targetParam = resolveOutboundTarget(target);
914
- console.log(`[DingTalk][LocalImage] sendTextToDingTalk 入口 | target=${target} textLen=${text?.length ?? 0}`);
915
- logMediaIdTrace("sendTextToDingTalk:in", text, `target=${target}`, true);
916
914
  const beforeLen = text?.length ?? 0;
915
+ const hasMdImg = /!\[[^\]]*\]\([^)]+\)/.test(text || "");
916
+ if (hasMdImg || isDingtalkDebug()) logMediaIdTrace("sendTextToDingTalk:in", text, `target=${target}`);
917
917
  try {
918
918
  const oapiToken = await getOapiAccessToken(config);
919
- console.log(`[DingTalk][LocalImage] sendTextToDingTalk 入口 | target=${target} textLen=${beforeLen} hasToken=${!!oapiToken}`);
920
919
  if (oapiToken && text) {
921
920
  text = (await processImagesForOutbound(text, oapiToken, log)).text;
922
- console.log(`[DingTalk][LocalImage] sendTextToDingTalk 处理后 | ${beforeLen}→${text.length} 字`);
923
- logMediaIdTrace("sendTextToDingTalk:after-process", text, void 0, true);
924
- } else if (!oapiToken) console.warn(`[DingTalk][LocalImage] sendTextToDingTalk 无 oapiToken,跳过图片上传(本地 MD 图会灰)`);
921
+ if (beforeLen !== text.length && (hasMdImg || isDingtalkDebug())) console.log(`[DingTalk][LocalImage] sendTextToDingTalk 处理后 | ${beforeLen}→${text.length} 字`);
922
+ if (hasMdImg || isDingtalkDebug()) logMediaIdTrace("sendTextToDingTalk:after-process", text);
923
+ } else if (!oapiToken && hasMdImg) console.warn(`[DingTalk][LocalImage] sendTextToDingTalk 无 oapiToken,跳过图片上传(本地 MD 图会灰)`);
925
924
  } catch (err) {
926
925
  console.warn(`[DingTalk][LocalImage] sendTextToDingTalk 图片处理失败: ${err?.message || err}`);
927
926
  }
928
927
  const msgType = shouldSendAsMarkdown(text) ? "markdown" : "text";
929
928
  const cardOpts = messageToolProactiveCardOptions(config);
930
- logMediaIdTrace("sendTextToDingTalk:API前", text, `msgType=${msgType} messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard}`, true);
931
- console.log(`[DingTalk][MessageCard] sendTextToDingTalk | messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard} tpl=${cardOpts.cardTemplateId || "-"}`);
929
+ if (hasMdImg || isDingtalkDebug()) logMediaIdTrace("sendTextToDingTalk:API前", text, `msgType=${msgType} messageAnswerCard=${isMessageAnswerCardEnabled(config)} useAICard=${cardOpts.useAICard}`);
932
930
  return sendProactive(config, targetParam, text, {
933
931
  msgType,
934
932
  replyToId,
@@ -1090,7 +1088,7 @@ async function sendMediaToDingTalk(params) {
1090
1088
  const mediaId = uploadResult.mediaId;
1091
1089
  const imgsInCaption = (caption.match(/!\[[^\]]*\]\([^)]+\)/g) || []).length;
1092
1090
  const mergeMd = config.messageImageMd === true && caption.length > 0 && imgsInCaption >= 1;
1093
- console.log(`[DingTalk][LocalImage] sendMedia 图片策略 | messageImageMd=${config.messageImageMd === true} imgsInCaption=${imgsInCaption} mergeMd=${mergeMd} remote=${isRemoteHttpUrl(mediaUrl)}`);
1091
+ if (isDingtalkDebug()) console.log(`[DingTalk][LocalImage] sendMedia 图片策略 | messageImageMd=${config.messageImageMd === true} imgsInCaption=${imgsInCaption} mergeMd=${mergeMd} remote=${isRemoteHttpUrl(mediaUrl)}`);
1094
1092
  if (mergeMd) {
1095
1093
  const result = await sendProactive(config, targetParam, `${caption}\n\n![](${mediaId})`, {
1096
1094
  msgType: "markdown",
@@ -1145,7 +1143,7 @@ async function sendMediaToDingTalk(params) {
1145
1143
  const fileName = mediaUrl.split("/").filter(Boolean).pop()?.split("?")[0] || "file";
1146
1144
  if (mediaType === "video") {
1147
1145
  const videoMarker = `[DINGTALK_VIDEO]{"path":"${resolvedMediaUrl}"}[/DINGTALK_VIDEO]`;
1148
- const { processVideoMarkers } = await import("./media-BqpUGCni.mjs");
1146
+ const { processVideoMarkers } = await import("./media-DDtX37T2.mjs");
1149
1147
  await processVideoMarkers(videoMarker, "", config, oapiToken, console, true, targetParam);
1150
1148
  return {
1151
1149
  ok: true,
@@ -1164,7 +1162,7 @@ async function sendMediaToDingTalk(params) {
1164
1162
  fileName,
1165
1163
  fileType: ext && ext.length < 12 ? ext : "file"
1166
1164
  };
1167
- const { sendFileProactive } = await import("./media-BqpUGCni.mjs");
1165
+ const { sendFileProactive } = await import("./media-DDtX37T2.mjs");
1168
1166
  await sendFileProactive(config, targetParam, fileInfo, uploadResult.mediaId, log);
1169
1167
  return {
1170
1168
  ok: true,
@@ -1174,7 +1172,7 @@ async function sendMediaToDingTalk(params) {
1174
1172
  } finally {
1175
1173
  if (cleanupTemp) try {
1176
1174
  _fs.unlinkSync(cleanupTemp);
1177
- console.log(`[DingTalk][RemoteMedia] 已清理临时文件 | ${cleanupTemp}`);
1175
+ if (isDingtalkDebug()) console.log(`[DingTalk][RemoteMedia] 已清理临时文件 | ${cleanupTemp}`);
1178
1176
  } catch {}
1179
1177
  }
1180
1178
  } catch (err) {
@@ -1249,7 +1247,7 @@ async function sendProactiveInternal(config, target, content, options) {
1249
1247
  const card = await createAICardForTarget(config, target, externalLog, cardTemplateId);
1250
1248
  if (card) {
1251
1249
  await finishAICard(card, content, config, externalLog, void 0, skipInputingWalk);
1252
- console.log(`[DingTalk][MessageCard] AI Card 发送成功 | outTrack=${card.cardInstanceId} tpl=${cardTemplateId || "default"} skipInputing=${skipInputingWalk}`);
1250
+ if (isDingtalkDebug()) console.log(`[DingTalk][MessageCard] AI Card 发送成功 | outTrack=${card.cardInstanceId} tpl=${cardTemplateId || "default"} skipInputing=${skipInputingWalk}`);
1253
1251
  return {
1254
1252
  ok: true,
1255
1253
  cardInstanceId: card.cardInstanceId,
@@ -1292,7 +1290,7 @@ async function sendProactiveInternal(config, target, content, options) {
1292
1290
  usedAICard: false
1293
1291
  };
1294
1292
  }
1295
- logMediaIdTrace("API出站", content, `msgKey=${payload.msgKey} type=${msgType}`, true);
1293
+ if (/!\[[^\]]*\]\([^)]+\)/.test(content || "") || isDingtalkDebug()) logMediaIdTrace("API出站", content, `msgKey=${payload.msgKey} type=${msgType}`);
1296
1294
  const body = {
1297
1295
  robotCode: String(config.clientId),
1298
1296
  msgKey: payload.msgKey,
@@ -1,9 +1,9 @@
1
- import { b as __exportAll } from "./media-DnQB2BrL.mjs";
1
+ import { b as __exportAll } from "./media-g8tJtpfU.mjs";
2
2
  import { a as resolveDingtalkAccount, c as addWildcardAllowFrom, d as hasConfiguredSecretInput, f as normalizeAccountId, l as createDefaultChannelRuntimeState, m as resolveDefaultGroupPolicy, o as resolveDingtalkCredentials, p as resolveAllowlistProviderRuntimeGroupPolicy, r as resolveDefaultDingtalkAccountId, s as DEFAULT_ACCOUNT_ID, t as listDingtalkAccountIds, u as formatDocsLink } from "./accounts-BAzdqkAV.mjs";
3
- import { t as createLogger } from "./logger-mZ9OSbmD.mjs";
3
+ import { t as createLogger } from "./logger-CnBTcwyq.mjs";
4
4
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
5
5
  import "./utils-CIfI_3Jh.mjs";
6
- import { S as finalClean, f as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-DVS3UKOp.mjs";
6
+ import { S as finalClean, f as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-CK0Wz3Ze.mjs";
7
7
  import { createRequire } from "node:module";
8
8
  import { z, z as z$1 } from "zod";
9
9
  //#region src/secret-input.ts
@@ -92,6 +92,7 @@ const DingtalkSharedConfigShape = {
92
92
  asyncMode: z$1.boolean().optional(),
93
93
  ackText: z$1.string().optional(),
94
94
  endpoint: z$1.string().optional(),
95
+ /** 调试日志:连接/入站摘要、图片 mediaId 追踪、引用回填、队列计数等(默认关,生产勿开) */
95
96
  debug: z$1.boolean().optional(),
96
97
  enableMediaUpload: z$1.boolean().optional(),
97
98
  systemPrompt: z$1.string().optional(),
@@ -955,8 +956,8 @@ async function monitorDingtalkProvider(opts = {}) {
955
956
  const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
956
957
  const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
957
958
  import("./accounts-BQptOmgB.mjs"),
958
- import("./message-handler-B1usz1wb.mjs"),
959
- import("./connection-CZ7ZoN5_.mjs")
959
+ import("./message-handler-BrO2i7tg.mjs"),
960
+ import("./connection-obtrPkj4.mjs")
960
961
  ]);
961
962
  const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
962
963
  const { handleDingTalkMessage } = monitorAccountModule;
@@ -1,4 +1,4 @@
1
- import "./logger-mZ9OSbmD.mjs";
1
+ import "./logger-CnBTcwyq.mjs";
2
2
  import { r as getAccessToken, t as DINGTALK_API } from "./utils-CIfI_3Jh.mjs";
3
3
  import "./session-DJ4jYqPv.mjs";
4
4
  export { DINGTALK_API, getAccessToken };
@@ -2,13 +2,13 @@
2
2
 
3
3
  **发布日期:** 2026-07-25
4
4
  **npm:** `@jeik/dingtalk-connector@0.8.28`
5
- **定位:** 基于官方 **0.8.24** 的社区增强正式版
5
+ **定位:** 基于官方 **0.8.24**,叠加本仓库独有优化的正式版
6
6
 
7
7
  ---
8
8
 
9
9
  ## 一句话
10
10
 
11
- 连接更稳、消息更少丢、模型出错时提示更清楚;官方 0.8.24 的长连接改进已吸收,社区图片/答案卡等增强继续保留。
11
+ 连接更稳、消息更少丢、模型出错时提示更清楚;官方 0.8.24 的长连接改进已吸收,**本仓库独有**的图片/答案卡等优化继续保留。
12
12
 
13
13
  ---
14
14
 
@@ -22,13 +22,13 @@
22
22
 
23
23
  ---
24
24
 
25
- ## 社区额外优化(效果)
25
+ ## 本仓库额外优化(效果)
26
26
 
27
27
  1. **真正能收消息才显示已连接** — 减少「显示在线、发了没反应」
28
28
  2. **连发 / 错误后 / 刚回完再发** — 消息进网关的成功率明显提高
29
29
  3. **上一条还在跑时再发** — 更容易马上看到排队提示和思考中表情
30
30
  4. **模型 503、欠费、无可用线路等** — 更容易定格成中文错误说明,少卡转圈
31
- 5. **原有社区能力** — 大段答案独立卡片、图片全路径、中文错误映射等均保留
31
+ 5. **本仓库独有能力** — 大段答案独立卡片、图片全路径、中文错误映射等均保留
32
32
 
33
33
  ---
34
34
 
@@ -0,0 +1,57 @@
1
+ # Release Notes · v0.8.29
2
+
3
+ **发布日期:** 2026-07-25
4
+ **npm:** `@jeik/dingtalk-connector@0.8.29`
5
+ **定位:** 正式加固版(日志 / 排障 / 文档)
6
+
7
+ ---
8
+
9
+ ## 一句话
10
+
11
+ 默认日志更干净;排障只需配置 `"debug": true`。连接、消息、错误卡能力继承 0.8.28。
12
+
13
+ ---
14
+
15
+ ## 本版变更
16
+
17
+ 1. **默认静默** — 无图正常回复不再刷 LocalImage / MediaIdTrace / CardCache
18
+ 2. **debug 配置** — 打开后输出连接、图片 mediaId、引用回填、队列等详细日志(无需环境变量)
19
+ 3. **文档** — 安装改为三条递进命令(最新 → 指定版本 → 官方源)
20
+
21
+ ---
22
+
23
+ ## 排障
24
+
25
+ ```json
26
+ "channels": {
27
+ "dingtalk-connector": {
28
+ "debug": true
29
+ }
30
+ }
31
+ ```
32
+
33
+ 改完后:`openclaw gateway restart`。用完请改回 `false`。
34
+
35
+ ---
36
+
37
+ ## 安装
38
+
39
+ ```bash
40
+ # 1)装最新
41
+ openclaw plugins install @jeik/dingtalk-connector --force && openclaw gateway restart
42
+
43
+ # 2)若不是最新,指定版本
44
+ openclaw plugins install @jeik/dingtalk-connector@0.8.29 --force && openclaw gateway restart
45
+
46
+ # 3)仍失败时走 npm 官方源
47
+ NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/dingtalk-connector@0.8.29 --force && openclaw gateway restart
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 建议验收
53
+
54
+ 1. 默认:纯文本对话日志无 LocalImage / MediaIdTrace 刷屏
55
+ 2. `"debug": true` 重启后:可见图片/引用类详细日志
56
+ 3. 模型 503:错误卡中文定稿,不永久转圈
57
+ 4. 任务进行中再发:有排队/处理中反馈
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "id": "dingtalk-connector",
3
3
  "name": "DingTalk Channel",
4
- "version": "0.8.20",
5
- "description": "Official OpenClaw DingTalk channel plugin | 钉钉官方 OpenClaw 插件",
6
- "author": "DingTalk Real Team",
4
+ "version": "0.8.29",
5
+ "description": "OpenClaw DingTalk channel plugin (community) | 钉钉 OpenClaw 社区增强版",
6
+ "author": "jeik",
7
7
  "main": "index.ts",
8
8
  "channels": [
9
9
  "dingtalk-connector"
@@ -240,7 +240,9 @@
240
240
  "type": "string"
241
241
  },
242
242
  "debug": {
243
- "type": "boolean"
243
+ "type": "boolean",
244
+ "default": false,
245
+ "description": "调试日志:连接/入站、图片 mediaId、引用回填、队列计数等。日常关闭;排障时设 true 后重启 gateway。"
244
246
  },
245
247
  "messageImageMd": {
246
248
  "type": "boolean",
@@ -491,7 +493,9 @@
491
493
  "type": "string"
492
494
  },
493
495
  "debug": {
494
- "type": "boolean"
496
+ "type": "boolean",
497
+ "default": false,
498
+ "description": "调试日志:连接/入站、图片 mediaId、引用回填、队列计数等。日常关闭;排障时设 true 后重启 gateway。"
495
499
  },
496
500
  "messageImageMd": {
497
501
  "type": "boolean",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeik/dingtalk-connector",
3
- "version": "0.8.28",
3
+ "version": "0.8.29",
4
4
  "description": "OpenClaw DingTalk channel plugin (community) | 钉钉 OpenClaw 社区增强版(基于官方 0.8.24,长连接与消息体验增强)",
5
5
  "type": "module",
6
6
  "exports": {
@@ -81,7 +81,8 @@ const DingtalkSharedConfigShape = {
81
81
  asyncMode: z.boolean().optional(),
82
82
  ackText: z.string().optional(),
83
83
  endpoint: z.string().optional(), // DWClient gateway endpoint
84
- debug: z.boolean().optional(), // DWClient debug mode
84
+ /** 调试日志:连接/入站摘要、图片 mediaId 追踪、引用回填、队列计数等(默认关,生产勿开) */
85
+ debug: z.boolean().optional(),
85
86
  enableMediaUpload: z.boolean().optional(),
86
87
  systemPrompt: z.string().optional(),
87
88
  /**