@huo15/dingtalk-connector-pro 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.
- package/CHANGELOG.md +485 -0
- package/LICENSE +21 -0
- package/README.en.md +479 -0
- package/README.md +209 -0
- package/docs/AGENT_ROUTING.md +335 -0
- package/docs/DEAP_AGENT_GUIDE.en.md +115 -0
- package/docs/DEAP_AGENT_GUIDE.md +115 -0
- package/docs/images/dingtalk.svg +1 -0
- package/docs/images/image-1.png +0 -0
- package/docs/images/image-2.png +0 -0
- package/docs/images/image-3.png +0 -0
- package/docs/images/image-4.png +0 -0
- package/docs/images/image-5.png +0 -0
- package/docs/images/image-6.png +0 -0
- package/docs/images/image-7.png +0 -0
- package/index.ts +28 -0
- package/install-beta.sh +438 -0
- package/install-npm.sh +167 -0
- package/openclaw.plugin.json +498 -0
- package/package.json +80 -0
- package/src/channel.ts +463 -0
- package/src/config/accounts.ts +242 -0
- package/src/config/schema.ts +148 -0
- package/src/core/connection.ts +722 -0
- package/src/core/message-handler.ts +1700 -0
- package/src/core/provider.ts +111 -0
- package/src/core/state.ts +54 -0
- package/src/directory.ts +95 -0
- package/src/docs.ts +293 -0
- package/src/gateway-methods.ts +404 -0
- package/src/onboarding.ts +413 -0
- package/src/policy.ts +32 -0
- package/src/probe.ts +212 -0
- package/src/reply-dispatcher.ts +630 -0
- package/src/runtime.ts +32 -0
- package/src/sdk/helpers.ts +322 -0
- package/src/sdk/types.ts +513 -0
- package/src/secret-input.ts +19 -0
- package/src/services/media/audio.ts +54 -0
- package/src/services/media/chunk-upload.ts +296 -0
- package/src/services/media/common.ts +155 -0
- package/src/services/media/file.ts +70 -0
- package/src/services/media/image.ts +81 -0
- package/src/services/media/index.ts +10 -0
- package/src/services/media/video.ts +162 -0
- package/src/services/media.ts +1136 -0
- package/src/services/messaging/card.ts +342 -0
- package/src/services/messaging/index.ts +17 -0
- package/src/services/messaging/send.ts +141 -0
- package/src/services/messaging.ts +1013 -0
- package/src/targets.ts +45 -0
- package/src/types/index.ts +59 -0
- package/src/utils/agent.ts +63 -0
- package/src/utils/async.ts +51 -0
- package/src/utils/constants.ts +27 -0
- package/src/utils/http-client.ts +37 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/logger.ts +78 -0
- package/src/utils/session.ts +147 -0
- package/src/utils/token.ts +93 -0
- package/src/utils/utils-legacy.ts +454 -0
- package/tsconfig.json +20 -0
package/install-beta.sh
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# 清理函数:确保临时文件被清理
|
|
5
|
+
TEMP_FILES=()
|
|
6
|
+
cleanup() {
|
|
7
|
+
for file in "${TEMP_FILES[@]}"; do
|
|
8
|
+
if [ -f "$file" ]; then
|
|
9
|
+
rm -f "$file"
|
|
10
|
+
fi
|
|
11
|
+
done
|
|
12
|
+
}
|
|
13
|
+
trap cleanup EXIT
|
|
14
|
+
|
|
15
|
+
# ============ 参数解析 ============
|
|
16
|
+
BRANCH="${1:-feat/migrate-to-openclaw-sdk}" # 默认分支
|
|
17
|
+
VERSION="" # 将从 package.json 动态获取
|
|
18
|
+
|
|
19
|
+
# 显示使用说明
|
|
20
|
+
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
|
21
|
+
echo "使用方法: $0 [分支名]"
|
|
22
|
+
echo ""
|
|
23
|
+
echo "参数:"
|
|
24
|
+
echo " 分支名 要安装的 Git 分支 (默认: feat/migrate-to-openclaw-sdk)"
|
|
25
|
+
echo ""
|
|
26
|
+
echo "示例:"
|
|
27
|
+
echo " $0 # 安装默认分支"
|
|
28
|
+
echo " $0 main # 安装 main 分支"
|
|
29
|
+
echo " $0 feat/new-feature # 安装指定功能分支"
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
echo "🚀 开始安装钉钉连接器..."
|
|
34
|
+
echo "📌 分支: $BRANCH"
|
|
35
|
+
|
|
36
|
+
# 检查 OpenClaw 是否已安装
|
|
37
|
+
if ! command -v openclaw &> /dev/null; then
|
|
38
|
+
echo "❌ 错误:未检测到 OpenClaw,请先安装 OpenClaw"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# 检查 jq 是否已安装(用于 JSON 处理)
|
|
43
|
+
if ! command -v jq &> /dev/null; then
|
|
44
|
+
echo "⚠️ 警告:未检测到 jq 工具,将跳过自动配置迁移"
|
|
45
|
+
echo "💡 提示:安装 jq 可以自动迁移配置 (brew install jq 或 apt-get install jq)"
|
|
46
|
+
HAS_JQ=false
|
|
47
|
+
else
|
|
48
|
+
HAS_JQ=true
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
CONFIG_FILE="$HOME/.openclaw/openclaw.json"
|
|
52
|
+
|
|
53
|
+
# 检查并处理旧备份
|
|
54
|
+
echo "🔍 检查旧备份..."
|
|
55
|
+
BACKUP_DIR="$HOME/.openclaw"
|
|
56
|
+
OLD_BACKUPS=$(ls -t "$BACKUP_DIR"/openclaw.json.backup.* 2>/dev/null || true)
|
|
57
|
+
|
|
58
|
+
if [ -n "$OLD_BACKUPS" ]; then
|
|
59
|
+
BACKUP_COUNT=$(echo "$OLD_BACKUPS" | wc -l | tr -d ' ')
|
|
60
|
+
echo "📋 发现 $BACKUP_COUNT 个旧备份"
|
|
61
|
+
|
|
62
|
+
# 找到最新的备份(用户当前正在使用的配置)
|
|
63
|
+
LATEST_BACKUP=$(echo "$OLD_BACKUPS" | head -1)
|
|
64
|
+
echo "📌 将从最新备份中提取配置:$(basename "$LATEST_BACKUP")"
|
|
65
|
+
|
|
66
|
+
# 先复制最新的备份到临时位置(避免被删除)
|
|
67
|
+
TEMP_SOURCE=$(mktemp)
|
|
68
|
+
TEMP_FILES+=("$TEMP_SOURCE")
|
|
69
|
+
if ! cp "$LATEST_BACKUP" "$TEMP_SOURCE"; then
|
|
70
|
+
echo "❌ 错误:无法复制备份文件"
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
SOURCE_CONFIG="$TEMP_SOURCE"
|
|
74
|
+
|
|
75
|
+
# 保留最新的备份用于回滚,只删除旧的备份
|
|
76
|
+
echo "🗑️ 清理旧备份(保留最新备份用于回滚)..."
|
|
77
|
+
FIRST=true
|
|
78
|
+
while read -r backup; do
|
|
79
|
+
if [ "$FIRST" = true ]; then
|
|
80
|
+
FIRST=false
|
|
81
|
+
echo " - 保留:$(basename "$backup")"
|
|
82
|
+
else
|
|
83
|
+
rm -f "$backup"
|
|
84
|
+
echo " - 已删除:$(basename "$backup")"
|
|
85
|
+
fi
|
|
86
|
+
done <<< "$OLD_BACKUPS"
|
|
87
|
+
else
|
|
88
|
+
echo "ℹ️ 未发现旧备份,将使用当前配置"
|
|
89
|
+
SOURCE_CONFIG="$CONFIG_FILE"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# 创建新备份
|
|
93
|
+
echo "📦 创建新备份..."
|
|
94
|
+
BACKUP_FILE="$HOME/.openclaw/openclaw.json.backup.$(date +%Y%m%d_%H%M%S)"
|
|
95
|
+
|
|
96
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
97
|
+
if ! cp "$CONFIG_FILE" "$BACKUP_FILE"; then
|
|
98
|
+
echo "❌ 错误:备份配置文件失败"
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
echo "✅ 配置已备份到: $BACKUP_FILE"
|
|
102
|
+
|
|
103
|
+
# 自动迁移配置(如果有 jq)
|
|
104
|
+
if [ "$HAS_JQ" = true ]; then
|
|
105
|
+
# 先检查当前配置中是否已有 dingtalk-connector 配置
|
|
106
|
+
EXISTING_CONNECTOR_ID=$(jq -r '.channels."dingtalk-connector".clientId // empty' "$CONFIG_FILE")
|
|
107
|
+
EXISTING_CONNECTOR_SECRET=$(jq -r '.channels."dingtalk-connector".clientSecret // empty' "$CONFIG_FILE")
|
|
108
|
+
EXISTING_CONNECTOR_ACCOUNTS=$(jq -r '.channels."dingtalk-connector".accounts // empty' "$CONFIG_FILE")
|
|
109
|
+
|
|
110
|
+
# 如果已经有 dingtalk-connector 配置,跳过迁移
|
|
111
|
+
if [ -n "$EXISTING_CONNECTOR_ID" ] || [ -n "$EXISTING_CONNECTOR_SECRET" ] || { [ "$EXISTING_CONNECTOR_ACCOUNTS" != "null" ] && [ -n "$EXISTING_CONNECTOR_ACCOUNTS" ]; }; then
|
|
112
|
+
echo "✅ 检测到已有 dingtalk-connector 配置,跳过迁移"
|
|
113
|
+
echo " - 配置文件保持不变"
|
|
114
|
+
else
|
|
115
|
+
echo "🔄 从原始配置中提取并迁移..."
|
|
116
|
+
|
|
117
|
+
# 从源配置中提取旧的 dingtalk 配置
|
|
118
|
+
OLD_CLIENT_ID=$(jq -r '.channels.dingtalk.clientId // empty' "$SOURCE_CONFIG")
|
|
119
|
+
|
|
120
|
+
# 检查 clientSecret 的类型(字符串或对象)
|
|
121
|
+
SECRET_TYPE=$(jq -r '.channels.dingtalk.clientSecret | type' "$SOURCE_CONFIG")
|
|
122
|
+
|
|
123
|
+
if [ "$SECRET_TYPE" = "string" ]; then
|
|
124
|
+
# 如果是字符串,直接提取
|
|
125
|
+
OLD_CLIENT_SECRET=$(jq -r '.channels.dingtalk.clientSecret // empty' "$SOURCE_CONFIG")
|
|
126
|
+
elif [ "$SECRET_TYPE" = "object" ]; then
|
|
127
|
+
# 如果是对象(SecretInput 引用),保持原样
|
|
128
|
+
OLD_CLIENT_SECRET=$(jq -c '.channels.dingtalk.clientSecret' "$SOURCE_CONFIG")
|
|
129
|
+
else
|
|
130
|
+
OLD_CLIENT_SECRET=""
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# 如果原始配置中有旧配置,则迁移
|
|
134
|
+
if [ -n "$OLD_CLIENT_ID" ] && [ -n "$OLD_CLIENT_SECRET" ]; then
|
|
135
|
+
echo "📋 正在迁移配置到 dingtalk-connector..."
|
|
136
|
+
|
|
137
|
+
# 创建临时文件
|
|
138
|
+
TEMP_FILE=$(mktemp)
|
|
139
|
+
TEMP_FILES+=("$TEMP_FILE")
|
|
140
|
+
|
|
141
|
+
# 迁移配置(根据 clientSecret 类型选择不同的处理方式)
|
|
142
|
+
if [ "$SECRET_TYPE" = "string" ]; then
|
|
143
|
+
# 字符串类型:使用 --arg 传递
|
|
144
|
+
if ! jq --arg clientId "$OLD_CLIENT_ID" \
|
|
145
|
+
--arg clientSecret "$OLD_CLIENT_SECRET" \
|
|
146
|
+
'.channels."dingtalk-connector" = (.channels."dingtalk-connector" // {}) |
|
|
147
|
+
.channels."dingtalk-connector".enabled = true |
|
|
148
|
+
.channels."dingtalk-connector".clientId = $clientId |
|
|
149
|
+
.channels."dingtalk-connector".clientSecret = $clientSecret |
|
|
150
|
+
.channels.dingtalk.enabled = false' \
|
|
151
|
+
"$CONFIG_FILE" > "$TEMP_FILE"; then
|
|
152
|
+
echo "❌ 错误:配置迁移失败"
|
|
153
|
+
rm -f "$TEMP_FILE"
|
|
154
|
+
exit 1
|
|
155
|
+
fi
|
|
156
|
+
elif [ "$SECRET_TYPE" = "object" ]; then
|
|
157
|
+
# 对象类型:使用 --argjson 传递 JSON 对象
|
|
158
|
+
if ! jq --arg clientId "$OLD_CLIENT_ID" \
|
|
159
|
+
--argjson clientSecret "$OLD_CLIENT_SECRET" \
|
|
160
|
+
'.channels."dingtalk-connector" = (.channels."dingtalk-connector" // {}) |
|
|
161
|
+
.channels."dingtalk-connector".enabled = true |
|
|
162
|
+
.channels."dingtalk-connector".clientId = $clientId |
|
|
163
|
+
.channels."dingtalk-connector".clientSecret = $clientSecret |
|
|
164
|
+
.channels.dingtalk.enabled = false' \
|
|
165
|
+
"$CONFIG_FILE" > "$TEMP_FILE"; then
|
|
166
|
+
echo "❌ 错误:配置迁移失败"
|
|
167
|
+
rm -f "$TEMP_FILE"
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# 替换原配置文件
|
|
173
|
+
if ! mv "$TEMP_FILE" "$CONFIG_FILE"; then
|
|
174
|
+
echo "❌ 错误:无法更新配置文件"
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
echo "✅ 配置迁移完成:"
|
|
179
|
+
echo " - clientId: ${OLD_CLIENT_ID:0:12}..."
|
|
180
|
+
echo " - clientSecret: [已迁移]"
|
|
181
|
+
echo " - 旧 dingtalk 插件已禁用"
|
|
182
|
+
else
|
|
183
|
+
echo "ℹ️ 未发现旧的 dingtalk 配置"
|
|
184
|
+
echo ""
|
|
185
|
+
echo "📝 检测到您是首次配置钉钉连接器,安装完成后请运行以下命令进行配置:"
|
|
186
|
+
echo " openclaw wizard"
|
|
187
|
+
echo ""
|
|
188
|
+
echo "或者手动编辑配置文件:"
|
|
189
|
+
echo " vim ~/.openclaw/openclaw.json"
|
|
190
|
+
echo ""
|
|
191
|
+
echo "配置示例:"
|
|
192
|
+
echo ' {'
|
|
193
|
+
echo ' "channels": {'
|
|
194
|
+
echo ' "dingtalk-connector": {'
|
|
195
|
+
echo ' "enabled": true,'
|
|
196
|
+
echo ' "clientId": "your-client-id",'
|
|
197
|
+
echo ' "clientSecret": "your-client-secret"'
|
|
198
|
+
echo ' }'
|
|
199
|
+
echo ' }'
|
|
200
|
+
echo ' }'
|
|
201
|
+
fi
|
|
202
|
+
fi
|
|
203
|
+
fi
|
|
204
|
+
else
|
|
205
|
+
echo "⚠️ 配置文件不存在,将在安装后创建"
|
|
206
|
+
echo ""
|
|
207
|
+
echo "📝 安装完成后请运行以下命令进行配置:"
|
|
208
|
+
echo " openclaw wizard"
|
|
209
|
+
echo ""
|
|
210
|
+
echo "或者手动编辑配置文件:"
|
|
211
|
+
echo " vim ~/.openclaw/openclaw.json"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
# 克隆升级分支
|
|
215
|
+
echo "📥 克隆分支: $BRANCH..."
|
|
216
|
+
cd /tmp
|
|
217
|
+
rm -rf dingtalk-openclaw-connector-beta
|
|
218
|
+
|
|
219
|
+
if ! git clone --single-branch --branch "$BRANCH" \
|
|
220
|
+
https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector.git \
|
|
221
|
+
dingtalk-openclaw-connector-beta; then
|
|
222
|
+
echo "❌ 错误:克隆分支 '$BRANCH' 失败"
|
|
223
|
+
echo "💡 提示:请检查分支名是否正确"
|
|
224
|
+
exit 1
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
cd dingtalk-openclaw-connector-beta
|
|
228
|
+
|
|
229
|
+
# 从 package.json 获取版本号
|
|
230
|
+
if command -v jq &> /dev/null; then
|
|
231
|
+
VERSION=$(jq -r '.version' package.json 2>/dev/null || echo "unknown")
|
|
232
|
+
else
|
|
233
|
+
# 如果没有 jq,使用 grep 和 sed 提取版本号
|
|
234
|
+
VERSION=$(grep '"version"' package.json | sed 's/.*"version": "\(.*\)".*/\1/' || echo "unknown")
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
echo "📦 版本: $VERSION"
|
|
238
|
+
echo ""
|
|
239
|
+
|
|
240
|
+
npm install
|
|
241
|
+
|
|
242
|
+
# 卸载旧版本
|
|
243
|
+
echo "🗑️ 卸载旧版本..."
|
|
244
|
+
|
|
245
|
+
# 检查插件是否已安装
|
|
246
|
+
INSTALLED_PLUGINS=$(openclaw plugins list 2>/dev/null || echo "")
|
|
247
|
+
if echo "$INSTALLED_PLUGINS" | grep -q "dingtalk-connector"; then
|
|
248
|
+
echo "📦 检测到已安装的 dingtalk-connector,正在卸载..."
|
|
249
|
+
# 使用 -f 强制卸载,避免交互式确认
|
|
250
|
+
# 捕获卸载错误,即使失败也继续执行(可能是插件文件已被手动删除)
|
|
251
|
+
UNINSTALL_FAILED=false
|
|
252
|
+
if command -v yes &> /dev/null; then
|
|
253
|
+
yes | openclaw plugins uninstall dingtalk-connector 2>&1 || {
|
|
254
|
+
echo "⚠️ 卸载过程出现错误(可能插件文件已被手动删除)"
|
|
255
|
+
UNINSTALL_FAILED=true
|
|
256
|
+
}
|
|
257
|
+
else
|
|
258
|
+
echo "y" | openclaw plugins uninstall dingtalk-connector 2>&1 || {
|
|
259
|
+
echo "⚠️ 卸载过程出现错误(可能插件文件已被手动删除)"
|
|
260
|
+
UNINSTALL_FAILED=true
|
|
261
|
+
}
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# 如果卸载失败,手动清理配置文件中的残留配置
|
|
265
|
+
if [ "$UNINSTALL_FAILED" = true ] && [ "$HAS_JQ" = true ]; then
|
|
266
|
+
echo "🧹 清理配置文件中的残留配置..."
|
|
267
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
268
|
+
# 先保存 dingtalk-connector 配置,用于后续恢复
|
|
269
|
+
SAVED_CONNECTOR_CONFIG=$(mktemp)
|
|
270
|
+
TEMP_FILES+=("$SAVED_CONNECTOR_CONFIG")
|
|
271
|
+
jq '.channels."dingtalk-connector" // {}' "$CONFIG_FILE" > "$SAVED_CONNECTOR_CONFIG"
|
|
272
|
+
|
|
273
|
+
TEMP_CLEANUP=$(mktemp)
|
|
274
|
+
TEMP_FILES+=("$TEMP_CLEANUP")
|
|
275
|
+
|
|
276
|
+
# 删除 channels.dingtalk-connector 和 plugins 相关配置
|
|
277
|
+
if jq 'del(.channels."dingtalk-connector") |
|
|
278
|
+
del(.plugins.entries."dingtalk-connector") |
|
|
279
|
+
.plugins.allow = (.plugins.allow // [] | map(select(. != "dingtalk-connector"))) |
|
|
280
|
+
.plugins.load.paths = (.plugins.load.paths // [] | map(select(. | contains("dingtalk-openclaw-connector") | not)))' \
|
|
281
|
+
"$CONFIG_FILE" > "$TEMP_CLEANUP"; then
|
|
282
|
+
mv "$TEMP_CLEANUP" "$CONFIG_FILE"
|
|
283
|
+
echo "✅ 配置文件已清理(channels + plugins + load paths)"
|
|
284
|
+
echo "💾 已保存 dingtalk-connector 配置,将在安装后恢复"
|
|
285
|
+
else
|
|
286
|
+
echo "⚠️ 无法清理配置文件,请手动检查"
|
|
287
|
+
rm -f "$TEMP_CLEANUP"
|
|
288
|
+
fi
|
|
289
|
+
fi
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
echo "✅ 旧版本处理完成"
|
|
293
|
+
else
|
|
294
|
+
echo "ℹ️ 未检测到已安装的 dingtalk-connector,跳过卸载"
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
# 安装新版本
|
|
298
|
+
echo "✨ 安装新版本..."
|
|
299
|
+
openclaw plugins install -l .
|
|
300
|
+
|
|
301
|
+
# 如果之前保存了配置,现在恢复
|
|
302
|
+
if [ "$UNINSTALL_FAILED" = true ] && [ "$HAS_JQ" = true ] && [ -f "$SAVED_CONNECTOR_CONFIG" ]; then
|
|
303
|
+
echo "🔄 恢复 dingtalk-connector 配置..."
|
|
304
|
+
|
|
305
|
+
# 检查保存的配置是否为空对象
|
|
306
|
+
SAVED_CONFIG_CONTENT=$(cat "$SAVED_CONNECTOR_CONFIG")
|
|
307
|
+
if [ "$SAVED_CONFIG_CONTENT" != "{}" ] && [ "$SAVED_CONFIG_CONTENT" != "null" ]; then
|
|
308
|
+
TEMP_RESTORE=$(mktemp)
|
|
309
|
+
TEMP_FILES+=("$TEMP_RESTORE")
|
|
310
|
+
|
|
311
|
+
# 将保存的配置合并回去
|
|
312
|
+
if jq --slurpfile saved "$SAVED_CONNECTOR_CONFIG" \
|
|
313
|
+
'.channels."dingtalk-connector" = $saved[0]' \
|
|
314
|
+
"$CONFIG_FILE" > "$TEMP_RESTORE"; then
|
|
315
|
+
mv "$TEMP_RESTORE" "$CONFIG_FILE"
|
|
316
|
+
echo "✅ 配置已恢复"
|
|
317
|
+
|
|
318
|
+
# 显示恢复的配置信息
|
|
319
|
+
RESTORED_CLIENT_ID=$(jq -r '.channels."dingtalk-connector".clientId // empty' "$CONFIG_FILE")
|
|
320
|
+
if [ -n "$RESTORED_CLIENT_ID" ]; then
|
|
321
|
+
echo " - clientId: ${RESTORED_CLIENT_ID:0:12}..."
|
|
322
|
+
echo " - clientSecret: [已恢复]"
|
|
323
|
+
fi
|
|
324
|
+
else
|
|
325
|
+
echo "⚠️ 配置恢复失败,请手动检查"
|
|
326
|
+
rm -f "$TEMP_RESTORE"
|
|
327
|
+
fi
|
|
328
|
+
else
|
|
329
|
+
echo "ℹ️ 未发现需要恢复的配置"
|
|
330
|
+
fi
|
|
331
|
+
fi
|
|
332
|
+
|
|
333
|
+
# 重启 Gateway
|
|
334
|
+
echo "🔄 重启 Gateway..."
|
|
335
|
+
if ! openclaw gateway restart; then
|
|
336
|
+
echo "⚠️ 警告:Gateway 重启失败,请手动重启"
|
|
337
|
+
echo " 命令:openclaw gateway restart"
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
echo ""
|
|
341
|
+
echo "============================================"
|
|
342
|
+
echo "✅ 安装完成!"
|
|
343
|
+
echo "============================================"
|
|
344
|
+
echo ""
|
|
345
|
+
|
|
346
|
+
# ============ 验证结果 ============
|
|
347
|
+
echo "🔍 验证安装结果..."
|
|
348
|
+
echo ""
|
|
349
|
+
|
|
350
|
+
# 1. 检查插件是否已安装
|
|
351
|
+
PLUGIN_INSTALLED=false
|
|
352
|
+
if openclaw plugins list 2>/dev/null | grep -q "dingtalk-connector"; then
|
|
353
|
+
PLUGIN_INSTALLED=true
|
|
354
|
+
echo "✅ 插件已安装"
|
|
355
|
+
else
|
|
356
|
+
echo "❌ 插件未安装"
|
|
357
|
+
fi
|
|
358
|
+
|
|
359
|
+
# 2. 检查配置文件
|
|
360
|
+
CONFIG_VALID=false
|
|
361
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
362
|
+
if [ "$HAS_JQ" = true ]; then
|
|
363
|
+
CONNECTOR_ENABLED=$(jq -r '.channels."dingtalk-connector".enabled // false' "$CONFIG_FILE")
|
|
364
|
+
CONNECTOR_CLIENT_ID=$(jq -r '.channels."dingtalk-connector".clientId // empty' "$CONFIG_FILE")
|
|
365
|
+
|
|
366
|
+
if [ "$CONNECTOR_ENABLED" = "true" ] && [ -n "$CONNECTOR_CLIENT_ID" ]; then
|
|
367
|
+
CONFIG_VALID=true
|
|
368
|
+
echo "✅ 配置文件有效"
|
|
369
|
+
echo " - 插件已启用"
|
|
370
|
+
echo " - clientId: ${CONNECTOR_CLIENT_ID:0:12}..."
|
|
371
|
+
else
|
|
372
|
+
echo "⚠️ 配置文件需要完善"
|
|
373
|
+
if [ "$CONNECTOR_ENABLED" != "true" ]; then
|
|
374
|
+
echo " - 插件未启用"
|
|
375
|
+
fi
|
|
376
|
+
if [ -z "$CONNECTOR_CLIENT_ID" ]; then
|
|
377
|
+
echo " - 缺少 clientId"
|
|
378
|
+
fi
|
|
379
|
+
fi
|
|
380
|
+
else
|
|
381
|
+
echo "⚠️ 无法验证配置(需要 jq 工具)"
|
|
382
|
+
fi
|
|
383
|
+
else
|
|
384
|
+
echo "❌ 配置文件不存在"
|
|
385
|
+
fi
|
|
386
|
+
|
|
387
|
+
# 3. 检查 Gateway 状态
|
|
388
|
+
GATEWAY_RUNNING=false
|
|
389
|
+
if openclaw gateway status 2>/dev/null | grep -q "running"; then
|
|
390
|
+
GATEWAY_RUNNING=true
|
|
391
|
+
echo "✅ Gateway 运行中"
|
|
392
|
+
else
|
|
393
|
+
echo "⚠️ Gateway 未运行"
|
|
394
|
+
fi
|
|
395
|
+
|
|
396
|
+
echo ""
|
|
397
|
+
echo "============================================"
|
|
398
|
+
echo "📊 安装总结"
|
|
399
|
+
echo "============================================"
|
|
400
|
+
echo "版本: $VERSION"
|
|
401
|
+
echo "分支: $BRANCH"
|
|
402
|
+
echo "插件安装: $([ "$PLUGIN_INSTALLED" = true ] && echo "✅" || echo "❌")"
|
|
403
|
+
echo "配置有效: $([ "$CONFIG_VALID" = true ] && echo "✅" || echo "⚠️")"
|
|
404
|
+
echo "Gateway: $([ "$GATEWAY_RUNNING" = true ] && echo "✅" || echo "⚠️")"
|
|
405
|
+
echo "============================================"
|
|
406
|
+
echo ""
|
|
407
|
+
|
|
408
|
+
# 根据验证结果给出建议
|
|
409
|
+
if [ "$PLUGIN_INSTALLED" = true ] && [ "$CONFIG_VALID" = true ] && [ "$GATEWAY_RUNNING" = true ]; then
|
|
410
|
+
echo "🎉 一切就绪!钉钉连接器已成功安装并配置完成"
|
|
411
|
+
else
|
|
412
|
+
echo "⚠️ 需要进一步操作:"
|
|
413
|
+
|
|
414
|
+
if [ "$PLUGIN_INSTALLED" = false ]; then
|
|
415
|
+
echo " 1. 插件未安装,请检查安装日志"
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
if [ "$CONFIG_VALID" = false ]; then
|
|
419
|
+
echo " 2. 配置未完成,请运行:"
|
|
420
|
+
echo " openclaw wizard"
|
|
421
|
+
echo " 或手动编辑:vim ~/.openclaw/openclaw.json"
|
|
422
|
+
fi
|
|
423
|
+
|
|
424
|
+
if [ "$GATEWAY_RUNNING" = false ]; then
|
|
425
|
+
echo " 3. Gateway 未运行,请运行:"
|
|
426
|
+
echo " openclaw gateway restart"
|
|
427
|
+
fi
|
|
428
|
+
fi
|
|
429
|
+
|
|
430
|
+
echo ""
|
|
431
|
+
echo "📖 更多信息:"
|
|
432
|
+
echo " - 新功能说明:README_UPGRADE.md"
|
|
433
|
+
echo " - 问题反馈:https://github.com/DingTalk-Real-AI/dingtalk-openclaw-connector/issues"
|
|
434
|
+
echo ""
|
|
435
|
+
echo "💡 如需回滚:"
|
|
436
|
+
echo " 1. 恢复配置:cp $BACKUP_FILE ~/.openclaw/openclaw.json"
|
|
437
|
+
echo " 2. 安装旧版本:openclaw plugins install @dingtalk-real-ai/dingtalk-connector@latest"
|
|
438
|
+
echo ""
|
package/install-npm.sh
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# install-npm.sh
|
|
4
|
+
# 将 dingtalk-connector 插件从本地 git 路径安装切换到 npm 包安装
|
|
5
|
+
#
|
|
6
|
+
# 流程:
|
|
7
|
+
# 1. 备份当前 openclaw.json 配置文件
|
|
8
|
+
# 2. 写入最小化干净配置(让 openclaw plugins 命令能正常运行)
|
|
9
|
+
# 3. 卸载旧插件(清除本地路径安装记录)
|
|
10
|
+
# 4. 从 npm 安装最新版插件
|
|
11
|
+
# 5. 恢复备份的配置文件(保留用户的所有业务配置)
|
|
12
|
+
# =============================================================================
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
# ============ 常量 ============
|
|
17
|
+
OPENCLAW_CONFIG="$HOME/.openclaw/openclaw.json"
|
|
18
|
+
PLUGIN_NAME="dingtalk-connector"
|
|
19
|
+
NPM_PACKAGE="@dingtalk-real-ai/dingtalk-connector"
|
|
20
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
21
|
+
BACKUP_FILE="${OPENCLAW_CONFIG}.migrate_backup.${TIMESTAMP}"
|
|
22
|
+
|
|
23
|
+
# ============ 颜色输出 ============
|
|
24
|
+
RED='\033[0;31m'
|
|
25
|
+
GREEN='\033[0;32m'
|
|
26
|
+
YELLOW='\033[1;33m'
|
|
27
|
+
BLUE='\033[0;34m'
|
|
28
|
+
NC='\033[0m' # No Color
|
|
29
|
+
|
|
30
|
+
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
|
31
|
+
log_success() { echo -e "${GREEN}[OK]${NC} $*"; }
|
|
32
|
+
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
33
|
+
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
34
|
+
|
|
35
|
+
# ============ 错误恢复 ============
|
|
36
|
+
# 如果脚本中途失败,自动恢复备份
|
|
37
|
+
restore_on_error() {
|
|
38
|
+
if [[ -f "$BACKUP_FILE" ]]; then
|
|
39
|
+
log_warn "脚本异常退出,正在恢复备份配置..."
|
|
40
|
+
cp "$BACKUP_FILE" "$OPENCLAW_CONFIG"
|
|
41
|
+
log_warn "已恢复备份: $BACKUP_FILE"
|
|
42
|
+
fi
|
|
43
|
+
}
|
|
44
|
+
trap restore_on_error ERR
|
|
45
|
+
|
|
46
|
+
# ============ 前置检查 ============
|
|
47
|
+
echo ""
|
|
48
|
+
echo "============================================================"
|
|
49
|
+
echo " DingTalk Connector — 切换到 npm 安装"
|
|
50
|
+
echo "============================================================"
|
|
51
|
+
echo ""
|
|
52
|
+
|
|
53
|
+
if [[ ! -f "$OPENCLAW_CONFIG" ]]; then
|
|
54
|
+
log_error "找不到 OpenClaw 配置文件: $OPENCLAW_CONFIG"
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if ! command -v openclaw &>/dev/null; then
|
|
59
|
+
log_error "找不到 openclaw 命令,请确认已安装 OpenClaw CLI"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# ============ 步骤 1:备份配置文件 ============
|
|
64
|
+
log_info "步骤 1/5:备份当前配置文件..."
|
|
65
|
+
cp "$OPENCLAW_CONFIG" "$BACKUP_FILE"
|
|
66
|
+
log_success "备份已保存至: $BACKUP_FILE"
|
|
67
|
+
|
|
68
|
+
# ============ 步骤 2:写入最小化干净配置 ============
|
|
69
|
+
log_info "步骤 2/5:写入临时干净配置(用于执行插件命令)..."
|
|
70
|
+
|
|
71
|
+
# 提取当前配置中 plugins 以外的所有字段,保留业务配置结构
|
|
72
|
+
# 同时写入一个空的 plugins 配置,让 openclaw 能正常初始化
|
|
73
|
+
python3 - <<'PYEOF'
|
|
74
|
+
import json, sys, os
|
|
75
|
+
|
|
76
|
+
config_path = os.path.expanduser("~/.openclaw/openclaw.json")
|
|
77
|
+
|
|
78
|
+
with open(config_path, "r") as f:
|
|
79
|
+
original = json.load(f)
|
|
80
|
+
|
|
81
|
+
# 保留所有非 plugins 字段,plugins 置为空(让 openclaw 重新初始化)
|
|
82
|
+
clean_config = {k: v for k, v in original.items() if k != "plugins"}
|
|
83
|
+
clean_config["plugins"] = {
|
|
84
|
+
"load": {},
|
|
85
|
+
"entries": {},
|
|
86
|
+
"allow": [],
|
|
87
|
+
"installs": {}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
with open(config_path, "w") as f:
|
|
91
|
+
json.dump(clean_config, f, indent=2)
|
|
92
|
+
|
|
93
|
+
print(" 干净配置写入完成")
|
|
94
|
+
PYEOF
|
|
95
|
+
|
|
96
|
+
log_success "临时干净配置写入完成"
|
|
97
|
+
|
|
98
|
+
# ============ 步骤 3:卸载旧插件 ============
|
|
99
|
+
log_info "步骤 3/5:卸载旧版插件 (${PLUGIN_NAME})..."
|
|
100
|
+
if openclaw plugins uninstall "$PLUGIN_NAME" --yes 2>&1 | grep -v "^$"; then
|
|
101
|
+
log_success "旧插件卸载完成"
|
|
102
|
+
else
|
|
103
|
+
log_warn "卸载命令返回非零,可能插件本来就未安装,继续执行..."
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# ============ 步骤 4:从 npm 安装最新版插件 ============
|
|
107
|
+
log_info "步骤 4/5:从 npm 安装最新版插件 (${NPM_PACKAGE})..."
|
|
108
|
+
echo ""
|
|
109
|
+
openclaw plugins install "$NPM_PACKAGE"
|
|
110
|
+
echo ""
|
|
111
|
+
log_success "npm 插件安装完成"
|
|
112
|
+
|
|
113
|
+
# ============ 步骤 5:恢复备份配置(保留业务配置) ============
|
|
114
|
+
log_info "步骤 5/5:将新安装的插件信息合并回原始业务配置..."
|
|
115
|
+
|
|
116
|
+
python3 - <<'PYEOF'
|
|
117
|
+
import json, os
|
|
118
|
+
|
|
119
|
+
config_path = os.path.expanduser("~/.openclaw/openclaw.json")
|
|
120
|
+
import glob
|
|
121
|
+
backup_files = sorted(glob.glob(config_path + ".migrate_backup.*"))
|
|
122
|
+
backup_path = backup_files[-1] # 取最新的备份
|
|
123
|
+
|
|
124
|
+
with open(config_path, "r") as f:
|
|
125
|
+
new_config = json.load(f)
|
|
126
|
+
|
|
127
|
+
with open(backup_path, "r") as f:
|
|
128
|
+
original_config = json.load(f)
|
|
129
|
+
|
|
130
|
+
# 策略:以原始业务配置为基础,只替换 plugins.installs 为新安装的结果
|
|
131
|
+
# 这样保留了用户所有的 channels、agents、bindings 等业务配置
|
|
132
|
+
merged = dict(original_config)
|
|
133
|
+
merged["plugins"] = dict(original_config.get("plugins", {}))
|
|
134
|
+
|
|
135
|
+
# 用新安装的 installs 记录覆盖旧的(包含新的 npm source 信息)
|
|
136
|
+
new_installs = new_config.get("plugins", {}).get("installs", {})
|
|
137
|
+
if new_installs:
|
|
138
|
+
merged["plugins"]["installs"] = new_installs
|
|
139
|
+
# 同步更新 entries 和 allow(保留原有的 enabled 状态)
|
|
140
|
+
for plugin_id in new_installs:
|
|
141
|
+
if plugin_id not in merged["plugins"].get("entries", {}):
|
|
142
|
+
merged["plugins"].setdefault("entries", {})[plugin_id] = {"enabled": True}
|
|
143
|
+
if plugin_id not in merged["plugins"].get("allow", []):
|
|
144
|
+
merged["plugins"].setdefault("allow", []).append(plugin_id)
|
|
145
|
+
|
|
146
|
+
with open(config_path, "w") as f:
|
|
147
|
+
json.dump(merged, f, indent=2)
|
|
148
|
+
|
|
149
|
+
print(f" 已合并配置,新插件安装信息:")
|
|
150
|
+
for plugin_id, install_info in new_installs.items():
|
|
151
|
+
print(f" - {plugin_id}: {install_info.get('spec', 'unknown')} (source: {install_info.get('source', 'unknown')})")
|
|
152
|
+
PYEOF
|
|
153
|
+
|
|
154
|
+
log_success "配置合并完成"
|
|
155
|
+
|
|
156
|
+
# ============ 完成 ============
|
|
157
|
+
echo ""
|
|
158
|
+
echo "============================================================"
|
|
159
|
+
log_success "迁移完成!"
|
|
160
|
+
echo ""
|
|
161
|
+
echo " 备份文件: $BACKUP_FILE"
|
|
162
|
+
echo " 如需回滚: cp \"$BACKUP_FILE\" \"$OPENCLAW_CONFIG\""
|
|
163
|
+
echo ""
|
|
164
|
+
echo " 下一步:重启 OpenClaw Gateway 使新插件生效"
|
|
165
|
+
echo " openclaw gateway --force"
|
|
166
|
+
echo "============================================================"
|
|
167
|
+
echo ""
|