@jeik/dingtalk-connector 0.8.34 → 0.8.36

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 CHANGED
@@ -5,6 +5,12 @@ 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.35] - 2026-07-31
9
+
10
+ ### Fixes
11
+
12
+ - **outbound-runtime 降级顺序明确为 openclaw → jeikclaw** — 包名 import、createRequire、全局 node_modules 均优先 `openclaw`,失败再试 `jeikclaw`;gateway 入口旁 filesystem 仅作最后兜底。
13
+
8
14
  ## [0.8.34] - 2026-07-31
9
15
 
10
16
  ### Fixes
File without changes
@@ -970,7 +970,7 @@ async function monitorDingtalkProvider(opts = {}) {
970
970
  const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
971
971
  const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
972
972
  import("./accounts-BQptOmgB.mjs"),
973
- import("./message-handler-Dsyk414y.mjs"),
973
+ import("./message-handler-0LEoMD85.mjs"),
974
974
  import("./connection-Bh3U9I4x.mjs")
975
975
  ]);
976
976
  const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
@@ -1,4 +1,4 @@
1
- import { t as CHANNEL_ID } from "./channel-HfPzJGwO.mjs";
1
+ import { t as CHANNEL_ID } from "./channel-B56QFS9m.mjs";
2
2
  //#region src/services/dws-delivery-context.ts
3
3
  /**
4
4
  * DWS 发消息成功后注入 outbound_message 上下文(对齐 OpenClaw message 工具 OC-4)。
@@ -103,80 +103,99 @@ function resolveModeFromConfigs(cfg, accountConfig) {
103
103
  return "target";
104
104
  }
105
105
  /**
106
+ * 尝试 import 一个候选并校验 append 导出。
107
+ * 成功返回 API;失败返回 null(由调用方继续降级)。
108
+ */
109
+ async function tryImportOutboundRuntime(id, errors) {
110
+ try {
111
+ const oc = await import(id);
112
+ if (typeof oc.appendOutboundMessageDeliveryContext !== "function") {
113
+ errors.push(`${id}: no appendOutboundMessageDeliveryContext`);
114
+ return null;
115
+ }
116
+ return {
117
+ append: oc.appendOutboundMessageDeliveryContext.bind(oc),
118
+ resolveRoute: typeof oc.resolveOutboundSessionRoute === "function" ? oc.resolveOutboundSessionRoute.bind(oc) : void 0,
119
+ ensureEntry: typeof oc.ensureOutboundSessionEntry === "function" ? oc.ensureOutboundSessionEntry.bind(oc) : void 0,
120
+ via: id
121
+ };
122
+ } catch (e) {
123
+ errors.push(`${id}: ${e?.message || e}`);
124
+ return null;
125
+ }
126
+ }
127
+ /**
106
128
  * 加载 OC-4 append API。
107
129
  *
108
- * 注意:钉钉插件装在 ~/.openclaw/npm/projects/... 下,Node 从插件路径
109
- * 解析不到名为 openclaw/jeikclaw package(包名还可能是 jeikclaw)。
110
- * 必须用 gateway 进程入口(process.argv[1])定位 dist/plugin-sdk。
130
+ * 降级策略(严格优先 openclaw,导不进去再 jeikclaw):
131
+ * 1) 包名 import:openclaw/* jeikclaw/*
132
+ * 2) createRequire gateway 入口 resolve 包:openclaw → jeikclaw
133
+ * 3) 文件系统:gateway argv[1] 旁 dist/plugin-sdk(不区分包名,作最后兜底)
134
+ * 4) 全局 node_modules:openclaw → jeikclaw
135
+ *
136
+ * 插件装在 ~/.openclaw/npm/projects/... 时,裸 import 包名常失败,
137
+ * 因此 2/4 会用 gateway 入口 / 全局路径再试一遍。
111
138
  */
112
139
  async function loadOutboundRuntime() {
113
140
  const { pathToFileURL } = await import("node:url");
114
141
  const path = await import("node:path");
115
142
  const fs = await import("node:fs");
116
143
  const { createRequire } = await import("node:module");
117
- const candidates = [
118
- "openclaw/plugin-sdk/outbound-runtime",
119
- "jeikclaw/plugin-sdk/outbound-runtime",
120
- "jeikclaw/dist/plugin-sdk/outbound-runtime.js",
121
- "openclaw/dist/plugin-sdk/outbound-runtime.js"
122
- ];
123
- const pushIfExists = (filePath) => {
124
- try {
125
- if (filePath && fs.existsSync(filePath)) candidates.push(pathToFileURL(filePath).href);
126
- } catch {}
144
+ const errors = [];
145
+ const seen = /* @__PURE__ */ new Set();
146
+ const tryOne = async (id) => {
147
+ if (!id || seen.has(id)) return null;
148
+ seen.add(id);
149
+ return tryImportOutboundRuntime(id, errors);
127
150
  };
151
+ for (const pkg of ["openclaw", "jeikclaw"]) for (const sub of [`${pkg}/plugin-sdk/outbound-runtime`, `${pkg}/dist/plugin-sdk/outbound-runtime.js`]) {
152
+ const hit = await tryOne(sub);
153
+ if (hit) return hit;
154
+ }
128
155
  const entry = typeof process.argv[1] === "string" ? process.argv[1] : "";
156
+ if (entry) try {
157
+ const req = createRequire(pathToFileURL(path.resolve(entry)).href);
158
+ for (const pkg of ["openclaw", "jeikclaw"]) try {
159
+ const pkgJson = req.resolve(`${pkg}/package.json`);
160
+ const root = path.dirname(pkgJson);
161
+ const file = path.join(root, "dist", "plugin-sdk", "outbound-runtime.js");
162
+ if (fs.existsSync(file)) {
163
+ const hit = await tryOne(pathToFileURL(file).href);
164
+ if (hit) return hit;
165
+ }
166
+ } catch {}
167
+ } catch {}
129
168
  if (entry) {
130
169
  const entryDir = path.dirname(path.resolve(entry));
131
- pushIfExists(path.join(entryDir, "plugin-sdk", "outbound-runtime.js"));
132
- pushIfExists(path.join(entryDir, "dist", "plugin-sdk", "outbound-runtime.js"));
170
+ const fileCandidates = [path.join(entryDir, "plugin-sdk", "outbound-runtime.js"), path.join(entryDir, "dist", "plugin-sdk", "outbound-runtime.js")];
133
171
  let dir = entryDir;
134
172
  for (let i = 0; i < 5; i++) {
135
- const pkgJson = path.join(dir, "package.json");
136
- if (fs.existsSync(pkgJson)) {
137
- pushIfExists(path.join(dir, "dist", "plugin-sdk", "outbound-runtime.js"));
138
- pushIfExists(path.join(dir, "plugin-sdk", "outbound-runtime.js"));
173
+ if (fs.existsSync(path.join(dir, "package.json"))) {
174
+ fileCandidates.push(path.join(dir, "dist", "plugin-sdk", "outbound-runtime.js"), path.join(dir, "plugin-sdk", "outbound-runtime.js"));
139
175
  break;
140
176
  }
141
177
  const parent = path.dirname(dir);
142
178
  if (parent === dir) break;
143
179
  dir = parent;
144
180
  }
145
- try {
146
- const req = createRequire(pathToFileURL(path.resolve(entry)).href);
147
- for (const name of ["jeikclaw", "openclaw"]) try {
148
- const pkgJson = req.resolve(`${name}/package.json`);
149
- const root = path.dirname(pkgJson);
150
- pushIfExists(path.join(root, "dist", "plugin-sdk", "outbound-runtime.js"));
151
- } catch {}
152
- } catch {}
181
+ for (const file of fileCandidates) if (fs.existsSync(file)) {
182
+ const hit = await tryOne(pathToFileURL(file).href);
183
+ if (hit) return hit;
184
+ }
153
185
  }
154
186
  try {
155
187
  const execDir = path.dirname(process.execPath);
156
- pushIfExists(path.join(execDir, "..", "lib", "node_modules", "jeikclaw", "dist", "plugin-sdk", "outbound-runtime.js"));
157
- pushIfExists(path.join(execDir, "..", "lib", "node_modules", "openclaw", "dist", "plugin-sdk", "outbound-runtime.js"));
158
- } catch {}
159
- const errors = [];
160
- const seen = /* @__PURE__ */ new Set();
161
- for (const id of candidates) {
162
- if (!id || seen.has(id)) continue;
163
- seen.add(id);
164
- try {
165
- const oc = await import(id);
166
- if (typeof oc.appendOutboundMessageDeliveryContext === "function") return {
167
- append: oc.appendOutboundMessageDeliveryContext.bind(oc),
168
- resolveRoute: typeof oc.resolveOutboundSessionRoute === "function" ? oc.resolveOutboundSessionRoute.bind(oc) : void 0,
169
- ensureEntry: typeof oc.ensureOutboundSessionEntry === "function" ? oc.ensureOutboundSessionEntry.bind(oc) : void 0,
170
- via: id
171
- };
172
- errors.push(`${id}: no append export`);
173
- } catch (e) {
174
- errors.push(`${id}: ${e?.message || e}`);
188
+ for (const pkg of ["openclaw", "jeikclaw"]) {
189
+ const file = path.join(execDir, "..", "lib", "node_modules", pkg, "dist", "plugin-sdk", "outbound-runtime.js");
190
+ if (fs.existsSync(file)) {
191
+ const hit = await tryOne(pathToFileURL(file).href);
192
+ if (hit) return hit;
193
+ }
175
194
  }
176
- }
195
+ } catch {}
177
196
  if (!warnedMissingApi) {
178
197
  warnedMissingApi = true;
179
- alwaysLog("warn", `无法加载 outbound-runtimeargv1=${entry || "-"} tried=${seen.size} err=${errors.slice(0, 4).join(" | ")}`);
198
+ alwaysLog("warn", `无法加载 outbound-runtime(openclaw→jeikclaw 均失败)。argv1=${entry || "-"} tried=${seen.size} err=${errors.slice(0, 4).join(" | ")}`);
180
199
  }
181
200
  return null;
182
201
  }
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as dingtalkPlugin, r as initDingtalkPluginConfigSchema } from "./channel-HfPzJGwO.mjs";
1
+ import { n as dingtalkPlugin, r as initDingtalkPluginConfigSchema } from "./channel-B56QFS9m.mjs";
2
2
  import { n as setDingtalkRuntime } from "./runtime-DDMzayvA.mjs";
3
3
  import { t as registerGatewayMethods } from "./gateway-methods-Ce1FXmCx.mjs";
4
4
  //#region index.ts
@@ -1,5 +1,5 @@
1
1
  import { a as resolveDingtalkAccount } from "./accounts-BAzdqkAV.mjs";
2
- import { t as CHANNEL_ID } from "./channel-HfPzJGwO.mjs";
2
+ import { t as CHANNEL_ID } from "./channel-B56QFS9m.mjs";
3
3
  import { n as createLoggerFromConfig, r as isDingtalkDebug } from "./logger-CnBTcwyq.mjs";
4
4
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
5
5
  import { i as getOapiAccessToken } from "./utils-CIfI_3Jh.mjs";
@@ -1036,7 +1036,7 @@ function createDingtalkReplyDispatcher(params) {
1036
1036
  payload.output,
1037
1037
  commandText
1038
1038
  ].filter(Boolean).join("\n") || "";
1039
- if (/\bdws\b/i.test(fullCmd)) import("./dws-delivery-context-DLR1ghNQ.mjs").then(({ maybeInjectDwsOutboundContext }) => maybeInjectDwsOutboundContext({
1039
+ if (/\bdws\b/i.test(fullCmd)) import("./dws-delivery-context-ZJalcxYA.mjs").then(({ maybeInjectDwsOutboundContext }) => maybeInjectDwsOutboundContext({
1040
1040
  cfg,
1041
1041
  accountConfig: account.config,
1042
1042
  agentId,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "dingtalk-connector",
3
3
  "name": "DingTalk Channel",
4
- "version": "0.8.34",
4
+ "version": "0.8.36",
5
5
  "description": "OpenClaw DingTalk channel plugin (community) | 钉钉 OpenClaw 社区增强版",
6
6
  "author": "jeik",
7
7
  "main": "index.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeik/dingtalk-connector",
3
- "version": "0.8.34",
3
+ "version": "0.8.36",
4
4
  "description": "OpenClaw DingTalk channel plugin (community) | 钉钉 OpenClaw 社区增强版(基于官方 0.8.24,长连接与消息体验增强)",
5
5
  "type": "module",
6
6
  "exports": {
File without changes
@@ -193,124 +193,163 @@ function resolveModeFromConfigs(cfg: any, accountConfig?: any): DwsDeliveryConte
193
193
  return "target";
194
194
  }
195
195
 
196
+ type OutboundRuntimeApi = {
197
+ append: (p: any) => Promise<void>;
198
+ resolveRoute?: (p: any) => Promise<any>;
199
+ ensureEntry?: (p: any) => Promise<void>;
200
+ via: string;
201
+ };
202
+
203
+ /**
204
+ * 尝试 import 一个候选并校验 append 导出。
205
+ * 成功返回 API;失败返回 null(由调用方继续降级)。
206
+ */
207
+ async function tryImportOutboundRuntime(
208
+ id: string,
209
+ errors: string[],
210
+ ): Promise<OutboundRuntimeApi | null> {
211
+ try {
212
+ const oc: any = await import(id);
213
+ if (typeof oc.appendOutboundMessageDeliveryContext !== "function") {
214
+ errors.push(`${id}: no appendOutboundMessageDeliveryContext`);
215
+ return null;
216
+ }
217
+ return {
218
+ append: oc.appendOutboundMessageDeliveryContext.bind(oc),
219
+ resolveRoute:
220
+ typeof oc.resolveOutboundSessionRoute === "function"
221
+ ? oc.resolveOutboundSessionRoute.bind(oc)
222
+ : undefined,
223
+ ensureEntry:
224
+ typeof oc.ensureOutboundSessionEntry === "function"
225
+ ? oc.ensureOutboundSessionEntry.bind(oc)
226
+ : undefined,
227
+ via: id,
228
+ };
229
+ } catch (e: any) {
230
+ errors.push(`${id}: ${e?.message || e}`);
231
+ return null;
232
+ }
233
+ }
234
+
196
235
  /**
197
236
  * 加载 OC-4 append API。
198
237
  *
199
- * 注意:钉钉插件装在 ~/.openclaw/npm/projects/... 下,Node 从插件路径
200
- * 解析不到名为 openclaw/jeikclaw package(包名还可能是 jeikclaw)。
201
- * 必须用 gateway 进程入口(process.argv[1])定位 dist/plugin-sdk。
238
+ * 降级策略(严格优先 openclaw,导不进去再 jeikclaw):
239
+ * 1) 包名 import:openclaw/* jeikclaw/*
240
+ * 2) createRequire gateway 入口 resolve 包:openclaw → jeikclaw
241
+ * 3) 文件系统:gateway argv[1] 旁 dist/plugin-sdk(不区分包名,作最后兜底)
242
+ * 4) 全局 node_modules:openclaw → jeikclaw
243
+ *
244
+ * 插件装在 ~/.openclaw/npm/projects/... 时,裸 import 包名常失败,
245
+ * 因此 2/4 会用 gateway 入口 / 全局路径再试一遍。
202
246
  */
203
- async function loadOutboundRuntime(): Promise<{
204
- append?: (p: any) => Promise<void>;
205
- resolveRoute?: (p: any) => Promise<any>;
206
- ensureEntry?: (p: any) => Promise<void>;
207
- via?: string;
208
- } | null> {
247
+ async function loadOutboundRuntime(): Promise<OutboundRuntimeApi | null> {
209
248
  const { pathToFileURL } = await import("node:url");
210
249
  const path = await import("node:path");
211
250
  const fs = await import("node:fs");
212
251
  const { createRequire } = await import("node:module");
213
252
 
214
- const candidates: string[] = [
215
- "openclaw/plugin-sdk/outbound-runtime",
216
- "jeikclaw/plugin-sdk/outbound-runtime",
217
- "jeikclaw/dist/plugin-sdk/outbound-runtime.js",
218
- "openclaw/dist/plugin-sdk/outbound-runtime.js",
219
- ];
253
+ const errors: string[] = [];
254
+ const seen = new Set<string>();
255
+
256
+ const tryOne = async (id: string): Promise<OutboundRuntimeApi | null> => {
257
+ if (!id || seen.has(id)) return null;
258
+ seen.add(id);
259
+ return tryImportOutboundRuntime(id, errors);
260
+ };
261
+
262
+ // ── 1) 包名 import:openclaw 优先,失败再 jeikclaw ──
263
+ for (const pkg of ["openclaw", "jeikclaw"] as const) {
264
+ for (const sub of [
265
+ `${pkg}/plugin-sdk/outbound-runtime`,
266
+ `${pkg}/dist/plugin-sdk/outbound-runtime.js`,
267
+ ]) {
268
+ const hit = await tryOne(sub);
269
+ if (hit) return hit;
270
+ }
271
+ }
272
+
273
+ const entry = typeof process.argv[1] === "string" ? process.argv[1] : "";
220
274
 
221
- const pushIfExists = (filePath: string) => {
275
+ // ── 2) gateway 入口 createRequire:openclaw 优先,再 jeikclaw ──
276
+ if (entry) {
222
277
  try {
223
- if (filePath && fs.existsSync(filePath)) {
224
- candidates.push(pathToFileURL(filePath).href);
278
+ const req = createRequire(pathToFileURL(path.resolve(entry)).href);
279
+ for (const pkg of ["openclaw", "jeikclaw"] as const) {
280
+ try {
281
+ const pkgJson = req.resolve(`${pkg}/package.json`);
282
+ const root = path.dirname(pkgJson);
283
+ const file = path.join(root, "dist", "plugin-sdk", "outbound-runtime.js");
284
+ if (fs.existsSync(file)) {
285
+ const hit = await tryOne(pathToFileURL(file).href);
286
+ if (hit) return hit;
287
+ }
288
+ } catch {
289
+ /* 该包名 resolve 失败,试下一个 */
290
+ }
225
291
  }
226
292
  } catch {
227
293
  /* ignore */
228
294
  }
229
- };
295
+ }
230
296
 
231
- // gateway 入口通常是 .../jeikclaw/dist/index.js 或 openclaw.mjs
232
- const entry = typeof process.argv[1] === "string" ? process.argv[1] : "";
297
+ // ── 3) 文件系统兜底:gateway 入口旁(运行中的就是这份 dist)──
233
298
  if (entry) {
234
299
  const entryDir = path.dirname(path.resolve(entry));
235
- // .../dist/index.js .../dist/plugin-sdk/outbound-runtime.js
236
- pushIfExists(path.join(entryDir, "plugin-sdk", "outbound-runtime.js"));
237
- // .../openclaw.mjs .../dist/plugin-sdk/...
238
- pushIfExists(path.join(entryDir, "dist", "plugin-sdk", "outbound-runtime.js"));
239
- // 再向上找 package root
300
+ const fileCandidates = [
301
+ path.join(entryDir, "plugin-sdk", "outbound-runtime.js"),
302
+ path.join(entryDir, "dist", "plugin-sdk", "outbound-runtime.js"),
303
+ ];
240
304
  let dir = entryDir;
241
305
  for (let i = 0; i < 5; i++) {
242
- const pkgJson = path.join(dir, "package.json");
243
- if (fs.existsSync(pkgJson)) {
244
- pushIfExists(path.join(dir, "dist", "plugin-sdk", "outbound-runtime.js"));
245
- pushIfExists(path.join(dir, "plugin-sdk", "outbound-runtime.js"));
306
+ if (fs.existsSync(path.join(dir, "package.json"))) {
307
+ fileCandidates.push(
308
+ path.join(dir, "dist", "plugin-sdk", "outbound-runtime.js"),
309
+ path.join(dir, "plugin-sdk", "outbound-runtime.js"),
310
+ );
246
311
  break;
247
312
  }
248
313
  const parent = path.dirname(dir);
249
314
  if (parent === dir) break;
250
315
  dir = parent;
251
316
  }
252
-
253
- // createRequire 从 gateway 入口解析 package 名
254
- try {
255
- const req = createRequire(pathToFileURL(path.resolve(entry)).href);
256
- for (const name of ["jeikclaw", "openclaw"]) {
257
- try {
258
- const pkgJson = req.resolve(`${name}/package.json`);
259
- const root = path.dirname(pkgJson);
260
- pushIfExists(path.join(root, "dist", "plugin-sdk", "outbound-runtime.js"));
261
- } catch {
262
- /* ignore */
263
- }
317
+ for (const file of fileCandidates) {
318
+ if (fs.existsSync(file)) {
319
+ const hit = await tryOne(pathToFileURL(file).href);
320
+ if (hit) return hit;
264
321
  }
265
- } catch {
266
- /* ignore */
267
322
  }
268
323
  }
269
324
 
270
- // 也试 process.execPath 同级的全局 node_modules
325
+ // ── 4) 全局 node_modules:openclaw 优先,再 jeikclaw ──
271
326
  try {
272
327
  const execDir = path.dirname(process.execPath);
273
- pushIfExists(
274
- path.join(execDir, "..", "lib", "node_modules", "jeikclaw", "dist", "plugin-sdk", "outbound-runtime.js"),
275
- );
276
- pushIfExists(
277
- path.join(execDir, "..", "lib", "node_modules", "openclaw", "dist", "plugin-sdk", "outbound-runtime.js"),
278
- );
328
+ for (const pkg of ["openclaw", "jeikclaw"] as const) {
329
+ const file = path.join(
330
+ execDir,
331
+ "..",
332
+ "lib",
333
+ "node_modules",
334
+ pkg,
335
+ "dist",
336
+ "plugin-sdk",
337
+ "outbound-runtime.js",
338
+ );
339
+ if (fs.existsSync(file)) {
340
+ const hit = await tryOne(pathToFileURL(file).href);
341
+ if (hit) return hit;
342
+ }
343
+ }
279
344
  } catch {
280
345
  /* ignore */
281
346
  }
282
347
 
283
- const errors: string[] = [];
284
- const seen = new Set<string>();
285
- for (const id of candidates) {
286
- if (!id || seen.has(id)) continue;
287
- seen.add(id);
288
- try {
289
- const oc: any = await import(id);
290
- if (typeof oc.appendOutboundMessageDeliveryContext === "function") {
291
- return {
292
- append: oc.appendOutboundMessageDeliveryContext.bind(oc),
293
- resolveRoute:
294
- typeof oc.resolveOutboundSessionRoute === "function"
295
- ? oc.resolveOutboundSessionRoute.bind(oc)
296
- : undefined,
297
- ensureEntry:
298
- typeof oc.ensureOutboundSessionEntry === "function"
299
- ? oc.ensureOutboundSessionEntry.bind(oc)
300
- : undefined,
301
- via: id,
302
- };
303
- }
304
- errors.push(`${id}: no append export`);
305
- } catch (e: any) {
306
- errors.push(`${id}: ${e?.message || e}`);
307
- }
308
- }
309
348
  if (!warnedMissingApi) {
310
349
  warnedMissingApi = true;
311
350
  alwaysLog(
312
351
  "warn",
313
- `无法加载 outbound-runtimeargv1=${entry || "-"} tried=${seen.size} err=${errors.slice(0, 4).join(" | ")}`,
352
+ `无法加载 outbound-runtime(openclaw→jeikclaw 均失败)。argv1=${entry || "-"} tried=${seen.size} err=${errors.slice(0, 4).join(" | ")}`,
314
353
  );
315
354
  }
316
355
  return null;
File without changes
File without changes