dlinkclaw-openclaw 1.0.0

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 (85) hide show
  1. package/LICENSE +201 -0
  2. package/README.en.md +46 -0
  3. package/README.md +15 -0
  4. package/dist/index.d.ts +9 -0
  5. package/dist/index.js +1 -0
  6. package/dist/package.json +95 -0
  7. package/dist/src/account.d.ts +54 -0
  8. package/dist/src/account.js +394 -0
  9. package/dist/src/channel.d.ts +17 -0
  10. package/dist/src/channel.js +153 -0
  11. package/dist/src/client/client-manager.d.ts +4 -0
  12. package/dist/src/client/client-manager.js +10 -0
  13. package/dist/src/client/const.d.ts +37 -0
  14. package/dist/src/client/const.js +155 -0
  15. package/dist/src/client/crypto.d.ts +47 -0
  16. package/dist/src/client/crypto.js +260 -0
  17. package/dist/src/client/dl-client.d.ts +117 -0
  18. package/dist/src/client/dl-client.js +588 -0
  19. package/dist/src/client/dl-http.d.ts +27 -0
  20. package/dist/src/client/dl-http.js +223 -0
  21. package/dist/src/client/media-handler.d.ts +21 -0
  22. package/dist/src/client/media-handler.js +196 -0
  23. package/dist/src/client/message.d.ts +96 -0
  24. package/dist/src/client/message.js +1211 -0
  25. package/dist/src/client/timeout.d.ts +20 -0
  26. package/dist/src/client/timeout.js +36 -0
  27. package/dist/src/client/types.d.ts +226 -0
  28. package/dist/src/client/types.js +1 -0
  29. package/dist/src/monitor.d.ts +18 -0
  30. package/dist/src/monitor.js +322 -0
  31. package/dist/src/outbound.d.ts +6 -0
  32. package/dist/src/outbound.js +78 -0
  33. package/dist/src/policy.d.ts +42 -0
  34. package/dist/src/policy.js +216 -0
  35. package/dist/src/runtime.d.ts +9 -0
  36. package/dist/src/runtime.js +65 -0
  37. package/dist/src/services/gateway-rpc.d.ts +37 -0
  38. package/dist/src/services/gateway-rpc.js +37 -0
  39. package/dist/src/services/index.d.ts +41 -0
  40. package/dist/src/services/index.js +245 -0
  41. package/dist/src/services/services.d.ts +169 -0
  42. package/dist/src/services/services.js +1160 -0
  43. package/dist/src/services/types.d.ts +391 -0
  44. package/dist/src/services/types.js +5 -0
  45. package/dist/src/services/ws-client.d.ts +186 -0
  46. package/dist/src/services/ws-client.js +896 -0
  47. package/dist/src/utils.d.ts +20 -0
  48. package/dist/src/utils.js +128 -0
  49. package/ext_capabilities/workrelay-speak/CLONE_GUIDE.md +129 -0
  50. package/ext_capabilities/workrelay-speak/HARDWARE.md +84 -0
  51. package/ext_capabilities/workrelay-speak/QWEN_GUIDE.md +151 -0
  52. package/ext_capabilities/workrelay-speak/README.md +79 -0
  53. package/ext_capabilities/workrelay-speak/__pycache__/patch-kokoro-en.cpython-312.pyc +0 -0
  54. package/ext_capabilities/workrelay-speak/install.sh +329 -0
  55. package/ext_capabilities/workrelay-speak/install.sh.bak-20260814 +376 -0
  56. package/ext_capabilities/workrelay-speak/manifest.json +63 -0
  57. package/ext_capabilities/workrelay-speak/patch-kokoro-en.py +85 -0
  58. package/ext_capabilities/workrelay-speak/status.sh +111 -0
  59. package/ext_capabilities/workrelay-speak/workrelay-tts.sh +118 -0
  60. package/ext_capabilities/workrelay-speak-luxtts/README.md +44 -0
  61. package/ext_capabilities/workrelay-speak-luxtts/install.sh +330 -0
  62. package/ext_capabilities/workrelay-speak-luxtts/manifest.json +63 -0
  63. package/ext_capabilities/workrelay-speak-luxtts/samples/45ea2e2c-0863-4966-a739-8bff8817f4c0.wav +0 -0
  64. package/ext_capabilities/workrelay-speak-luxtts/samples/800e5af4-cba5-441e-8003-6d36f35409e6.wav +0 -0
  65. package/ext_capabilities/workrelay-speak-luxtts/samples/85fafe01-d4d6-4a48-890e-9ae113f21905.wav +0 -0
  66. package/ext_capabilities/workrelay-speak-luxtts/samples/reference_text.txt +4 -0
  67. package/ext_capabilities/workrelay-speak-luxtts/samples/stone-sample-6.4s.wav +0 -0
  68. package/ext_capabilities/workrelay-speak-luxtts/status.sh +115 -0
  69. package/ext_capabilities/workrelay-speak-luxtts/workrelay-tts.sh +98 -0
  70. package/ext_capabilities/workrelay-speak-qwen/README.md +62 -0
  71. package/ext_capabilities/workrelay-speak-qwen/install.sh +349 -0
  72. package/ext_capabilities/workrelay-speak-qwen/manifest.json +63 -0
  73. package/ext_capabilities/workrelay-speak-qwen/status.sh +106 -0
  74. package/ext_capabilities/workrelay-speak-qwen/workrelay-tts.sh +98 -0
  75. package/ext_capabilities/workrelay-transcribe/README.md +76 -0
  76. package/ext_capabilities/workrelay-transcribe/__pycache__/transcribe.cpython-312.pyc +0 -0
  77. package/ext_capabilities/workrelay-transcribe/__pycache__/transcribe_server.cpython-312.pyc +0 -0
  78. package/ext_capabilities/workrelay-transcribe/install.sh +227 -0
  79. package/ext_capabilities/workrelay-transcribe/manifest.json +42 -0
  80. package/ext_capabilities/workrelay-transcribe/status.sh +63 -0
  81. package/ext_capabilities/workrelay-transcribe/transcribe.py +56 -0
  82. package/ext_capabilities/workrelay-transcribe/transcribe_server.py +116 -0
  83. package/ext_capabilities/workrelay-transcribe/voicebox-transcribe.sh +88 -0
  84. package/openclaw.plugin.json +142 -0
  85. package/package.json +95 -0
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ # WorkRelay 语音转录状态检查
3
+ # 返回值: 0=已启用, 1=未安装, 2=部分安装, 3=配置缺失
4
+ # 同时输出 JSON 给客户端解析
5
+
6
+ set -e
7
+
8
+ STATUS_OK=0
9
+ STATUS_NOT_INSTALLED=1
10
+ STATUS_PARTIAL=2
11
+ STATUS_CONFIG_MISSING=3
12
+
13
+ INSTALL_DIR="${WR_INSTALL_DIR:-$HOME/.workrelay/transcribe}"
14
+ MODEL_CACHE="${WR_WHISPER_CACHE:-$HOME/.cache/faster-whisper}"
15
+
16
+ checks=()
17
+
18
+ # 检查1: faster-whisper 包
19
+ check_dep=0
20
+ python3 -c "import faster_whisper" 2>/dev/null && check_dep=1 || true
21
+
22
+ # 检查2: 模型(small 模型 ~460MB,阈值从 500 降到 200,避免误报未下载)
23
+ check_model=0
24
+ if [ -d "$MODEL_CACHE" ]; then
25
+ model_size=$(du -sm "$MODEL_CACHE" 2>/dev/null | cut -f1 || echo 0)
26
+ [ "$model_size" -gt 200 ] && check_model=1
27
+ fi
28
+
29
+ # 检查3: 脚本
30
+ check_scripts=0
31
+ [ -f "$INSTALL_DIR/transcribe.py" ] && [ -f "$INSTALL_DIR/voicebox-transcribe.sh" ] && check_scripts=1
32
+
33
+ # 检查4: OpenClaw 配置(2026-09-14 openclaw 升级后:1) config 路径变更 audio.transcription.* → tools.media.models;2) 不再调 openclaw CLI——升级后 CLI 可能挂起卡住插件队列,改为直接读 openclaw.json,毫秒级返回)
34
+ check_config=0
35
+ OC_JSON="${OPENCLAW_HOME:-$HOME/.openclaw}/openclaw.json"
36
+ if [ -f "$OC_JSON" ]; then
37
+ grep -q 'voicebox-transcribe' "$OC_JSON" && check_config=1 || true
38
+ fi
39
+
40
+ # ── 汇总状态 ──
41
+ total=$((check_dep + check_model + check_scripts + check_config))
42
+
43
+ case $total in
44
+ 4) status="enabled"; desc="语音转录已启用"; exit_code=$STATUS_OK ;;
45
+ 0) status="disabled"; desc="未安装"; exit_code=$STATUS_NOT_INSTALLED ;;
46
+ *) status="partial"; desc="部分安装"; exit_code=$STATUS_PARTIAL ;;
47
+ esac
48
+
49
+ # ── 输出 JSON ──
50
+ cat <<EOF
51
+ {
52
+ "status": "$status",
53
+ "description": "$desc",
54
+ "checks": {
55
+ "faster_whisper": $([ $check_dep -eq 1 ] && echo true || echo false),
56
+ "model": $([ $check_model -eq 1 ] && echo true || echo false),
57
+ "scripts": $([ $check_scripts -eq 1 ] && echo true || echo false),
58
+ "openclaw_config": $([ $check_config -eq 1 ] && echo true || echo false)
59
+ }
60
+ }
61
+ EOF
62
+
63
+ exit $exit_code
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env python3
2
+ """WorkRelay 语音转录引擎 - 基于 faster-whisper."""
3
+
4
+ import sys
5
+ import os
6
+ from faster_whisper import WhisperModel
7
+
8
+ MODEL_NAME = os.environ.get("WR_WHISPER_MODEL", "small")
9
+ MODEL = None
10
+ MODEL_CACHE = os.environ.get(
11
+ "WR_WHISPER_CACHE",
12
+ os.path.join(os.path.expanduser("~"), ".cache", "faster-whisper"),
13
+ )
14
+
15
+
16
+ def load_model():
17
+ global MODEL
18
+ MODEL = WhisperModel(
19
+ MODEL_NAME,
20
+ device="cpu",
21
+ compute_type="int8",
22
+ download_root=MODEL_CACHE,
23
+ )
24
+ print(f"[WorkRelay] Whisper model '{MODEL_NAME}' loaded", file=sys.stderr)
25
+
26
+
27
+ def transcribe(audio_path: str, language: str = "zh") -> str:
28
+ if MODEL is None:
29
+ load_model()
30
+ segments, info = MODEL.transcribe(
31
+ audio_path,
32
+ language=language,
33
+ beam_size=5,
34
+ vad_filter=True,
35
+ )
36
+ return " ".join(s.text.strip() for s in segments)
37
+
38
+
39
+ if __name__ == "__main__":
40
+ if len(sys.argv) < 2:
41
+ print("Usage: transcribe.py <audio_file> [language]", file=sys.stderr)
42
+ sys.exit(1)
43
+
44
+ audio_file = sys.argv[1]
45
+ lang = sys.argv[2] if len(sys.argv) > 2 else "zh"
46
+
47
+ if not os.path.isfile(audio_file):
48
+ print(f"ERROR: file not found: {audio_file}", file=sys.stderr)
49
+ sys.exit(1)
50
+
51
+ try:
52
+ result = transcribe(audio_file, lang)
53
+ print(result.strip())
54
+ except Exception as e:
55
+ print(f"ERROR: {e}", file=sys.stderr)
56
+ sys.exit(1)
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ """WorkRelay 语音转录常驻服务(2026-08-12)
3
+ faster-whisper 模型加载一次后常驻内存,避免每次转写重复加载模型(省 3-5 秒)。
4
+ HTTP 接口:
5
+ POST /transcribe multipart/form-data: file=<audio>
6
+ GET /health 健康检查
7
+ 启动:python3 transcribe_server.py [port] (默认 17890)
8
+ """
9
+ import sys
10
+ import os
11
+ import json
12
+ import tempfile
13
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
14
+ from urllib.parse import urlparse
15
+
16
+ from faster_whisper import WhisperModel
17
+
18
+ PORT = int(os.environ.get("WR_WHISPER_PORT", "17890"))
19
+ MODEL_NAME = os.environ.get("WR_WHISPER_MODEL", "small")
20
+ MODEL_CACHE = os.environ.get(
21
+ "WR_WHISPER_CACHE",
22
+ os.path.join(os.path.expanduser("~"), ".cache", "faster-whisper"),
23
+ )
24
+ LANGUAGE = os.environ.get("WR_WHISPER_LANG", "zh")
25
+
26
+ _model = None
27
+
28
+
29
+ def get_model():
30
+ global _model
31
+ if _model is None:
32
+ _model = WhisperModel(
33
+ MODEL_NAME,
34
+ device="cpu",
35
+ compute_type="int8",
36
+ download_root=MODEL_CACHE,
37
+ )
38
+ return _model
39
+
40
+
41
+ class Handler(BaseHTTPRequestHandler):
42
+ def log_message(self, fmt, *args): # 安静模式
43
+ pass
44
+
45
+ def _send_json(self, code: int, obj: dict):
46
+ body = json.dumps(obj, ensure_ascii=False).encode("utf-8")
47
+ self.send_response(code)
48
+ self.send_header("Content-Type", "application/json; charset=utf-8")
49
+ self.send_header("Content-Length", str(len(body)))
50
+ self.end_headers()
51
+ self.wfile.write(body)
52
+
53
+ def do_GET(self):
54
+ path = urlparse(self.path).path
55
+ if path == "/health":
56
+ self._send_json(200, {"status": "ok", "model": MODEL_NAME})
57
+ else:
58
+ self._send_json(404, {"error": "not found"})
59
+
60
+ def do_POST(self):
61
+ path = urlparse(self.path).path
62
+ if path != "/transcribe":
63
+ self._send_json(404, {"error": "not found"})
64
+ return
65
+ try:
66
+ # 解析 multipart(只取第一个 file 字段)
67
+ content_type = self.headers.get("Content-Type", "")
68
+ boundary = None
69
+ if "boundary=" in content_type:
70
+ boundary = content_type.split("boundary=")[1].strip().strip('"')
71
+ if not boundary:
72
+ self._send_json(400, {"error": "missing boundary"})
73
+ return
74
+
75
+ body = self.rfile.read(int(self.headers.get("Content-Length", "0")))
76
+ # 极简 multipart 解析:按 boundary 切块,找 filename + 内容
77
+ parts = body.split(b"--" + boundary.encode())
78
+ audio_data = None
79
+ for part in parts:
80
+ if b'filename="' in part and b"\r\n\r\n" in part:
81
+ _, data = part.split(b"\r\n\r\n", 1)
82
+ audio_data = data.rstrip(b"\r\n--")
83
+ break
84
+ if audio_data is None:
85
+ self._send_json(400, {"error": "no file part"})
86
+ return
87
+
88
+ with tempfile.NamedTemporaryFile(suffix=".webm", delete=False) as tmp:
89
+ tmp.write(audio_data)
90
+ tmp_path = tmp.name
91
+ try:
92
+ model = get_model()
93
+ segments, _info = model.transcribe(
94
+ tmp_path, language=LANGUAGE, beam_size=5, vad_filter=True
95
+ )
96
+ text = " ".join(s.text.strip() for s in segments)
97
+ self._send_json(200, {"text": text})
98
+ finally:
99
+ try:
100
+ os.remove(tmp_path)
101
+ except OSError:
102
+ pass
103
+ except Exception as e: # noqa: BLE001
104
+ self._send_json(500, {"error": str(e)})
105
+
106
+
107
+ def main():
108
+ server = ThreadingHTTPServer(("127.0.0.1", PORT), Handler)
109
+ # 先加载模型(启动即常驻)
110
+ get_model()
111
+ print(f"[WorkRelay] whisper server ready: http://127.0.0.1:{PORT} model={MODEL_NAME}", flush=True)
112
+ server.serve_forever()
113
+
114
+
115
+ if __name__ == "__main__":
116
+ main()
@@ -0,0 +1,88 @@
1
+ #!/bin/bash
2
+ # WorkRelay 语音转录桥接脚本
3
+ # 优先本地 faster-whisper 常驻服务(模型常驻内存,免重复加载),服务不可用时回退直接转写
4
+ # 环境变量:
5
+ # WR_WHISPER_HOST - 常驻服务地址(默认 127.0.0.1)
6
+ # WR_WHISPER_PORT - 常驻服务端口(默认 17890)
7
+ # WR_WHISPER_MODEL - 本地模型名(默认 small)
8
+ # WR_FALLBACK_URL - 远程转录服务 URL(可选,不设则仅本地)
9
+
10
+ set -e
11
+
12
+ AUDIO_FILE="$1"
13
+ SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
14
+
15
+ if [ ! -f "$AUDIO_FILE" ]; then
16
+ echo "ERROR: audio file not found: $AUDIO_FILE" >&2
17
+ exit 1
18
+ fi
19
+
20
+ WH_HOST="${WR_WHISPER_HOST:-127.0.0.1}"
21
+ WH_PORT="${WR_WHISPER_PORT:-17890}"
22
+
23
+ # ── 第1步:常驻服务(模型常驻内存,转写快)──
24
+ result=$(curl -s --connect-timeout 2 --max-time 60 \
25
+ -X POST "http://${WH_HOST}:${WH_PORT}/transcribe" \
26
+ -F "file=@${AUDIO_FILE}" 2>/dev/null)
27
+ if [ -n "$result" ]; then
28
+ text=$(echo "$result" | python3 -c "
29
+ import sys, json
30
+ try:
31
+ data = json.load(sys.stdin)
32
+ if data.get('text'):
33
+ print(data['text'].strip())
34
+ else:
35
+ print('ERROR: ' + str(data.get('error', 'unknown')))
36
+ except Exception:
37
+ print('ERROR: bad response')
38
+ " 2>/dev/null)
39
+ if [ -n "$text" ] && [[ "$text" != ERROR:* ]]; then
40
+ echo "$text"
41
+ exit 0
42
+ fi
43
+ fi
44
+
45
+ # ── 第2步:直接本地 faster-whisper(常驻服务未启动时的回退)──
46
+ result=$(python3 "$SCRIPT_DIR/transcribe.py" "$AUDIO_FILE" 2>/tmp/wr-transcribe-err.log)
47
+ exit_code=$?
48
+
49
+ if [ $exit_code -eq 0 ] && [ -n "$result" ]; then
50
+ # 排除以 ERROR: 开头的输出(有些 Python 错误仍返回 exit 0)
51
+ if [[ "$result" != ERROR:* ]]; then
52
+ echo "$result"
53
+ exit 0
54
+ fi
55
+ fi
56
+
57
+ # 本地失败日志
58
+ cat /tmp/wr-transcribe-err.log >&2
59
+ rm -f /tmp/wr-transcribe-err.log
60
+
61
+ # ── 第3步:远程 fallback(如果配置了) ──
62
+ if [ -n "${WR_FALLBACK_URL:-}" ]; then
63
+ result=$(curl -s --connect-timeout 5 --max-time 60 \
64
+ -X POST "$WR_FALLBACK_URL" \
65
+ -F "file=@${AUDIO_FILE}" \
66
+ -F "language=zh" 2>&1)
67
+
68
+ # 尝试解析 JSON 响应
69
+ text=$(echo "$result" | python3 -c "
70
+ import sys, json
71
+ try:
72
+ data = json.load(sys.stdin)
73
+ for key in ('text','transcript','result'):
74
+ if data.get(key):
75
+ print(data[key].strip())
76
+ break
77
+ except:
78
+ pass
79
+ " 2>/dev/null)
80
+
81
+ if [ -n "$text" ]; then
82
+ echo "$text"
83
+ exit 0
84
+ fi
85
+ fi
86
+
87
+ echo "ERROR: transcription failed (local whisper + remote fallback both failed)" >&2
88
+ exit 1
@@ -0,0 +1,142 @@
1
+ {
2
+ "id": "dlink",
3
+ "channels": [
4
+ "dlink"
5
+ ],
6
+ "skills": [
7
+ "./skills"
8
+ ],
9
+ "configSchema": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "properties": {
13
+ "apiKey": {
14
+ "type": "string",
15
+ "description": "朵联 apiKey"
16
+ },
17
+ "baseUrl": {
18
+ "type": "string",
19
+ "description": "朵联回调URL",
20
+ "default": "https://your-dlink-server.example.com"
21
+ },
22
+ "secret": {
23
+ "type": "string",
24
+ "description": "朵联签名密钥"
25
+ },
26
+ "enabled": {
27
+ "type": "boolean",
28
+ "default": true
29
+ },
30
+ "accountId": {
31
+ "type": "string",
32
+ "description": "账号标识",
33
+ "default": "default"
34
+ },
35
+ "mediaMaxMb": {
36
+ "type": "number",
37
+ "description": "媒体大小上限(MB),OpenClaw 核心出站媒体校验读取,默认 100",
38
+ "default": 100
39
+ }
40
+ }
41
+ },
42
+ "setup": {
43
+ "requiresRuntime": true,
44
+ "prompts": [
45
+ {
46
+ "name": "apiKey",
47
+ "type": "input",
48
+ "message": "请输入朵联 API Key:",
49
+ "validate": "required"
50
+ },
51
+ {
52
+ "name": "secret",
53
+ "type": "input",
54
+ "message": "请输入朵联签名密钥:",
55
+ "validate": "required"
56
+ },
57
+ {
58
+ "name": "baseUrl",
59
+ "type": "input",
60
+ "message": "请输入朵联回调地址:",
61
+ "default": "https://your-dlink-server.example.com",
62
+ "validate": "required"
63
+ },
64
+ {
65
+ "name": "accountId",
66
+ "type": "input",
67
+ "message": "请输入账号标识(默认: default):",
68
+ "default": "default"
69
+ },
70
+ {
71
+ "name": "enabled",
72
+ "type": "confirm",
73
+ "message": "是否立即启用朵联通道?",
74
+ "default": true
75
+ }
76
+ ]
77
+ },
78
+ "channelConfigs": {
79
+ "dlink": {
80
+ "schema": {
81
+ "type": "object",
82
+ "additionalProperties": false,
83
+ "properties": {
84
+ "apiKey": {
85
+ "type": "string",
86
+ "description": "朵联 apiKey"
87
+ },
88
+ "baseUrl": {
89
+ "type": "string",
90
+ "description": "朵联回调URL",
91
+ "default": "https://your-dlink-server.example.com"
92
+ },
93
+ "secret": {
94
+ "type": "string",
95
+ "description": "朵联签名密钥"
96
+ },
97
+ "enabled": {
98
+ "type": "boolean",
99
+ "default": true
100
+ },
101
+ "accountId": {
102
+ "type": "string",
103
+ "description": "账号标识",
104
+ "default": "default"
105
+ },
106
+ "mediaMaxMb": {
107
+ "type": "number",
108
+ "description": "媒体大小上限(MB),OpenClaw 核心出站媒体校验读取,默认 100",
109
+ "default": 100
110
+ }
111
+ }
112
+ },
113
+ "label": "朵联 DLinkClaw",
114
+ "description": "朵联 DLinkClaw OpenClaw 接入通道",
115
+ "commands": {
116
+ "nativeCommandsAutoEnabled": false
117
+ },
118
+ "uiHints": {
119
+ "apiKey": {
120
+ "label": "API Key",
121
+ "help": "朵联平台的 API 密钥,在朵联控制台获取",
122
+ "placeholder": "请输入 API Key",
123
+ "sensitive": true
124
+ },
125
+ "secret": {
126
+ "label": "签名密钥",
127
+ "help": "朵联平台的签名密钥,用于消息加解密与签名认证",
128
+ "placeholder": "请输入签名密钥",
129
+ "sensitive": true
130
+ },
131
+ "baseUrl": {
132
+ "label": "回调地址",
133
+ "help": "朵联消息回调的服务器地址",
134
+ "placeholder": "https://your-dlink-server.example.com"
135
+ },
136
+ "enabled": {
137
+ "label": "启用通道"
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "dlinkclaw-openclaw",
3
+ "version": "1.0.0",
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
+ ],
40
+ "dependencies": {
41
+ "axios": "^1.15.2",
42
+ "file-type": "^21.3.1",
43
+ "form-data": "^4.0.5",
44
+ "mime-types": "^3.0.2",
45
+ "mqtt": "^5.10.0",
46
+ "qrcode-terminal": "^0.12.0",
47
+ "uuid": "^14.0.2",
48
+ "ws": "^8.20.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/mime-types": "^3.0.1",
52
+ "@types/ws": "^8.18.1",
53
+ "terser": "^5.46.1",
54
+ "typescript": "^5.3.3"
55
+ },
56
+ "peerDependencies": {
57
+ "openclaw": ">=2026.9.1"
58
+ },
59
+ "openclaw": {
60
+ "extensions": [
61
+ "./index.ts"
62
+ ],
63
+ "installDependencies": true,
64
+ "channel": {
65
+ "id": "dlink",
66
+ "label": "朵联 DLinkClaw",
67
+ "selectionLabel": "朵联(DLinkClaw)",
68
+ "docsPath": "/channels/dlinkclaw-openclaw",
69
+ "docsLabel": "dlinkclaw-openclaw",
70
+ "blurb": "朵联 DLinkClaw OpenClaw 接入通道, 本地部署连接朵联客户端, 支持企业微信、QQ、钉钉、飞书, 无需公网IP.",
71
+ "aliases": [
72
+ "dlink",
73
+ "DLinkClaw",
74
+ "朵联"
75
+ ],
76
+ "order": 90,
77
+ "quickstartAllowFrom": true,
78
+ "isDebug": false,
79
+ "preferSessionLookupForAnnounceTarget": true
80
+ },
81
+ "install": {
82
+ "npmSpec": "dlinkclaw-openclaw",
83
+ "localPath": "extensions/dlinkclaw-openclaw",
84
+ "defaultChoice": "npm"
85
+ }
86
+ },
87
+ "repository": {
88
+ "type": "git",
89
+ "url": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel.git"
90
+ },
91
+ "homepage": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel#readme",
92
+ "bugs": {
93
+ "url": "https://github.com/dlinkclaw/dlinkclaw-openclaw-channel/issues"
94
+ }
95
+ }