dlinkclaw-openclaw 2026.10.18 → 2026.10.19

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/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{emptyPluginConfigSchema as e}from"openclaw/plugin-sdk/core";import{channelMeta as n,dlChannel as t,LOG_TAG as r}from"./src/channel.js";import{setDLLogger as o,setDLRuntime as i,isRunStopped as s}from"./src/runtime.js";const l=n;n.isDebug&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0",process.env.NODE_ENV="dev");const a={id:l.id,name:l.label,description:l.blurb,configSchema:e(),register(e){i(e.runtime),o(e.logger,r),e.registerChannel({plugin:t}),e.on("before_tool_call",(e,n)=>{const t=l.id;if(n.channelId===t)return e.runId&&s(e.runId)?{block:!0,blockReason:"用户已点击停止,任务终止执行"}:void 0}),e.on("before_prompt_build",(n,t)=>{const r=l.id;if(e.logger.warn(`ctx.channel=${t.channel}, ctx.channelId=${t.channelId}, channelId=${r}`),t.channel===r||t.channelId===r)return{prependSystemContext:["[AGENT CODE OF CONDUCT - ALWAYS FOLLOW]","1. ASK BEFORE GUESSING: If the task is incomplete or has multiple reasonable interpretations, send a one-line confirmation first. Never guess.",'2. STOP ON FAILURE: If the same problem fails 2-3 times in a row, stop and report: "I am stuck: <reason>. Please advise." Never retry endlessly.','3. ALWAYS REPORT COMPLETION: Every task must end with a completion signal. After sending media/files, always follow up with a short text confirmation (e.g. "✅ Sent 3 files: a.png / b.pdf / c.txt"). The client shows a spinner until it receives the final text reply.'].join("\n")}})}};export default a;
1
+ import{emptyPluginConfigSchema as e}from"openclaw/plugin-sdk/core";import{channelMeta as n,dlChannel as t,LOG_TAG as r}from"./src/channel.js";import{setDLLogger as o,setDLRuntime as i,isRunStopped as s}from"./src/runtime.js";const l=n;l.isDebug&&(process.env.NODE_TLS_REJECT_UNAUTHORIZED="0",process.env.NODE_ENV="dev");const a={id:l.id,name:l.label,description:l.blurb,configSchema:e(),register(e){i(e.runtime),o(e.logger,r),e.registerChannel({plugin:t}),e.on("before_tool_call",(e,n)=>{const t=l.id;if(n.channelId===t)return e.runId&&s(e.runId)?{block:!0,blockReason:"用户已点击停止,任务终止执行"}:void 0}),e.on("before_prompt_build",(n,t)=>{const r=l.id;if(e.logger.warn(`ctx.channel=${t.channel}, ctx.channelId=${t.channelId}, channelId=${r}`),t.channel===r||t.channelId===r)return{prependSystemContext:["[AGENT CODE OF CONDUCT - ALWAYS FOLLOW]","1. ASK BEFORE GUESSING: If the task is incomplete or has multiple reasonable interpretations, send a one-line confirmation first. Never guess.",'2. STOP ON FAILURE: If the same problem fails 2-3 times in a row, stop and report: "I am stuck: <reason>. Please advise." Never retry endlessly.','3. ALWAYS REPORT COMPLETION: Every task must end with a completion signal. After sending media/files, always follow up with a short text confirmation (e.g. "✅ Sent 3 files: a.png / b.pdf / c.txt"). The client shows a spinner until it receives the final text reply.'].join("\n")}})}};export default a;
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlinkclaw-openclaw",
3
- "version": "2026.10.18",
3
+ "version": "2026.10.19",
4
4
  "description": "DLinkClaw OpenClaw channel plugin — 朵联 OpenClaw 接入通道",
5
5
  "keywords": [
6
6
  "DLinkClaw",
@@ -76,7 +76,7 @@
76
76
  ],
77
77
  "order": 90,
78
78
  "quickstartAllowFrom": true,
79
- "isDebug": true,
79
+ "isDebug": false,
80
80
  "preferSessionLookupForAnnounceTarget": true
81
81
  },
82
82
  "install": {
@@ -231,24 +231,40 @@ export class DLClient extends EventEmitter {
231
231
  await this.changeConnectStatus('start');
232
232
  }
233
233
  async stop() {
234
+ // 2026-10-19:关闭阶段必须有界。MQTT end 回调或 HTTP 上报只要有一个不返回,
235
+ // 网关的 drain 就会一直等(systemd TimeoutStopSec 默认 15 分钟),表现为重启卡死。
234
236
  if (this.mqttClient) {
235
- // 2026-09-16 修复:原实现不等 end 回调(清理动作都在回调里),与紧随其后的 start()
236
- // 形成竞态:isConnected() 仍为 true → 跳过 connect(),随后回调才把 mqttClient /
237
- // cmdHandler / mqttConfig 清空 → 连接彻底废掉。这里等回调执行完再返回。
238
- await new Promise((resolve) => {
239
- this.mqttClient.end(false, () => {
237
+ await Promise.race([
238
+ new Promise((resolve) => {
239
+ this.mqttClient.end(true, () => {
240
+ this.mqttClient = null;
241
+ this.logger.warn(`DLClient account[${this.ctx.account.accountId}] Disconnected`);
242
+ if (this.cmdHandler) {
243
+ this.cmdHandler.cleanup();
244
+ }
245
+ this.cmdHandler = null;
246
+ this.mqttConfig = null;
247
+ resolve();
248
+ });
249
+ }),
250
+ new Promise((resolve) => setTimeout(() => {
251
+ this.logger.warn(`DLClient account[${this.ctx.account.accountId}] mqtt end timeout(3s), force continue`);
240
252
  this.mqttClient = null;
241
- this.logger.warn(`DLClient account[${this.ctx.account.accountId}] Disconnected`);
242
- if (this.cmdHandler) {
243
- this.cmdHandler.cleanup();
244
- }
245
253
  this.cmdHandler = null;
246
254
  this.mqttConfig = null;
247
255
  resolve();
248
- });
249
- });
256
+ }, 1200)),
257
+ ]);
258
+ }
259
+ try {
260
+ await Promise.race([
261
+ this.changeConnectStatus('stop'),
262
+ new Promise((resolve) => setTimeout(resolve, 5000)),
263
+ ]);
264
+ }
265
+ catch (e) {
266
+ this.logger.warn(`DLClient changeConnectStatus(stop) failed: ${String(e)}`);
250
267
  }
251
- await this.changeConnectStatus('stop');
252
268
  }
253
269
  /**
254
270
  * 2026-09-15 方案A(石头哥确认):重新拉取 mqtt 配置(含 openUserTopics)。
@@ -1094,7 +1094,7 @@ export async function routeAndDispatchMessage(ctx) {
1094
1094
  streamId,
1095
1095
  content,
1096
1096
  status: 'read',
1097
- kind: isTaskListContent(content) ? 'plan' : 'block',
1097
+ kind: isTaskListContent(content) ? 'plan' : 'commentary',
1098
1098
  });
1099
1099
  }
1100
1100
  },
@@ -1181,7 +1181,7 @@ export async function routeAndDispatchMessage(ctx) {
1181
1181
  streamId,
1182
1182
  content: joined,
1183
1183
  status: 'read',
1184
- kind: isTaskListContent(joined) ? 'plan' : 'block'
1184
+ kind: isTaskListContent(joined) ? 'plan' : 'commentary'
1185
1185
  });
1186
1186
  }
1187
1187
  },
@@ -96,7 +96,7 @@ export interface DLMixedBody extends DLBaseBody {
96
96
  msgList: Array<DLTextBody | DLImageBody | DLVoiceBody | DLVideoBody | DLFileBody>;
97
97
  quote?: DLQuoteBase;
98
98
  }
99
- export type DLKind = 'block' | 'in_process' | 'tool' | 'plan' | 'patch' | 'command' | 'reasoning' | 'end_reasoning';
99
+ export type DLKind = 'block' | 'in_process' | 'tool' | 'plan' | 'patch' | 'command' | 'reasoning' | 'end_reasoning' | 'commentary';
100
100
  export type MessageStatus = 'read' | 'unRead' | undefined;
101
101
  export interface ChatUser {
102
102
  id: string;
@@ -154,7 +154,7 @@ export class CmdHandler {
154
154
  this.dlClient.publishProcessingState({
155
155
  streamId,
156
156
  content,
157
- kind: isTaskList ? 'plan' : 'block',
157
+ kind: isTaskList ? 'plan' : 'commentary',
158
158
  status: 'read'
159
159
  });
160
160
  }
package/package.json CHANGED
@@ -1,96 +1,96 @@
1
- {
2
- "name": "dlinkclaw-openclaw",
3
- "version": "2026.10.18",
4
- "description": "DLinkClaw OpenClaw channel plugin — 朵联 OpenClaw 接入通道",
5
- "keywords": [
6
- "DLinkClaw",
7
- "openclaw",
8
- "朵联",
9
- "钉钉",
10
- "QQ",
11
- "企业微信",
12
- "飞书"
13
- ],
14
- "publishConfig": {
15
- "access": "public"
16
- },
17
- "scripts": {
18
- "build": "tsc && terser dist/index.js --output dist/index.js --compress --mangle --module",
19
- "dev": "tsc --watch",
20
- "prepublishOnly": "npm run build"
21
- },
22
- "license": "MIT",
23
- "author": "rock.chen<szygnet@qq.com>",
24
- "type": "module",
25
- "types": "./dist/index.d.ts",
26
- "main": "./index.ts",
27
- "exports": {
28
- ".": {
29
- "types": "./dist/index.d.ts",
30
- "import": "./dist/index.js"
31
- }
32
- },
33
- "files": [
34
- "dist",
35
- "skills",
36
- "ext_capabilities",
37
- "openclaw.plugin.json",
38
- "README.md",
39
- "docs"
40
- ],
41
- "dependencies": {
42
- "axios": "^1.15.2",
43
- "file-type": "^21.3.1",
44
- "form-data": "^4.0.5",
45
- "mime-types": "^3.0.2",
46
- "mqtt": "^5.10.0",
47
- "qrcode-terminal": "^0.12.0",
48
- "uuid": "^14.0.2",
49
- "ws": "^8.20.0"
50
- },
51
- "devDependencies": {
52
- "@types/mime-types": "^3.0.1",
53
- "@types/ws": "^8.18.1",
54
- "terser": "^5.46.1",
55
- "typescript": "^5.3.3"
56
- },
57
- "peerDependencies": {
58
- "openclaw": ">=2026.10.3"
59
- },
60
- "openclaw": {
61
- "extensions": [
62
- "./index.ts"
63
- ],
64
- "installDependencies": true,
65
- "channel": {
66
- "id": "dlink",
67
- "label": "朵联 DLinkClaw",
68
- "selectionLabel": "朵联(DLinkClaw)",
69
- "docsPath": "/channels/dlinkclaw-openclaw",
70
- "docsLabel": "dlinkclaw-openclaw",
71
- "blurb": "朵联 DLinkClaw OpenClaw 接入通道, 本地或云端部署OpenClaw连接朵联客户端, 支持企业微信、QQ、钉钉、飞书, 无需公网IP.",
72
- "aliases": [
73
- "dlink",
74
- "DLinkClaw",
75
- "朵联"
76
- ],
77
- "order": 90,
78
- "quickstartAllowFrom": true,
79
- "isDebug": true,
80
- "preferSessionLookupForAnnounceTarget": true
81
- },
82
- "install": {
83
- "npmSpec": "dlinkclaw-openclaw",
84
- "localPath": "extensions/dlinkclaw-openclaw",
85
- "defaultChoice": "npm"
86
- }
87
- },
88
- "repository": {
89
- "type": "git",
90
- "url": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel.git"
91
- },
92
- "homepage": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel#readme",
93
- "bugs": {
94
- "url": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel/issues"
95
- }
1
+ {
2
+ "name": "dlinkclaw-openclaw",
3
+ "version": "2026.10.19",
4
+ "description": "DLinkClaw OpenClaw channel plugin — 朵联 OpenClaw 接入通道",
5
+ "keywords": [
6
+ "DLinkClaw",
7
+ "openclaw",
8
+ "朵联",
9
+ "钉钉",
10
+ "QQ",
11
+ "企业微信",
12
+ "飞书"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc && terser dist/index.js --output dist/index.js --compress --mangle --module",
19
+ "dev": "tsc --watch",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "license": "MIT",
23
+ "author": "rock.chen<szygnet@qq.com>",
24
+ "type": "module",
25
+ "types": "./dist/index.d.ts",
26
+ "main": "./index.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "skills",
36
+ "ext_capabilities",
37
+ "openclaw.plugin.json",
38
+ "README.md",
39
+ "docs"
40
+ ],
41
+ "dependencies": {
42
+ "axios": "^1.15.2",
43
+ "file-type": "^21.3.1",
44
+ "form-data": "^4.0.5",
45
+ "mime-types": "^3.0.2",
46
+ "mqtt": "^5.10.0",
47
+ "qrcode-terminal": "^0.12.0",
48
+ "uuid": "^14.0.2",
49
+ "ws": "^8.20.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/mime-types": "^3.0.1",
53
+ "@types/ws": "^8.18.1",
54
+ "terser": "^5.46.1",
55
+ "typescript": "^5.3.3"
56
+ },
57
+ "peerDependencies": {
58
+ "openclaw": ">=2026.10.3"
59
+ },
60
+ "openclaw": {
61
+ "extensions": [
62
+ "./index.ts"
63
+ ],
64
+ "installDependencies": true,
65
+ "channel": {
66
+ "id": "dlink",
67
+ "label": "朵联 DLinkClaw",
68
+ "selectionLabel": "朵联(DLinkClaw)",
69
+ "docsPath": "/channels/dlinkclaw-openclaw",
70
+ "docsLabel": "dlinkclaw-openclaw",
71
+ "blurb": "朵联 DLinkClaw OpenClaw 接入通道, 本地或云端部署OpenClaw连接朵联客户端, 支持企业微信、QQ、钉钉、飞书, 无需公网IP.",
72
+ "aliases": [
73
+ "dlink",
74
+ "DLinkClaw",
75
+ "朵联"
76
+ ],
77
+ "order": 90,
78
+ "quickstartAllowFrom": true,
79
+ "isDebug": false,
80
+ "preferSessionLookupForAnnounceTarget": true
81
+ },
82
+ "install": {
83
+ "npmSpec": "dlinkclaw-openclaw",
84
+ "localPath": "extensions/dlinkclaw-openclaw",
85
+ "defaultChoice": "npm"
86
+ }
87
+ },
88
+ "repository": {
89
+ "type": "git",
90
+ "url": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel.git"
91
+ },
92
+ "homepage": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel#readme",
93
+ "bugs": {
94
+ "url": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel/issues"
95
+ }
96
96
  }