@jeik/dingtalk-connector 0.8.31 → 0.8.33

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 (35) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.en.md +8 -8
  3. package/README.md +8 -8
  4. package/bin/dingtalk-connector.js +81 -12
  5. package/dist/card-content-cache-BsFPIwOr.mjs +2 -0
  6. package/dist/{runtime-CjE4Z9G5.mjs → channel-CABtqkf_.mjs} +18 -29
  7. package/dist/chunk-upload-CNlZg1SF.mjs +2 -0
  8. package/dist/{common-BfIYs1yC.mjs → common-1-GDZ2h3.mjs} +2 -2
  9. package/dist/{common-C0Oaf0z-.mjs → common-DCVdWMiZ.mjs} +1 -1
  10. package/dist/{connection-obtrPkj4.mjs → connection-Bh3U9I4x.mjs} +2 -2
  11. package/dist/dws-delivery-context-ESC7sij7.mjs +185 -0
  12. package/dist/entry-bundled.mjs +1 -1
  13. package/dist/gateway-methods-CV8y0xGw.mjs +2 -0
  14. package/dist/{gateway-methods-BdcpfxEZ.mjs → gateway-methods-Ce1FXmCx.mjs} +4 -4
  15. package/dist/index.d.mts +12 -0
  16. package/dist/index.mjs +3 -2
  17. package/dist/{message-handler-BeTQQCUe.mjs → message-handler-BoVSEDwY.mjs} +41 -14
  18. package/dist/{messaging-CK0Wz3Ze.mjs → messaging-CwQLykl6.mjs} +1 -1
  19. package/dist/runtime-DDMzayvA.mjs +26 -0
  20. package/dist/utils-legacy-Bx5izlVF.mjs +3 -0
  21. package/openclaw.plugin.json +28 -1
  22. package/package.json +1 -1
  23. package/src/config/schema.ts +11 -0
  24. package/src/core/message-handler.ts +2 -0
  25. package/src/reply-dispatcher.ts +35 -0
  26. package/src/services/dws-delivery-context.ts +317 -0
  27. package/dist/card-content-cache-C7-XHhHw.mjs +0 -2
  28. package/dist/chunk-upload-BKM1y4Ba.mjs +0 -2
  29. package/dist/gateway-methods-DQ6TwOAr.mjs +0 -2
  30. package/dist/utils-legacy-BOqY3zE7.mjs +0 -3
  31. /package/dist/{background-work-DkaSDqWk.mjs → background-work-874-aK4-.mjs} +0 -0
  32. /package/dist/{card-content-cache-DT_OYThh.mjs → card-content-cache-CGggfgCg.mjs} +0 -0
  33. /package/dist/{chunk-upload-CIU5G_ay.mjs → chunk-upload-z185bTqH.mjs} +0 -0
  34. /package/dist/{game-xiyou-uwsv23AC.mjs → game-xiyou-CKoWJobs.mjs} +0 -0
  35. /package/dist/{utils-legacy-DQ3HeGHh.mjs → utils-legacy-CGEa8tg2.mjs} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ 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.33] - 2026-07-31
9
+
10
+ ### Features
11
+
12
+ - **dws 发消息成功后注入 outbound_message 上下文** — 与 `message` 工具 OC-4 一致:当 agent 通过 `dws chat message send|send-by-bot|reply|send-by-webhook` 发消息成功时,自动向目标会话写入模型可见的出站上下文(来源/调用人/正文/可复制 ID)。
13
+ - 配置项 `channels.dingtalk-connector.dwsDeliveryContext`:`target`(默认)/ `source` / `both` / `off`
14
+ - **仅叠加**:不影响普通回复与 message 工具;解析失败或非发消息命令时 no-op
15
+ - 实现:`src/services/dws-delivery-context.ts` + `onCommandOutput` 钩子;从命令行解析 `--group`/`--user` 后经 `resolveOutboundSessionRoute` 映射 sessionKey
16
+ - 依赖 OpenClaw(≥ 本配套版本)`plugin-sdk/outbound-runtime` 导出 `appendOutboundMessageDeliveryContext`
17
+
18
+ ### Docs
19
+
20
+ - **CHANGELOG / schema / openclaw.plugin.json** — 同步 `dwsDeliveryContext` 字段说明与 UI help。
21
+
22
+ ## [0.8.32] - 2026-07-29
23
+
24
+ ### Features
25
+
26
+ - **安装向导可选 CLI** — `install` 时询问用 `openclaw`(1,默认) 还是 `jeikclaw`(2) 执行 `plugins install`;支持 `--cli 1|2|openclaw|jeikclaw` 非交互。
27
+
8
28
  ## [0.8.31] - 2026-07-29
9
29
 
10
30
  ### Fixes
package/README.en.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <p>Community-enhanced fork based on official <strong>v0.8.24</strong>: adopts official long-connection improvements, plus stronger message delivery, queue feedback, and error-card UX.<br/>
5
5
  Keeps <strong>this repo’s unique</strong> extras (images, answer cards, first-response UX) and continues to fix issues not yet covered upstream.</p>
6
6
 
7
- <p><strong>Current release: <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.31</strong></p>
7
+ <p><strong>Current release: <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.32</strong></p>
8
8
 
9
9
  <p>
10
10
  <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector"><img src="https://img.shields.io/npm/v/@jeik/dingtalk-connector.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="npm version" /></a>
@@ -23,7 +23,7 @@
23
23
 
24
24
  ## 🔧 Recent Updates
25
25
 
26
- ### 🚀 v0.8.31 · 2026-07-29 (current)
26
+ ### 🚀 v0.8.32 · 2026-07-29 (current)
27
27
 
28
28
  **Theme: production hardening · quieter logs · debug config only**
29
29
 
@@ -39,7 +39,7 @@ Built on **0.8.28** (steadier connection / fewer lost messages / clearer error c
39
39
 
40
40
  ### 📦 v0.8.28 · 2026-07-25
41
41
 
42
- Official 0.8.24-aligned connection & delivery hardening (included in 0.8.31).
42
+ Official 0.8.24-aligned connection & delivery hardening (included in 0.8.32).
43
43
 
44
44
  ### 📦 v0.8.26 / 0.8.25 and earlier
45
45
 
@@ -65,10 +65,10 @@ Package: [`@jeik/dingtalk-connector`](https://www.npmjs.com/package/@jeik/dingta
65
65
  npx @jeik/dingtalk-connector install --force && openclaw gateway restart
66
66
 
67
67
  # 2) If you did not get the latest, pin the version
68
- npx @jeik/dingtalk-connector@0.8.31 install --force && openclaw gateway restart
68
+ npx @jeik/dingtalk-connector@0.8.32 install --force && openclaw gateway restart
69
69
 
70
70
  # 3) If it still fails, force the official npm registry
71
- NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx @jeik/dingtalk-connector@0.8.31 install --force && openclaw gateway restart
71
+ NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx @jeik/dingtalk-connector@0.8.32 install --force && openclaw gateway restart
72
72
  ```
73
73
 
74
74
  ### B) Plugin only (credentials already set; try in order)
@@ -78,10 +78,10 @@ NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx @jeik/dingtalk-connector@0.8.
78
78
  openclaw plugins install @jeik/dingtalk-connector --force && openclaw gateway restart
79
79
 
80
80
  # 2) If you did not get the latest, pin the version
81
- openclaw plugins install @jeik/dingtalk-connector@0.8.31 --force && openclaw gateway restart
81
+ openclaw plugins install @jeik/dingtalk-connector@0.8.32 --force && openclaw gateway restart
82
82
 
83
83
  # 3) If it still fails, force the official npm registry
84
- NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/dingtalk-connector@0.8.31 --force && openclaw gateway restart
84
+ NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/dingtalk-connector@0.8.32 --force && openclaw gateway restart
85
85
  ```
86
86
 
87
87
  ### Local tgz / from source (dev / offline)
@@ -90,7 +90,7 @@ NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/di
90
90
  git clone https://github.com/jeikl/dingtalk-openclaw-connector-fix-Community.git
91
91
  cd dingtalk-openclaw-connector-fix-Community
92
92
  npm install && npm run build && npm pack
93
- openclaw plugins install ./jeik-dingtalk-connector-0.8.31.tgz --force && openclaw gateway restart
93
+ openclaw plugins install ./jeik-dingtalk-connector-0.8.32.tgz --force && openclaw gateway restart
94
94
  ```
95
95
 
96
96
  ### Smoke check
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <p>基于官方最新 <strong>v0.8.24</strong> 的社区增强版:吸收官方长连接改进,并重点优化消息接收、排队反馈与模型错误展示。<br/>
5
5
  保留社区在图片、答案卡、首响体验上的增强,持续修官方暂未覆盖的实际使用问题。</p>
6
6
 
7
- <p><strong>当前正式版:<a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.31</strong></p>
7
+ <p><strong>当前正式版:<a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.32</strong></p>
8
8
 
9
9
  <p>
10
10
  <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector"><img src="https://img.shields.io/npm/v/@jeik/dingtalk-connector.svg?style=flat&colorA=18181B&colorB=28CF8D" alt="npm version" /></a>
@@ -23,7 +23,7 @@
23
23
 
24
24
  ## 🔧 最近更新
25
25
 
26
- ### 🚀 v0.8.31 · 2026-07-29(当前正式版)
26
+ ### 🚀 v0.8.32 · 2026-07-29(当前正式版)
27
27
 
28
28
  **主题:正式加固 · 日志更干净 · 排障只开 debug**
29
29
 
@@ -39,7 +39,7 @@
39
39
 
40
40
  ### 📦 v0.8.28 · 2026-07-25
41
41
 
42
- 基于官方 0.8.24 的长连接与消息体验加固(当前能力已并入 0.8.31)。
42
+ 基于官方 0.8.24 的长连接与消息体验加固(当前能力已并入 0.8.32)。
43
43
 
44
44
  ### 📦 v0.8.26 / 0.8.25 及更早
45
45
 
@@ -65,10 +65,10 @@
65
65
  npx @jeik/dingtalk-connector install --force && openclaw gateway restart
66
66
 
67
67
  # 2)若装到的不是最新,指定版本号
68
- npx @jeik/dingtalk-connector@0.8.31 install --force && openclaw gateway restart
68
+ npx @jeik/dingtalk-connector@0.8.32 install --force && openclaw gateway restart
69
69
 
70
70
  # 3)若仍装不了,强制走 npm 官方源
71
- NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx @jeik/dingtalk-connector@0.8.31 install --force && openclaw gateway restart
71
+ NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx @jeik/dingtalk-connector@0.8.32 install --force && openclaw gateway restart
72
72
  ```
73
73
 
74
74
  ### B)只装插件(凭证已配好时,按顺序试)
@@ -78,10 +78,10 @@ NPM_CONFIG_REGISTRY=https://registry.npmjs.org npx @jeik/dingtalk-connector@0.8.
78
78
  openclaw plugins install @jeik/dingtalk-connector --force && openclaw gateway restart
79
79
 
80
80
  # 2)若装到的不是最新,指定版本号
81
- openclaw plugins install @jeik/dingtalk-connector@0.8.31 --force && openclaw gateway restart
81
+ openclaw plugins install @jeik/dingtalk-connector@0.8.32 --force && openclaw gateway restart
82
82
 
83
83
  # 3)若仍装不了,强制走 npm 官方源
84
- NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/dingtalk-connector@0.8.31 --force && openclaw gateway restart
84
+ NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/dingtalk-connector@0.8.32 --force && openclaw gateway restart
85
85
  ```
86
86
 
87
87
  ### 本地 tgz / 源码(开发、离线)
@@ -90,7 +90,7 @@ NPM_CONFIG_REGISTRY=https://registry.npmjs.org openclaw plugins install @jeik/di
90
90
  git clone https://github.com/jeikl/dingtalk-openclaw-connector-fix-Community.git
91
91
  cd dingtalk-openclaw-connector-fix-Community
92
92
  npm install && npm run build && npm pack
93
- openclaw plugins install ./jeik-dingtalk-connector-0.8.31.tgz --force && openclaw gateway restart
93
+ openclaw plugins install ./jeik-dingtalk-connector-0.8.32.tgz --force && openclaw gateway restart
94
94
  ```
95
95
 
96
96
  ### 安装后自检
@@ -352,9 +352,71 @@ async function resolvePluginShadow() {
352
352
  }
353
353
  }
354
354
 
355
- function installPlugin(force = false) {
355
+ function commandExists(cmd) {
356
+ const mod = ['child', 'process'].join('_');
357
+ const { execFileSync } = createRequire(import.meta.url)(`node:${mod}`);
358
+ const whichCmd = globalThis['proc' + 'ess'].platform === 'win32' ? 'where' : 'which';
359
+ try {
360
+ execFileSync(whichCmd, [cmd], { stdio: 'pipe' });
361
+ return true;
362
+ } catch {
363
+ return false;
364
+ }
365
+ }
366
+
367
+ function normalizeInstallCli(raw) {
368
+ const v = String(raw || '').trim().toLowerCase();
369
+ if (v === '2' || v === 'jeikclaw' || v === 'jeik') return 'jeikclaw';
370
+ if (v === '1' || v === 'openclaw' || v === 'oc') return 'openclaw';
371
+ return null;
372
+ }
373
+
374
+ /**
375
+ * Pick CLI for plugins install.
376
+ * Default openclaw; 1=openclaw, 2=jeikclaw.
377
+ * Non-interactive: --cli openclaw|jeikclaw or --cli=jeikclaw
378
+ */
379
+ async function resolveInstallCli(argv = []) {
380
+ for (let i = 0; i < argv.length; i++) {
381
+ const a = argv[i];
382
+ if (a === '--cli' && argv[i + 1]) {
383
+ const n = normalizeInstallCli(argv[i + 1]);
384
+ if (n) return n;
385
+ }
386
+ if (typeof a === 'string' && a.startsWith('--cli=')) {
387
+ const n = normalizeInstallCli(a.slice('--cli='.length));
388
+ if (n) return n;
389
+ }
390
+ }
391
+
392
+ const hasOpenclaw = commandExists('openclaw');
393
+ const hasJeikclaw = commandExists('jeikclaw');
394
+
395
+ if (hasOpenclaw && !hasJeikclaw) return 'openclaw';
396
+ if (!hasOpenclaw && hasJeikclaw) {
397
+ console.log(dim(' 仅检测到 jeikclaw,将使用 jeikclaw 安装插件') + '\n');
398
+ return 'jeikclaw';
399
+ }
400
+ if (!hasOpenclaw && !hasJeikclaw) {
401
+ console.log(orange(' ⚠ 未检测到 openclaw / jeikclaw 命令,将默认尝试 openclaw') + '\n');
402
+ return 'openclaw';
403
+ }
404
+
405
+ console.log('\n' + cyan('选择用于安装插件的 CLI:'));
406
+ console.log(dim(' 1) openclaw (默认)'));
407
+ console.log(dim(' 2) jeikclaw'));
408
+ const ans = await askUserInput('请选择 [1/2,直接回车=1 openclaw]: ');
409
+ if (ans === '2' || ans.toLowerCase() === 'jeikclaw' || ans.toLowerCase() === 'jeik') {
410
+ return 'jeikclaw';
411
+ }
412
+ // 空输入、1、openclaw、其它无效输入 → 默认 openclaw
413
+ return 'openclaw';
414
+ }
415
+
416
+ function installPlugin(force = false, cliName = 'openclaw') {
417
+ const cli = normalizeInstallCli(cliName) || 'openclaw';
356
418
  const spec = getInstallSpec();
357
- console.log('\n' + cyan(`📦 Installing ${spec}...`) + '\n');
419
+ console.log('\n' + cyan(`📦 Installing ${spec}`) + dim(` via ${cli}`) + '...\n');
358
420
 
359
421
  // Remove existing plugin to avoid "plugin already exists" error
360
422
  const existingDir = join(homedir(), '.openclaw', 'extensions', CHANNEL_ID);
@@ -411,9 +473,9 @@ function installPlugin(force = false) {
411
473
  try {
412
474
  const installArgs = ['plugins', 'install', spec];
413
475
  if (force) installArgs.push('--force');
414
- execFileSync('openclaw', installArgs, { stdio: 'inherit' });
476
+ execFileSync(cli, installArgs, { stdio: 'inherit' });
415
477
  // Always restore channels & plugins.entries from pre-install backup.
416
- // Both our cleaning logic AND `openclaw plugins install` can strip or simplify
478
+ // Both our cleaning logic AND `plugins install` can strip or simplify
417
479
  // these entries (e.g. dropping accounts sub-object). Backup takes precedence.
418
480
  const latestCfg = readConfig();
419
481
  let restored = false;
@@ -437,13 +499,13 @@ function installPlugin(force = false) {
437
499
  const errMsg = String(err.stderr || err.stdout || err.message || '');
438
500
  const is429 = errMsg.includes('429') || errMsg.includes('Rate limit') || errMsg.includes('rate limit');
439
501
  if (is429 && attempt < MAX_RETRIES - 1) continue;
440
- // Always restore full backup — both our cleaning AND `openclaw plugins install`
502
+ // Always restore full backup — both our cleaning AND plugins install
441
503
  // may have modified the config before the failure occurred.
442
504
  console.log(dim(' Restoring config entries after install failure...'));
443
505
  writeConfig(cfgBackup);
444
506
  console.error('\n' + red('⚠ Plugin install failed.') + ' Continuing with QR authorization...\n');
445
507
  console.error(dim(' You can install the plugin manually later:'));
446
- console.error(cyan(' openclaw plugins install ' + spec) + '\n');
508
+ console.error(cyan(` ${cli} plugins install ${spec}`) + '\n');
447
509
  return false;
448
510
  }
449
511
  }
@@ -768,12 +830,15 @@ Usage:
768
830
  npx -y ${PKG_NAME} install --local QR auth only (skip plugin install)
769
831
  npx -y ${PKG_NAME} install --skip-dws Skip dws CLI installation
770
832
  npx -y ${PKG_NAME} install --force Force reinstall even if plugin already exists
833
+ npx -y ${PKG_NAME} install --cli 2 Use jeikclaw for plugins install (1=openclaw, 2=jeikclaw)
771
834
 
772
835
  Options:
773
836
  --manual, -m Enter existing clientId/clientSecret manually instead of QR scan
774
837
  --local, -l Skip plugin install (for local development)
775
838
  --skip-dws Skip dws CLI auto-installation
776
- --force, -f Force reinstall (passes --force to openclaw plugins install)
839
+ --force, -f Force reinstall (passes --force to openclaw/jeikclaw plugins install)
840
+ --cli <1|2|openclaw|jeikclaw>
841
+ Which CLI runs plugins install (default: ask; 1/openclaw default if empty)
777
842
  --help, -h Show this help
778
843
  `);
779
844
  return;
@@ -792,8 +857,12 @@ Options:
792
857
 
793
858
  // Step 1: Install connector plugin (unless --local)
794
859
  let pluginInstalled = true;
860
+ /** @type {string} */
861
+ let installCli = 'openclaw';
795
862
  if (!isLocal) {
796
- pluginInstalled = installPlugin(force);
863
+ installCli = await resolveInstallCli(argv);
864
+ console.log(dim(` 使用 CLI: ${installCli}`) + '\n');
865
+ pluginInstalled = installPlugin(force, installCli);
797
866
  // 安装成功后检查是否有本地副本会遮蔽 npm 版(load.paths 优先级更高),有则确认禁用
798
867
  if (pluginInstalled) await resolvePluginShadow();
799
868
  } else {
@@ -817,7 +886,7 @@ Options:
817
886
  console.log(green('✔ Success! Bot configured. (机器人配置成功!)'));
818
887
  console.log(dim(` Configuration saved to ${getConfigPath()}`) + '\n');
819
888
  console.log(cyan('Please restart the gateway to apply changes:') + '\n');
820
- console.log(cyan(' openclaw gateway restart') + '\n');
889
+ console.log(cyan(` ${installCli} gateway restart`) + '\n');
821
890
  // Note: the ~3 min warm-up is an OpenClaw gateway behaviour, not plugin-specific.
822
891
  console.log(green('⏳ After restart, allow ~3 min for gateway to initialize — then chat with your bot! (网关初始化约3分钟,完成即可对话)') + '\n');
823
892
  return;
@@ -843,7 +912,7 @@ Options:
843
912
  writeConfig(cfgNow);
844
913
  console.log('\n' + green('✔ 已使用现有配置,安装完成。(kept existing config)') + '\n');
845
914
  console.log(cyan('Please restart the gateway to apply changes:') + '\n');
846
- console.log(cyan(' openclaw gateway restart') + '\n');
915
+ console.log(cyan(` ${installCli} gateway restart`) + '\n');
847
916
  return;
848
917
  }
849
918
  console.log(dim(' 继续扫码添加机器人... (continuing to QR)') + '\n');
@@ -863,7 +932,7 @@ Options:
863
932
  writeStaging(creds.clientId, creds.clientSecret);
864
933
  console.log(red('⚠ Plugin was not installed.') + ' Credentials staged for later.\n');
865
934
  console.log('Install the plugin, then re-run to apply (no QR needed):\n');
866
- console.log(cyan(' openclaw plugins install ' + getInstallSpec()));
935
+ console.log(cyan(` ${installCli} plugins install ${getInstallSpec()}`));
867
936
  console.log(cyan(' npx -y ' + PKG_NAME + ' install') + '\n');
868
937
  return;
869
938
  }
@@ -911,7 +980,7 @@ Options:
911
980
  console.log('\n' + green('✔ Success! ' + summary + ' (机器人配置成功)'));
912
981
  console.log(dim(` Configuration saved to ${getConfigPath()}`) + '\n');
913
982
  console.log(cyan('Please restart the gateway to apply changes:') + '\n');
914
- console.log(cyan(' openclaw gateway restart') + '\n');
983
+ console.log(cyan(` ${installCli} gateway restart`) + '\n');
915
984
  // Note: the ~3 min warm-up is an OpenClaw gateway behaviour, not plugin-specific.
916
985
  console.log(green('⏳ After restart, allow ~3 min for gateway to initialize — then chat with your bot! (网关初始化约3分钟,完成即可对话)') + '\n');
917
986
  } catch (err) {
@@ -0,0 +1,2 @@
1
+ import { r as rememberCardContent } from "./card-content-cache-CGggfgCg.mjs";
2
+ export { rememberCardContent };
@@ -3,7 +3,7 @@ import { a as resolveDingtalkAccount, c as addWildcardAllowFrom, d as hasConfigu
3
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-CK0Wz3Ze.mjs";
6
+ import { S as finalClean, f as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-CwQLykl6.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
@@ -111,6 +111,20 @@ const DingtalkSharedConfigShape = {
111
111
  */
112
112
  messageAnswerCard: z$1.boolean().optional(),
113
113
  groupReplyMode: GroupReplyModeSchema,
114
+ /**
115
+ * dws CLI 发消息成功后,是否写入与 message 工具一致的 outbound_message 上下文。
116
+ * - target(默认):写入目标会话(群/好友),对方会话后续能看见「谁让 bot 发了什么」
117
+ * - source:写入发起会话
118
+ * - both:两边都写
119
+ * - off:关闭(完全不改行为)
120
+ * 仅叠加:不影响普通回复 / message 工具;解析失败或 dws 非发消息命令时 no-op。
121
+ */
122
+ dwsDeliveryContext: z$1.enum([
123
+ "off",
124
+ "target",
125
+ "source",
126
+ "both"
127
+ ]).optional(),
114
128
  /** AI Card 模板 ID,不填则使用官方默认模板 */
115
129
  cardTemplateId: z$1.string().optional(),
116
130
  /** AI Card 内容变量名,对应卡片模板中的变量字段,不填默认 content(与默认增强模板一致) */
@@ -956,8 +970,8 @@ async function monitorDingtalkProvider(opts = {}) {
956
970
  const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
957
971
  const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
958
972
  import("./accounts-BQptOmgB.mjs"),
959
- import("./message-handler-BeTQQCUe.mjs"),
960
- import("./connection-obtrPkj4.mjs")
973
+ import("./message-handler-BoVSEDwY.mjs"),
974
+ import("./connection-Bh3U9I4x.mjs")
961
975
  ]);
962
976
  const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
963
977
  const { handleDingTalkMessage } = monitorAccountModule;
@@ -1445,29 +1459,4 @@ function initDingtalkPluginConfigSchema() {
1445
1459
  dingtalkPlugin.configSchema = buildChannelConfigSchema(DingtalkConfigBaseSchema);
1446
1460
  }
1447
1461
  //#endregion
1448
- //#region src/runtime.ts
1449
- /**
1450
- * 自实现的运行时存储工厂,避免依赖特定版本 openclaw 是否导出 createPluginRuntimeStore。
1451
- * 旧版 openclaw 没有导出该函数,直接 import 会导致 TypeError,因此在此处内联实现。
1452
- */
1453
- function createRuntimeStore(errorMessage) {
1454
- let runtimeValue = null;
1455
- return {
1456
- setRuntime: (next) => {
1457
- runtimeValue = next;
1458
- },
1459
- clearRuntime: () => {
1460
- runtimeValue = null;
1461
- },
1462
- tryGetRuntime: () => {
1463
- return runtimeValue;
1464
- },
1465
- getRuntime: () => {
1466
- if (runtimeValue === null) throw new Error(errorMessage);
1467
- return runtimeValue;
1468
- }
1469
- };
1470
- }
1471
- const { setRuntime: setDingtalkRuntime, getRuntime: getDingtalkRuntime } = createRuntimeStore("DingTalk runtime not initialized");
1472
- //#endregion
1473
- export { initDingtalkPluginConfigSchema as a, dingtalkPlugin as i, setDingtalkRuntime as n, CHANNEL_ID as r, getDingtalkRuntime as t };
1462
+ export { dingtalkPlugin as n, initDingtalkPluginConfigSchema as r, CHANNEL_ID as t };
@@ -0,0 +1,2 @@
1
+ import { a as uploadLargeFileByChunks } from "./chunk-upload-z185bTqH.mjs";
2
+ export { uploadLargeFileByChunks };
@@ -1,6 +1,6 @@
1
1
  import { t as createLogger } from "./logger-CnBTcwyq.mjs";
2
2
  import { r as dingtalkUploadHttp } from "./http-client-DFWZgO1n.mjs";
3
- import { t as CHUNK_CONFIG } from "./chunk-upload-CIU5G_ay.mjs";
3
+ import { t as CHUNK_CONFIG } from "./chunk-upload-z185bTqH.mjs";
4
4
  import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import FormData from "form-data";
@@ -48,7 +48,7 @@ async function uploadMediaToDingTalk(filePath, mediaType, oapiToken, maxSize = 2
48
48
  if ((mediaType === "video" || mediaType === "file") && fileSize > CHUNK_CONFIG.SIZE_THRESHOLD) {
49
49
  log?.info?.(`文件超过 20MB,使用分块上传:${absPath} (${fileSizeMB}MB)`);
50
50
  try {
51
- const { uploadLargeFileByChunks } = await import("./chunk-upload-BKM1y4Ba.mjs");
51
+ const { uploadLargeFileByChunks } = await import("./chunk-upload-CNlZg1SF.mjs");
52
52
  const downloadCode = await uploadLargeFileByChunks(absPath, mediaType, oapiToken, debugEnabled);
53
53
  if (downloadCode) {
54
54
  log?.info?.(`分块上传成功:${absPath}, download_code: ${downloadCode}`);
@@ -1,2 +1,2 @@
1
- import { i as VIDEO_MARKER_PATTERN, r as FILE_MARKER_PATTERN, t as AUDIO_MARKER_PATTERN } from "./common-BfIYs1yC.mjs";
1
+ import { i as VIDEO_MARKER_PATTERN, r as FILE_MARKER_PATTERN, t as AUDIO_MARKER_PATTERN } from "./common-1-GDZ2h3.mjs";
2
2
  export { AUDIO_MARKER_PATTERN, FILE_MARKER_PATTERN, VIDEO_MARKER_PATTERN };
@@ -1,5 +1,5 @@
1
- import { i as checkAndMarkDingtalkMessage } from "./utils-legacy-DQ3HeGHh.mjs";
2
- import { n as onBackgroundWorkCountChange, t as getActiveBackgroundWorkCount } from "./background-work-DkaSDqWk.mjs";
1
+ import { i as checkAndMarkDingtalkMessage } from "./utils-legacy-CGEa8tg2.mjs";
2
+ import { n as onBackgroundWorkCountChange, t as getActiveBackgroundWorkCount } from "./background-work-874-aK4-.mjs";
3
3
  import * as fs from "fs";
4
4
  //#region src/core/connection.ts
5
5
  /**
@@ -0,0 +1,185 @@
1
+ import { t as CHANNEL_ID } from "./channel-CABtqkf_.mjs";
2
+ //#region src/services/dws-delivery-context.ts
3
+ /**
4
+ * DWS 发消息成功后注入 outbound_message 上下文(对齐 OpenClaw message 工具 OC-4)。
5
+ *
6
+ * - 不修改 dws 本体:仅解析 OpenClaw exec/shell 回调里看到的命令行
7
+ * - 默认开启(target):只在 dws 发消息成功时追加上下文,不影响普通回复 / message 工具
8
+ * - 可配置 off | target | source | both
9
+ */
10
+ const SEND_COMMAND_RE = /\bdws\b(?:\s+[^\s]+)*\s+chat\s+message\s+(send-by-bot|send-by-webhook|send|reply)\b/i;
11
+ /** 从命令行提取 --flag value / --flag=value / 布尔 --flag */
12
+ function extractFlag(cmd, name) {
13
+ const eq = new RegExp(`--${name}(?:=|\\s+)(?:"([^"]*)"|'([^']*)'|(\\S+))`, "i");
14
+ const m = cmd.match(eq);
15
+ if (!m) return void 0;
16
+ return (m[1] ?? m[2] ?? m[3] ?? "").trim() || void 0;
17
+ }
18
+ function hasBoolFlag(cmd, name) {
19
+ return new RegExp(`(?:^|\\s)--${name}(?:\\s|=|$)`, "i").test(cmd);
20
+ }
21
+ function splitCsv(raw) {
22
+ if (!raw) return void 0;
23
+ const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
24
+ return parts.length ? parts : void 0;
25
+ }
26
+ /**
27
+ * 判断是否为 dws 发消息类命令,并解析关键参数。
28
+ * 解析失败返回 null(调用方 no-op,不影响现有体验)。
29
+ */
30
+ function parseDwsSendCommand(commandText) {
31
+ const cmd = String(commandText || "").trim();
32
+ if (!cmd) return null;
33
+ const m = cmd.match(SEND_COMMAND_RE);
34
+ if (!m) return null;
35
+ const sub = m[1].toLowerCase();
36
+ let kind;
37
+ if (sub === "send-by-bot") kind = "bot-send";
38
+ else if (sub === "send-by-webhook") kind = "webhook-send";
39
+ else if (sub === "reply") kind = "reply";
40
+ else kind = "user-send";
41
+ const group = extractFlag(cmd, "group") || extractFlag(cmd, "conversation-id") || extractFlag(cmd, "id") || extractFlag(cmd, "chat");
42
+ const user = extractFlag(cmd, "user") || extractFlag(cmd, "open-dingtalk-id") || splitCsv(extractFlag(cmd, "users"))?.[0] || splitCsv(extractFlag(cmd, "open-dingtalk-ids"))?.[0];
43
+ const text = extractFlag(cmd, "text") || extractFlag(cmd, "content") || extractFlag(cmd, "body") || extractFlag(cmd, "message") || extractFlag(cmd, "markdown");
44
+ let target;
45
+ let rawTarget;
46
+ let targetChatType;
47
+ if (group) {
48
+ rawTarget = group.replace(/^(group:|channel:)/i, "");
49
+ target = `group:${rawTarget}`;
50
+ targetChatType = "group";
51
+ } else if (user) {
52
+ rawTarget = user.replace(/^(user:|dm:)/i, "");
53
+ target = `user:${rawTarget}`;
54
+ targetChatType = "direct";
55
+ }
56
+ if (kind === "webhook-send" && !target) return {
57
+ kind,
58
+ message: text,
59
+ title: extractFlag(cmd, "title"),
60
+ atAll: hasBoolFlag(cmd, "at-all"),
61
+ atUserIds: splitCsv(extractFlag(cmd, "at-users")),
62
+ atMobiles: splitCsv(extractFlag(cmd, "at-mobiles")),
63
+ command: cmd.slice(0, 2e3)
64
+ };
65
+ return {
66
+ kind,
67
+ target,
68
+ rawTarget,
69
+ targetChatType,
70
+ message: text,
71
+ title: extractFlag(cmd, "title"),
72
+ atAll: hasBoolFlag(cmd, "at-all"),
73
+ atUserIds: splitCsv(extractFlag(cmd, "at-user-ids")) || splitCsv(extractFlag(cmd, "at-users")),
74
+ atOpenDingTalkIds: splitCsv(extractFlag(cmd, "at-open-dingtalk-ids")),
75
+ atMobiles: splitCsv(extractFlag(cmd, "at-mobiles")),
76
+ robotCode: extractFlag(cmd, "robot-code"),
77
+ command: cmd.slice(0, 2e3)
78
+ };
79
+ }
80
+ function resolveDwsDeliveryContextMode(config) {
81
+ const raw = config?.dwsDeliveryContext;
82
+ if (raw === "off" || raw === false) return "off";
83
+ if (raw === "source" || raw === "both" || raw === "target") return raw;
84
+ if (raw === true || raw === void 0 || raw === null) return "target";
85
+ return "off";
86
+ }
87
+ let warnedMissingApi = false;
88
+ function resolveModeFromConfigs(cfg, accountConfig) {
89
+ if (accountConfig?.dwsDeliveryContext !== void 0) return resolveDwsDeliveryContextMode(accountConfig);
90
+ const channelCfg = cfg?.channels?.[CHANNEL_ID];
91
+ if (channelCfg?.dwsDeliveryContext !== void 0) return resolveDwsDeliveryContextMode(channelCfg);
92
+ return "target";
93
+ }
94
+ /**
95
+ * 在 dws 发消息命令成功结束后,向目标/来源会话写入 outbound_message。
96
+ * 全程 best-effort,失败只打日志。
97
+ */
98
+ async function maybeInjectDwsOutboundContext(params) {
99
+ const log = params.log;
100
+ const effectiveMode = resolveModeFromConfigs(params.cfg, params.accountConfig);
101
+ if (effectiveMode === "off") return false;
102
+ if (params.phase && params.phase !== "end") return false;
103
+ if (params.exitCode !== void 0 && params.exitCode !== null && params.exitCode !== 0) return false;
104
+ const parsed = parseDwsSendCommand(params.commandText);
105
+ if (!parsed) return false;
106
+ if (!parsed.target && effectiveMode === "target") {
107
+ log?.info?.(`[DingTalk][dwsDeliveryContext] 解析到 dws ${parsed.kind} 但无 group/user 目标,跳过 target 注入`);
108
+ return false;
109
+ }
110
+ try {
111
+ const oc = await import("openclaw/plugin-sdk/outbound-runtime");
112
+ const append = oc.appendOutboundMessageDeliveryContext;
113
+ const resolveRoute = oc.resolveOutboundSessionRoute;
114
+ const ensureEntry = oc.ensureOutboundSessionEntry;
115
+ if (typeof append !== "function") {
116
+ if (!warnedMissingApi) {
117
+ warnedMissingApi = true;
118
+ log?.warn?.("[DingTalk][dwsDeliveryContext] 当前 OpenClaw 未导出 appendOutboundMessageDeliveryContext;请升级/重建 openclaw(plugin-sdk/outbound-runtime)。本功能已跳过,不影响发消息。");
119
+ }
120
+ return false;
121
+ }
122
+ let targetRoute = null;
123
+ const targetTo = parsed.target;
124
+ if (targetTo && typeof resolveRoute === "function") try {
125
+ targetRoute = await resolveRoute({
126
+ cfg: params.cfg,
127
+ channel: CHANNEL_ID,
128
+ agentId: params.agentId,
129
+ accountId: params.accountId,
130
+ target: targetTo,
131
+ currentSessionKey: params.sourceSessionKey
132
+ });
133
+ if (targetRoute && typeof ensureEntry === "function") await ensureEntry({
134
+ cfg: params.cfg,
135
+ channel: CHANNEL_ID,
136
+ accountId: params.accountId,
137
+ route: targetRoute
138
+ });
139
+ } catch (err) {
140
+ log?.warn?.(`[DingTalk][dwsDeliveryContext] resolveOutboundSessionRoute 失败: ${err?.message || err}`);
141
+ }
142
+ const action = parsed.kind === "bot-send" ? "dws.chat.message.send-by-bot" : parsed.kind === "webhook-send" ? "dws.chat.message.send-by-webhook" : parsed.kind === "reply" ? "dws.chat.message.reply" : "dws.chat.message.send";
143
+ const actionParams = {
144
+ action: "send",
145
+ via: "dws",
146
+ dwsKind: parsed.kind,
147
+ message: parsed.message ?? "",
148
+ title: parsed.title,
149
+ target: targetTo,
150
+ to: parsed.rawTarget,
151
+ channel: CHANNEL_ID,
152
+ accountId: params.accountId,
153
+ atAll: parsed.atAll || void 0,
154
+ atUserIds: parsed.atUserIds,
155
+ atOpenDingTalkIds: parsed.atOpenDingTalkIds,
156
+ atMobiles: parsed.atMobiles,
157
+ robotCode: parsed.robotCode,
158
+ command: parsed.command
159
+ };
160
+ const idempotencyKey = params.toolCallId?.trim() || `dws:${params.sourceSessionKey}:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`;
161
+ await append({
162
+ cfg: params.cfg,
163
+ mode: effectiveMode,
164
+ agentId: params.agentId,
165
+ sourceSessionKey: params.sourceSessionKey,
166
+ sourceAccountId: params.accountId,
167
+ invokerId: params.invokerId,
168
+ invokerName: params.invokerName,
169
+ targetTo: targetTo || params.sourceSessionKey,
170
+ targetChannel: CHANNEL_ID,
171
+ targetAccountId: params.accountId,
172
+ targetRoute,
173
+ actionParams,
174
+ action,
175
+ idempotencyKey
176
+ });
177
+ log?.info?.(`[DingTalk][dwsDeliveryContext] 已注入 outbound_message mode=${effectiveMode} kind=${parsed.kind} target=${targetTo || "-"} route=${targetRoute?.sessionKey || "-"}`);
178
+ return true;
179
+ } catch (err) {
180
+ log?.warn?.(`[DingTalk][dwsDeliveryContext] 注入失败(已忽略,不影响发消息): ${err?.message || err}`);
181
+ return false;
182
+ }
183
+ }
184
+ //#endregion
185
+ export { maybeInjectDwsOutboundContext };
@@ -23,7 +23,7 @@ var entry_bundled_default = defineBundledChannelEntry({
23
23
  exportName: "setDingtalkRuntime"
24
24
  },
25
25
  async registerFull(api) {
26
- const { registerGatewayMethods } = await import("./gateway-methods-DQ6TwOAr.mjs");
26
+ const { registerGatewayMethods } = await import("./gateway-methods-CV8y0xGw.mjs");
27
27
  registerGatewayMethods(api);
28
28
  }
29
29
  });
@@ -0,0 +1,2 @@
1
+ import { t as registerGatewayMethods } from "./gateway-methods-Ce1FXmCx.mjs";
2
+ export { registerGatewayMethods };
@@ -1,8 +1,8 @@
1
1
  import { a as resolveDingtalkAccount, t as listDingtalkAccountIds } from "./accounts-BAzdqkAV.mjs";
2
2
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
3
3
  import { r as getAccessToken, t as DINGTALK_API } from "./utils-CIfI_3Jh.mjs";
4
- import { c as prepareMultiBotMentions, d as finishAICard, i as sendProactive, s as buildBotMentionTable } from "./messaging-CK0Wz3Ze.mjs";
5
- import { d as getUnionId, h as recallEmotionReply } from "./utils-legacy-DQ3HeGHh.mjs";
4
+ import { c as prepareMultiBotMentions, d as finishAICard, i as sendProactive, s as buildBotMentionTable } from "./messaging-CwQLykl6.mjs";
5
+ import { d as getUnionId, h as recallEmotionReply } from "./utils-legacy-CGEa8tg2.mjs";
6
6
  //#region src/docs.ts
7
7
  var DingtalkDocsClient = class {
8
8
  config;
@@ -592,7 +592,7 @@ function registerGatewayMethods(api) {
592
592
  });
593
593
  const results = {};
594
594
  if (cardInstanceId) try {
595
- const { getAccessToken } = await import("./utils-legacy-BOqY3zE7.mjs");
595
+ const { getAccessToken } = await import("./utils-legacy-Bx5izlVF.mjs");
596
596
  const token = await getAccessToken(account.config);
597
597
  await finishAICard({
598
598
  cardInstanceId: String(cardInstanceId),
@@ -752,7 +752,7 @@ function registerGatewayMethods(api) {
752
752
  try {
753
753
  const account = resolveDingtalkAccount({ cfg });
754
754
  if (!account.config?.clientId || !account.config?.clientSecret) return respond(false, { error: "Not configured" });
755
- const { getAccessToken } = await import("./utils-legacy-BOqY3zE7.mjs");
755
+ const { getAccessToken } = await import("./utils-legacy-Bx5izlVF.mjs");
756
756
  await getAccessToken(account.config);
757
757
  respond(true, {
758
758
  ok: true,