@jeik/dingtalk-connector 0.8.21-fix46 → 0.8.21-fix47

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,18 @@ 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.21-fix47] - 2026-07-20
9
+
10
+ ### 修复 / Fixed
11
+ - 🐛 **`file://` 本地图被误判为远程** — `looksLikeRemoteUrl` 对含 `://` 一律当远程,导致 `![x](file:///mnt/...)` / `file:///root/...` 走 `fetch` → `fetch failed`,原样发出灰图。现:`file://` / `MEDIA:` / `attachment://` **优先按本地上传**(`toLocalPath` 后 oapi)。
12
+ 日志特征(fix46):`kind=http path=file://...` + `远程图下载异常 | fetch failed` + `localTried=0`。
13
+
14
+ ### 安装 / Install
15
+ ```bash
16
+ npx -y @jeik/dingtalk-connector install --force
17
+ openclaw gateway restart
18
+ ```
19
+
8
20
  ## [0.8.21-fix46] - 2026-07-20
9
21
 
10
22
  ### 诊断 / Diagnostics
package/README.en.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <p>Community maintained fork of the official <strong>v0.8.20</strong> release, tracking and fixing bugs the official team hasn't addressed.<br/>
5
5
  Identical to the official release in functionality — only community-critical fixes applied.</p>
6
6
 
7
- <p><strong>Current published release: <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix46</strong> (production-stable; install: <code>npx -y @jeik/dingtalk-connector install</code>).</p>
7
+ <p><strong>Current published release: <a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix47</strong> (production-stable; install: <code>npx -y @jeik/dingtalk-connector install</code>).</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,19 +23,22 @@
23
23
 
24
24
  ## 🔧 Recent Updates
25
25
 
26
- ### 🚀 v0.8.21-fix46 · 2026-07-20 (current)
26
+ ### 🚀 v0.8.21-fix47 · 2026-07-20 (current)
27
27
 
28
- **Theme: always-on local MD image diagnostics (behavior same as fix45)**
28
+ **Theme: fix `file://` misclassified as remote URL**
29
29
 
30
30
  | | Change |
31
31
  |--|--------|
32
- | 🔍 **LocalImage logs** | message path: scan / exists / upload / residual |
33
- | 🔍 **MediaIdTrace** | `mdImgs`, `residualLocal`, API-before preview |
32
+ | 🐛 **`file://` grey images** | Treat `file://` / `MEDIA:` / `attachment://` as local upload, not `fetch` |
34
33
 
35
34
  ```bash
36
35
  npx -y @jeik/dingtalk-connector install --force && openclaw gateway restart
37
36
  ```
38
37
 
38
+ ### 📦 v0.8.21-fix46 · 2026-07-20
39
+
40
+ Always-on local MD image diagnostics.
41
+
39
42
  ### 📦 v0.8.21-fix45 · 2026-07-20
40
43
 
41
44
  Image + download link one bubble · only `![]` · quote cache · residual false-positive fix.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <p>基于官方 <strong>v0.8.20</strong> 的社区维护版本,由社区持续跟进修复官方无暇处理的 Bug。<br/>
5
5
  功能与官方完全一致,拥有最快的修复速度,及时合并官方pr和个人发现的bug和社区急需的 Bug。</p>
6
6
 
7
- <p><strong>当前发布版:<a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix46</strong>(稳定生产可用;一键安装:`npx -y @jeik/dingtalk-connector install`;本地 tgz:`openclaw plugins install ./jeik-dingtalk-connector-0.8.21-fix46.tgz --force`)</p>
7
+ <p><strong>当前发布版:<a href="https://www.npmjs.com/package/@jeik/dingtalk-connector">@jeik/dingtalk-connector</a> v0.8.21-fix47</strong>(稳定生产可用;一键安装:`npx -y @jeik/dingtalk-connector install`;本地 tgz:`openclaw plugins install ./jeik-dingtalk-connector-0.8.21-fix47.tgz --force`)</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,19 +23,22 @@
23
23
 
24
24
  ## 🔧 最近更新
25
25
 
26
- ### 🚀 v0.8.21-fix46 · 2026-07-20(当前)
26
+ ### 🚀 v0.8.21-fix47 · 2026-07-20(当前)
27
27
 
28
- **主题:本地 MD 图灰图诊断日志(逻辑同 fix45)**
28
+ **主题:`file://` 本地图误判远程修复**
29
29
 
30
30
  | | 改动 |
31
31
  |--|------|
32
- | 🔍 **LocalImage 日志** | message 路径 always-on:扫描 / exists / 上传成败 / residual |
33
- | 🔍 **MediaIdTrace** | `mdImgs`、`residualLocal`、API前 preview,方便对灰图 |
32
+ | 🐛 **`file://` 灰图** | `![x](file:///mnt/...)` / `file:///root/...` 按本地上传,不再 `fetch failed` |
34
33
 
35
34
  ```bash
36
35
  npx -y @jeik/dingtalk-connector install --force && openclaw gateway restart
37
36
  ```
38
37
 
38
+ ### 📦 v0.8.21-fix46 · 2026-07-20
39
+
40
+ 本地 MD 图灰图诊断日志(LocalImage / MediaIdTrace)。
41
+
39
42
  ### 📦 v0.8.21-fix45 · 2026-07-20
40
43
 
41
44
  图 + 下载链接单气泡 · 只认 `![]` · 引用卡片缓存 · residual 误报修复。
@@ -66,7 +69,7 @@ message 远程 `media` 下载上传。
66
69
  | 2026-06-28 | 上线 npm `@jeik/dingtalk-connector`;过程消息提前定稿修复 |
67
70
  | 2026-05 | MD 直链/本地图;多轮刷屏;4.29+ 无文本输出;WebSocket 幻影重连 |
68
71
 
69
- 完整说明:[CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix46](docs/RELEASE_NOTES_V0.8.21-fix46.md)
72
+ 完整说明:[CHANGELOG.md](CHANGELOG.md) · [FIXES.md](FIXES.md) · [Release fix47](docs/RELEASE_NOTES_V0.8.21-fix47.md)
70
73
 
71
74
  ---
72
75
 
@@ -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-BTByJFxo.mjs");
26
+ const { registerGatewayMethods } = await import("./gateway-methods-DHMdV0k8.mjs");
27
27
  registerGatewayMethods(api);
28
28
  }
29
29
  });
@@ -0,0 +1,2 @@
1
+ import { t as registerGatewayMethods } from "./gateway-methods-DNvtOYEG.mjs";
2
+ export { registerGatewayMethods };
@@ -1,7 +1,7 @@
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-ngF20yqM.mjs";
4
+ import { c as prepareMultiBotMentions, d as finishAICard, i as sendProactive, s as buildBotMentionTable } from "./messaging-msXFq5IJ.mjs";
5
5
  import { c as getUnionId, d as recallEmotionReply } from "./utils-legacy-CALCPP1t.mjs";
6
6
  //#region src/docs.ts
7
7
  var DingtalkDocsClient = class {
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-I36vhOzx.mjs";
2
- import { t as registerGatewayMethods } from "./gateway-methods-CkBI4__L.mjs";
1
+ import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-f78QdJj5.mjs";
2
+ import { t as registerGatewayMethods } from "./gateway-methods-DNvtOYEG.mjs";
3
3
  //#region index.ts
4
4
  /**
5
5
  * 检测同一 plugin id 在多个路径被加载的情况。
@@ -1,2 +1,2 @@
1
- import { _ as toLocalPath, d as processLocalImages, f as processRawMediaPaths, h as sendFileProactive, o as hasResidualLocalMdImagesOutsideCode, p as processVideoMarkers } from "./media-BMNRjseJ.mjs";
1
+ import { _ as toLocalPath, d as processLocalImages, f as processRawMediaPaths, h as sendFileProactive, o as hasResidualLocalMdImagesOutsideCode, p as processVideoMarkers } from "./media-DnQB2BrL.mjs";
2
2
  export { hasResidualLocalMdImagesOutsideCode, processLocalImages, processRawMediaPaths, processVideoMarkers, sendFileProactive, toLocalPath };
@@ -30,10 +30,18 @@ const IMAGE_EXTENSIONS = /\.(png|jpg|jpeg|gif|bmp|webp|tiff|svg)$/i;
30
30
  * 注意:旧版只匹配 /tmp|/home|/root 等前缀,**漏掉 /mnt 共享盘**,导致 message 工具 MD 灰图。
31
31
  */
32
32
  const LOCAL_IMAGE_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
33
- /** 是否像远程 URL 或其截断片段(禁止当本地路径上传) */
33
+ /** 本地文件 URI / OpenClaw 媒体前缀(不是 http 远程) */
34
+ function isLocalFileScheme(p) {
35
+ return p.startsWith("file://") || p.startsWith("MEDIA:") || p.startsWith("attachment://");
36
+ }
37
+ /**
38
+ * 是否像远程 URL(禁止当本地路径上传)。
39
+ * **不含** file:// / MEDIA: / attachment://(那些是本地引用)。
40
+ */
34
41
  function looksLikeRemoteUrl(raw) {
35
42
  const p = (raw || "").trim();
36
43
  if (!p) return false;
44
+ if (isLocalFileScheme(p)) return false;
37
45
  if (/^https?:\/\//i.test(p)) return true;
38
46
  if (/^[a-z]:\/\//i.test(p) && !/^[a-z]:[\\/][^/\\]/i.test(p)) return true;
39
47
  if (p.includes("://")) return true;
@@ -43,9 +51,9 @@ function looksLikeRemoteUrl(raw) {
43
51
  function isLocalImageRef(rawPath) {
44
52
  const p = (rawPath || "").trim();
45
53
  if (!p) return false;
54
+ if (isLocalFileScheme(p)) return true;
46
55
  if (looksLikeRemoteUrl(p) || /^https?:\/\//i.test(p)) return false;
47
56
  if (p.startsWith("@") && !p.includes("/") && !p.includes("\\")) return false;
48
- if (p.startsWith("file://") || p.startsWith("MEDIA:") || p.startsWith("attachment://")) return true;
49
57
  if (p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p)) {
50
58
  if (IMAGE_EXTENSIONS.test(p.split("?")[0] || p)) return true;
51
59
  return !p.includes("://");
@@ -1,9 +1,9 @@
1
1
  import { a as resolveDingtalkAccount } from "./accounts-BAzdqkAV.mjs";
2
- import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-I36vhOzx.mjs";
2
+ import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-f78QdJj5.mjs";
3
3
  import { n as createLoggerFromConfig } from "./logger-mZ9OSbmD.mjs";
4
4
  import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
5
5
  import { i as getOapiAccessToken } from "./utils-CIfI_3Jh.mjs";
6
- import { S as finalClean, _ as FINAL_TAG, a as sendTextMessage, b as estimateTokens, d as finishAICard, g as unregisterActiveCard, h as streamAICard, i as sendProactive, m as registerActiveCard, p as isQpsLimitError, r as sendMessage, t as sendMarkdownMessage, u as createAICardForTarget, v as PROCESS_TAG, x as extractFinal, y as displayClean } from "./messaging-ngF20yqM.mjs";
6
+ import { S as finalClean, _ as FINAL_TAG, a as sendTextMessage, b as estimateTokens, d as finishAICard, g as unregisterActiveCard, h as streamAICard, i as sendProactive, m as registerActiveCard, p as isQpsLimitError, r as sendMessage, t as sendMarkdownMessage, u as createAICardForTarget, v as PROCESS_TAG, x as extractFinal, y as displayClean } from "./messaging-msXFq5IJ.mjs";
7
7
  import { a as QUEUE_BUSY_ACK_PHRASES, n as normalizeSlashCommand, t as buildSessionContext } from "./session-DJ4jYqPv.mjs";
8
8
  import { d as recallEmotionReply, o as getAccessToken, r as addEmotionReply, s as getOapiAccessToken$1, t as DINGTALK_API } from "./utils-legacy-CALCPP1t.mjs";
9
9
  import "./chunk-upload-BBQgGtcZ.mjs";
@@ -62,7 +62,7 @@ function resolveAgentWorkspaceDir(cfg, agentId) {
62
62
  * 直接复用 media.ts 权威实现,避免 reply 路径与 message 路径两套逻辑分叉。
63
63
  */
64
64
  async function processLocalImages(content, oapiToken, log) {
65
- const { processLocalImages: impl } = await import("./media-9LvaywGZ.mjs");
65
+ const { processLocalImages: impl } = await import("./media-BqpUGCni.mjs");
66
66
  return impl(content, oapiToken, log);
67
67
  }
68
68
  //#endregion
@@ -581,14 +581,14 @@ function createDingtalkReplyDispatcher(params) {
581
581
  finalText = await processLocalImages(finalText, oapiToken, log);
582
582
  if (beforeImg !== finalText) console.log(`[DingTalk][LocalImage] closeStreaming 图片处理 | ${beforeImg.length}→${finalText.length}`);
583
583
  try {
584
- const { hasResidualLocalMdImagesOutsideCode } = await import("./media-9LvaywGZ.mjs");
584
+ const { hasResidualLocalMdImagesOutsideCode } = await import("./media-BqpUGCni.mjs");
585
585
  if (hasResidualLocalMdImagesOutsideCode(finalText)) console.warn(`[DingTalk][LocalImage] closeStreaming 定稿后仍有代码块外的本地 MD 图未上传,钉钉可能灰图`);
586
586
  } catch {}
587
587
  finalText = await processVideoMarkers(finalText, "", account.config, oapiToken, log, true, target);
588
588
  finalText = await processAudioMarkers(finalText, "", account.config, oapiToken, log, true, target);
589
589
  finalText = await uploadAndReplaceFileMarkers(finalText, "", account.config, oapiToken, log, true, target);
590
590
  log.info(`[DingTalk][closeStreaming] 准备调用 processRawMediaPaths`);
591
- const { processRawMediaPaths } = await import("./media-9LvaywGZ.mjs");
591
+ const { processRawMediaPaths } = await import("./media-BqpUGCni.mjs");
592
592
  finalText = await processRawMediaPaths(finalText, account.config, oapiToken, log, target);
593
593
  log.info(`[DingTalk][closeStreaming] processRawMediaPaths 处理完成`);
594
594
  } else log.warn(`[DingTalk][closeStreaming] oapiToken 为空,跳过媒体处理`);
@@ -744,7 +744,7 @@ function createDingtalkReplyDispatcher(params) {
744
744
  const oapiToken = await getOapiAccessToken(account.config);
745
745
  if (oapiToken) {
746
746
  log.info(`[DingTalk][deliver] 检测到 final 响应,准备处理裸露文件路径`);
747
- const { processRawMediaPaths } = await import("./media-9LvaywGZ.mjs");
747
+ const { processRawMediaPaths } = await import("./media-BqpUGCni.mjs");
748
748
  text = await processRawMediaPaths(text, account.config, oapiToken, log, target);
749
749
  log.info(`[DingTalk][deliver] 裸露文件路径处理完成`);
750
750
  }
@@ -2184,7 +2184,7 @@ async function handleDingTalkMessageInternal(params) {
2184
2184
  finalText = await processVideoMarkers(finalText, "", config, oapiToken, log, true, mediaTarget);
2185
2185
  finalText = await processAudioMarkers(finalText, "", config, oapiToken, log, true, mediaTarget);
2186
2186
  finalText = await uploadAndReplaceFileMarkers(finalText, "", config, oapiToken, log, true, mediaTarget);
2187
- const { processRawMediaPaths } = await import("./media-9LvaywGZ.mjs");
2187
+ const { processRawMediaPaths } = await import("./media-BqpUGCni.mjs");
2188
2188
  finalText = await processRawMediaPaths(finalText, config, oapiToken, log, mediaTarget);
2189
2189
  }
2190
2190
  const textToSend = finalText.trim() || "✅ 任务执行完成(无文本输出)";
@@ -1,4 +1,4 @@
1
- import { c as logMediaIdTrace, d as processLocalImages, u as processImagesForOutbound, y as uploadMediaToDingTalk } from "./media-BMNRjseJ.mjs";
1
+ import { c as logMediaIdTrace, d as processLocalImages, u as processImagesForOutbound, y as uploadMediaToDingTalk } from "./media-DnQB2BrL.mjs";
2
2
  import { n as createLoggerFromConfig } from "./logger-mZ9OSbmD.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";
@@ -848,7 +848,7 @@ async function resolveMediaSourceToLocalFile(mediaUrl, mediaLocalRoots, log) {
848
848
  cleanup: tmp
849
849
  };
850
850
  }
851
- const { toLocalPath } = await import("./media-9LvaywGZ.mjs");
851
+ const { toLocalPath } = await import("./media-BqpUGCni.mjs");
852
852
  const _fs = await import("fs");
853
853
  const _path = await import("path");
854
854
  let resolved = toLocalPath(mediaUrl);
@@ -1121,7 +1121,7 @@ async function sendMediaToDingTalk(params) {
1121
1121
  const fileName = mediaUrl.split("/").filter(Boolean).pop()?.split("?")[0] || "file";
1122
1122
  if (mediaType === "video") {
1123
1123
  const videoMarker = `[DINGTALK_VIDEO]{"path":"${resolvedMediaUrl}"}[/DINGTALK_VIDEO]`;
1124
- const { processVideoMarkers } = await import("./media-9LvaywGZ.mjs");
1124
+ const { processVideoMarkers } = await import("./media-BqpUGCni.mjs");
1125
1125
  await processVideoMarkers(videoMarker, "", config, oapiToken, console, true, targetParam);
1126
1126
  return {
1127
1127
  ok: true,
@@ -1140,7 +1140,7 @@ async function sendMediaToDingTalk(params) {
1140
1140
  fileName,
1141
1141
  fileType: ext && ext.length < 12 ? ext : "file"
1142
1142
  };
1143
- const { sendFileProactive } = await import("./media-9LvaywGZ.mjs");
1143
+ const { sendFileProactive } = await import("./media-BqpUGCni.mjs");
1144
1144
  await sendFileProactive(config, targetParam, fileInfo, uploadResult.mediaId, log);
1145
1145
  return {
1146
1146
  ok: true,
@@ -1,9 +1,9 @@
1
- import { b as __exportAll } from "./media-BMNRjseJ.mjs";
1
+ import { b as __exportAll } from "./media-DnQB2BrL.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
3
  import { t as createLogger } from "./logger-mZ9OSbmD.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-ngF20yqM.mjs";
6
+ import { S as finalClean, f as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-msXFq5IJ.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
@@ -930,7 +930,7 @@ async function monitorDingtalkProvider(opts = {}) {
930
930
  const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
931
931
  const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
932
932
  import("./accounts-BQptOmgB.mjs"),
933
- import("./message-handler-CytB34ZJ.mjs"),
933
+ import("./message-handler-DVXM5olz.mjs"),
934
934
  import("./connection-DHHFFNQJ.mjs")
935
935
  ]);
936
936
  const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
@@ -0,0 +1,32 @@
1
+ # Release Notes — v0.8.21-fix47(2026-07-20)
2
+
3
+ ## 安装 / Install
4
+
5
+ ```bash
6
+ npx -y @jeik/dingtalk-connector install --force
7
+ openclaw gateway restart
8
+ ```
9
+
10
+ ## 修复 / Fixed
11
+
12
+ ### `file://` MD 本地图灰图
13
+
14
+ **现象(fix46 日志):**
15
+
16
+ ```text
17
+ 扫描 ![]() | #2 kind=http path=file:///mnt/smb/...
18
+ processImagesForOutbound 远程图 | file:///mnt/...
19
+ 远程图下载异常 | fetch failed
20
+ localTried=0 remoteTried=3
21
+ API前 mdImgs 仍含 http:file:///...
22
+ ```
23
+
24
+ **原因:** `looksLikeRemoteUrl` 把任意含 `://` 的字符串当远程;`isLocalImageRef` 又先调用它,`file://` 永远进不了本地上传。
25
+
26
+ **修复:** `file://` / `MEDIA:` / `attachment://` 优先判本地 → `toLocalPath` → 上传 mediaId。
27
+
28
+ 裸绝对路径 `/mnt/...`、`/tmp/...` 本来就正常;本版修的是 **带 `file://` 前缀** 的写法。
29
+
30
+ ## 升级
31
+
32
+ 从 fix46 直接 `--force` 安装。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeik/dingtalk-connector",
3
- "version": "0.8.21-fix46",
3
+ "version": "0.8.21-fix47",
4
4
  "description": "OpenClaw DingTalk channel plugin (fork) | 钉钉 OpenClaw 渠道插件(fork 自官方,含标记/卡片渲染修复)",
5
5
  "type": "module",
6
6
  "exports": {
@@ -28,18 +28,17 @@ export const IMAGE_EXTENSIONS = /\.(png|jpg|jpeg|gif|bmp|webp|tiff|svg)$/i;
28
28
  */
29
29
  export const LOCAL_IMAGE_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
30
30
 
31
- /** 是否为需上传的本地图引用 */
31
+ /** 是否为需上传的本地图引用(与 media.ts 权威实现一致:file:// 必须算本地) */
32
32
  export function isLocalImageRef(rawPath: string): boolean {
33
33
  const p = (rawPath || "").trim();
34
34
  if (!p) return false;
35
- if (/^https?:\/\//i.test(p)) return false;
36
- if (p.includes("://") && !p.startsWith("file://") && !p.startsWith("MEDIA:") && !p.startsWith("attachment://")) {
37
- return false;
38
- }
39
- if (p.startsWith("@") && !p.includes("/") && !p.includes("\\")) return false;
35
+ // file:// 等本地 scheme 优先(勿被 includes("://") 挡掉)
40
36
  if (p.startsWith("file://") || p.startsWith("MEDIA:") || p.startsWith("attachment://")) {
41
37
  return true;
42
38
  }
39
+ if (/^https?:\/\//i.test(p)) return false;
40
+ if (p.includes("://")) return false;
41
+ if (p.startsWith("@") && !p.includes("/") && !p.includes("\\")) return false;
43
42
  if (p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p)) {
44
43
  if (IMAGE_EXTENSIONS.test(p.split("?")[0] || p)) return true;
45
44
  return !p.includes("://");
@@ -45,11 +45,26 @@ export const IMAGE_EXTENSIONS = /\.(png|jpg|jpeg|gif|bmp|webp|tiff|svg)$/i;
45
45
  */
46
46
  export const LOCAL_IMAGE_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
47
47
 
48
- /** 是否像远程 URL 或其截断片段(禁止当本地路径上传) */
48
+ /** 本地文件 URI / OpenClaw 媒体前缀(不是 http 远程) */
49
+ function isLocalFileScheme(p: string): boolean {
50
+ return (
51
+ p.startsWith("file://") ||
52
+ p.startsWith("MEDIA:") ||
53
+ p.startsWith("attachment://")
54
+ );
55
+ }
56
+
57
+ /**
58
+ * 是否像远程 URL(禁止当本地路径上传)。
59
+ * **不含** file:// / MEDIA: / attachment://(那些是本地引用)。
60
+ */
49
61
  export function looksLikeRemoteUrl(raw: string): boolean {
50
62
  const p = (raw || "").trim();
51
63
  if (!p) return false;
64
+ // 本地 scheme 优先:否则 file:// 会被 includes("://") 误判成远程 → fetch 失败 → 灰图
65
+ if (isLocalFileScheme(p)) return false;
52
66
  if (/^https?:\/\//i.test(p)) return true;
67
+ // 伪协议截断如 p://(Windows 路径被当 URL 的历史坑)
53
68
  if (/^[a-z]:\/\//i.test(p) && !/^[a-z]:[\\/][^/\\]/i.test(p)) return true;
54
69
  if (p.includes("://")) return true;
55
70
  return false;
@@ -156,12 +171,11 @@ export function protectNonImageOccurrencesOfTargets(
156
171
  export function isLocalImageRef(rawPath: string): boolean {
157
172
  const p = (rawPath || "").trim();
158
173
  if (!p) return false;
174
+ // file:// / MEDIA: / attachment:// 一律本地(必须先于 looksLikeRemoteUrl)
175
+ if (isLocalFileScheme(p)) return true;
159
176
  // 已是远程 URL 或钉钉 mediaId(@ 开头)→ 不上传
160
177
  if (looksLikeRemoteUrl(p) || /^https?:\/\//i.test(p)) return false;
161
178
  if (p.startsWith("@") && !p.includes("/") && !p.includes("\\")) return false;
162
- if (p.startsWith("file://") || p.startsWith("MEDIA:") || p.startsWith("attachment://")) {
163
- return true;
164
- }
165
179
  // Unix 绝对路径 / Windows 盘符
166
180
  if (p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p)) {
167
181
  // 有图片后缀,或路径中明显是文件(含扩展名)
@@ -1,2 +0,0 @@
1
- import { t as registerGatewayMethods } from "./gateway-methods-CkBI4__L.mjs";
2
- export { registerGatewayMethods };