openclaw-xiaoyou 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/README.md +163 -0
- package/config.example.json +35 -0
- package/demo-enterprise-server.ts +138 -0
- package/docs/Xiaoyou-SKILL.md +111 -0
- package/docs/communication-flow.md +639 -0
- package/docs/install-xiaoyou.sh +427 -0
- package/docs/publish-and-deploy.md +296 -0
- package/index.ts +70 -0
- package/openclaw.plugin.json +74 -0
- package/package.json +34 -0
- package/setup-entry.ts +18 -0
- package/src/channel.test.ts +140 -0
- package/src/channel.ts +218 -0
- package/src/enterprise-client.ts +190 -0
- package/src/onboarding.ts +76 -0
- package/src/types.ts +86 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# install-xiayou.sh — OpenClaw xiaoyou channel 一键安装/升级/卸载脚本
|
|
3
|
+
#
|
|
4
|
+
# 用法:
|
|
5
|
+
# install-xiayou.sh --ws-url <url> --token <token>
|
|
6
|
+
# install-xiayou.sh --version <ver> --ws-url <url> --token <token>
|
|
7
|
+
# install-xiayou.sh uninstall
|
|
8
|
+
# install-xiayou.sh --check-only
|
|
9
|
+
|
|
10
|
+
if [ -z "${BASH_VERSION:-}" ] || shopt -oq posix 2>/dev/null; then
|
|
11
|
+
if command -v bash >/dev/null 2>&1; then
|
|
12
|
+
exec bash "$0" "$@"
|
|
13
|
+
fi
|
|
14
|
+
printf '[xiaoyou-install][error] install-xiayou.sh 需要 bash\n' >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
set -Eeuo pipefail
|
|
19
|
+
|
|
20
|
+
SCRIPT_NAME="$(basename "$0")"
|
|
21
|
+
WS_URL=""
|
|
22
|
+
TOKEN=""
|
|
23
|
+
CHECK_ONLY=0
|
|
24
|
+
ACTION="install"
|
|
25
|
+
REQUESTED_VERSION=""
|
|
26
|
+
PLUGIN_NAME="openclaw-xiaoyou"
|
|
27
|
+
CHANNEL_KEY="xiaoyou"
|
|
28
|
+
STATUS_TIMEOUT="${XIAOYOU_INSTALL_STATUS_TIMEOUT:-30}"
|
|
29
|
+
LIST_TIMEOUT="${XIAOYOU_INSTALL_LIST_TIMEOUT:-30}"
|
|
30
|
+
LATEST_TIMEOUT="${XIAOYOU_INSTALL_LATEST_TIMEOUT:-15}"
|
|
31
|
+
OPENCLAW_PROCESS_PATTERN='openclaw-gateway|(^|[ /])openclaw[[:space:]]+gateway([[:space:]]|$)|(^|[ /])openclaw$'
|
|
32
|
+
|
|
33
|
+
# -----------------------------------------------------------------------------
|
|
34
|
+
# Logging helpers
|
|
35
|
+
# -----------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
log() { printf '[xiaoyou-install] %s\n' "$*"; }
|
|
38
|
+
warn() { printf '[xiaoyou-install][warn] %s\n' "$*" >&2; }
|
|
39
|
+
die() { printf '[xiaoyou-install][error] %s\n' "$*" >&2; exit 1; }
|
|
40
|
+
|
|
41
|
+
phase_start() {
|
|
42
|
+
printf '[xiaoyou-install][phase.start] name=%s\n' "$1"
|
|
43
|
+
printf '[xiaoyou-install][phase.start] will_do=%s\n' "$2"
|
|
44
|
+
printf '[xiaoyou-install][phase.start] why=%s\n' "$3"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
phase_end() {
|
|
48
|
+
printf '[xiaoyou-install][phase.end] name=%s\n' "$1"
|
|
49
|
+
printf '[xiaoyou-install][phase.end] result=%s\n' "$2"
|
|
50
|
+
printf '[xiaoyou-install][phase.end] summary=%s\n' "$3"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
command_exists() { command -v "$1" >/dev/null 2>&1; }
|
|
54
|
+
|
|
55
|
+
run() { log "run: $*"; "$@"; }
|
|
56
|
+
|
|
57
|
+
run_or_dry_run() {
|
|
58
|
+
if [[ "$CHECK_ONLY" -eq 1 ]]; then log "dry-run: $*"; return 0; fi
|
|
59
|
+
run "$@"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
capture_or_empty() { "$@" 2>/dev/null || true; }
|
|
63
|
+
|
|
64
|
+
capture_timeout_or_empty() {
|
|
65
|
+
local seconds="$1"; shift
|
|
66
|
+
if command_exists perl; then
|
|
67
|
+
perl -e '
|
|
68
|
+
use POSIX ":sys_wait_h";
|
|
69
|
+
my $timeout = shift @ARGV;
|
|
70
|
+
my $pid = fork(); exit 127 unless defined $pid;
|
|
71
|
+
if ($pid == 0) { exec @ARGV; exit 127; }
|
|
72
|
+
my $deadline = time() + $timeout;
|
|
73
|
+
while (1) {
|
|
74
|
+
my $done = waitpid($pid, WNOHANG);
|
|
75
|
+
if ($done == $pid) { exit($? >> 8); }
|
|
76
|
+
if (time() >= $deadline) { kill "TERM", $pid; sleep 1; kill "KILL", $pid; waitpid($pid, 0); exit 124; }
|
|
77
|
+
select undef, undef, undef, 0.1;
|
|
78
|
+
}
|
|
79
|
+
' "$seconds" "$@" 2>/dev/null || true
|
|
80
|
+
else
|
|
81
|
+
"$@" 2>/dev/null || true
|
|
82
|
+
fi
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# -----------------------------------------------------------------------------
|
|
86
|
+
# Argument parsing
|
|
87
|
+
# -----------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
usage() {
|
|
90
|
+
cat <<'USAGE'
|
|
91
|
+
Usage:
|
|
92
|
+
install-xiayou.sh --ws-url <url> --token <token>
|
|
93
|
+
install-xiayou.sh --version <ver> --ws-url <url> --token <token>
|
|
94
|
+
install-xiayou.sh uninstall
|
|
95
|
+
install-xiayou.sh --check-only
|
|
96
|
+
|
|
97
|
+
Options:
|
|
98
|
+
--ws-url <url> 企业 WebSocket 服务地址 (wss://... 或 ws://...)
|
|
99
|
+
--token <token> 企业服务认证 Token
|
|
100
|
+
--version <ver> 指定 openclaw-xiaoyou 版本 (默认 latest)
|
|
101
|
+
--check-only 只输出计划,不执行
|
|
102
|
+
uninstall 卸载 xiaoyou channel
|
|
103
|
+
USAGE
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
parse_args() {
|
|
107
|
+
while [[ $# -gt 0 ]]; do
|
|
108
|
+
case "$1" in
|
|
109
|
+
-h|--help) usage; exit 0 ;;
|
|
110
|
+
--ws-url)
|
|
111
|
+
[[ $# -ge 2 ]] || die "--ws-url 缺少参数"
|
|
112
|
+
WS_URL="$2"; shift 2 ;;
|
|
113
|
+
--token)
|
|
114
|
+
[[ $# -ge 2 ]] || die "--token 缺少参数"
|
|
115
|
+
TOKEN="$2"; shift 2 ;;
|
|
116
|
+
--version)
|
|
117
|
+
[[ $# -ge 2 ]] || die "--version 缺少参数"
|
|
118
|
+
REQUESTED_VERSION="$2"; shift 2 ;;
|
|
119
|
+
--check-only) CHECK_ONLY=1; shift ;;
|
|
120
|
+
uninstall) ACTION="uninstall"; shift ;;
|
|
121
|
+
--) shift; break ;;
|
|
122
|
+
-*) die "未知参数: $1" ;;
|
|
123
|
+
*)
|
|
124
|
+
# 兼容位置参数传 token
|
|
125
|
+
if [[ -z "$TOKEN" ]]; then TOKEN="$1"; shift
|
|
126
|
+
else die "多余的位置参数: $1"; fi ;;
|
|
127
|
+
esac
|
|
128
|
+
done
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
validate_ws_url() {
|
|
132
|
+
[[ -z "$WS_URL" ]] && return 0
|
|
133
|
+
if [[ ! "$WS_URL" =~ ^wss?:// ]]; then
|
|
134
|
+
die "--ws-url 格式不合法,必须以 ws:// 或 wss:// 开头。当前值: $WS_URL"
|
|
135
|
+
fi
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# -----------------------------------------------------------------------------
|
|
139
|
+
# Version helpers
|
|
140
|
+
# -----------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
extract_semver() {
|
|
143
|
+
printf '%s\n' "$1" | grep -Eo '[0-9]+(\.[0-9]+){1,2}' | head -n 1 || true
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
normalize_semver() {
|
|
147
|
+
local v="$1"; local major minor patch
|
|
148
|
+
IFS='.' read -r major minor patch <<<"$v"
|
|
149
|
+
printf '%s.%s.%s\n' "${major:-0}" "${minor:-0}" "${patch:-0}"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# -----------------------------------------------------------------------------
|
|
153
|
+
# Platform detection
|
|
154
|
+
# -----------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
process_lines() {
|
|
157
|
+
ps -axww -o pid,command 2>/dev/null || ps -axo pid,command 2>/dev/null || ps -ef 2>/dev/null || true
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
openclaw_gateway_running() {
|
|
161
|
+
process_lines | grep -E "$OPENCLAW_PROCESS_PATTERN" | grep -v grep | grep -v 'install-xiayou' >/dev/null 2>&1
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
openclaw_installed() {
|
|
165
|
+
command_exists openclaw || [[ -d "$HOME/.openclaw" ]]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
openclaw_version() {
|
|
169
|
+
local raw version
|
|
170
|
+
raw="$(capture_or_empty openclaw --version)"
|
|
171
|
+
version="$(extract_semver "$raw")"
|
|
172
|
+
[[ -n "$version" ]] || die "无法解析 OpenClaw 版本: $raw"
|
|
173
|
+
normalize_semver "$version"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# -----------------------------------------------------------------------------
|
|
177
|
+
# Read existing config
|
|
178
|
+
# -----------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
openclaw_config_file() {
|
|
181
|
+
local primary="$HOME/.openclaw/openclaw.json"
|
|
182
|
+
local legacy="$HOME/.openclaw/config.json"
|
|
183
|
+
if [[ -f "$primary" || ! -f "$legacy" ]]; then printf '%s\n' "$primary"
|
|
184
|
+
else printf '%s\n' "$legacy"; fi
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
existing_ws_url() {
|
|
188
|
+
local cfg; cfg="$(openclaw_config_file)"
|
|
189
|
+
[[ -f "$cfg" ]] || return 0
|
|
190
|
+
cat "$cfg" 2>/dev/null | grep -Eo '"wsUrl"[[:space:]]*:[[:space:]]*"[^"]*"' | head -n 1 | sed -E 's/.*"wsUrl"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/' || true
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
existing_auth_token() {
|
|
194
|
+
local cfg; cfg="$(openclaw_config_file)"
|
|
195
|
+
[[ -f "$cfg" ]] || return 0
|
|
196
|
+
cat "$cfg" 2>/dev/null | grep -Eo '"authToken"[[:space:]]*:[[:space:]]*"[^"]*"' | head -n 1 | sed -E 's/.*"authToken"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/' || true
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
installed_plugin_version() {
|
|
200
|
+
local list line
|
|
201
|
+
list="$(capture_timeout_or_empty "$LIST_TIMEOUT" openclaw plugins list)"
|
|
202
|
+
line="$(printf '%s\n' "$list" | grep -E "$PLUGIN_NAME" | head -n 1 || true)"
|
|
203
|
+
[[ -n "$line" ]] || return 0
|
|
204
|
+
printf '%s\n' "$line" | grep -Eo '[0-9]+(\.[0-9]+){1,2}' | head -n 1 || true
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
npm_latest_version() {
|
|
208
|
+
capture_timeout_or_empty "$LATEST_TIMEOUT" npm view "$PLUGIN_NAME" version
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# -----------------------------------------------------------------------------
|
|
212
|
+
# Install / Upgrade
|
|
213
|
+
# -----------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
install_or_upgrade() {
|
|
216
|
+
phase_start \
|
|
217
|
+
"xiaoyou.install-or-upgrade" \
|
|
218
|
+
"安装或升级 $PLUGIN_NAME 插件,并写入 xiaoyou channel 配置" \
|
|
219
|
+
"需要确保插件版本可用,且 wsUrl/authToken 配置完整"
|
|
220
|
+
|
|
221
|
+
command_exists openclaw || die "未找到 openclaw 命令,请先安装 OpenClaw"
|
|
222
|
+
|
|
223
|
+
local version current latest should_install=0 target final_summary=""
|
|
224
|
+
version="$(openclaw_version)"
|
|
225
|
+
log "OpenClaw version: $version"
|
|
226
|
+
|
|
227
|
+
# 确定目标包
|
|
228
|
+
if [[ -n "$REQUESTED_VERSION" ]]; then
|
|
229
|
+
target="${PLUGIN_NAME}@${REQUESTED_VERSION}"
|
|
230
|
+
else
|
|
231
|
+
target="${PLUGIN_NAME}@latest"
|
|
232
|
+
fi
|
|
233
|
+
log "target package: $target"
|
|
234
|
+
|
|
235
|
+
# 检查已安装版本
|
|
236
|
+
current="$(installed_plugin_version || true)"
|
|
237
|
+
current="${current:-}"
|
|
238
|
+
log "installed $PLUGIN_NAME version: ${current:-<none>}"
|
|
239
|
+
|
|
240
|
+
# 决定是否需要安装
|
|
241
|
+
if [[ -z "$current" ]]; then
|
|
242
|
+
log "未检测到 $PLUGIN_NAME 插件,进入安装流程"
|
|
243
|
+
should_install=1
|
|
244
|
+
elif [[ -n "$REQUESTED_VERSION" ]]; then
|
|
245
|
+
if [[ "$current" == "$REQUESTED_VERSION" ]]; then
|
|
246
|
+
log "已安装指定版本 $REQUESTED_VERSION,无需重新安装"
|
|
247
|
+
else
|
|
248
|
+
log "当前 ${current},目标 ${REQUESTED_VERSION},需要升级"
|
|
249
|
+
should_install=1
|
|
250
|
+
fi
|
|
251
|
+
else
|
|
252
|
+
latest="$(npm_latest_version || true)"
|
|
253
|
+
latest="${latest:-}"
|
|
254
|
+
log "npm latest $PLUGIN_NAME: ${latest:-<unknown>}"
|
|
255
|
+
if [[ -z "$latest" ]]; then
|
|
256
|
+
warn "无法查询 npm latest,执行幂等安装"
|
|
257
|
+
should_install=1
|
|
258
|
+
elif [[ "$current" != "$latest" ]]; then
|
|
259
|
+
log "当前 ${current},latest ${latest},需要升级"
|
|
260
|
+
should_install=1
|
|
261
|
+
else
|
|
262
|
+
log "$PLUGIN_NAME 已是最新版本: $current"
|
|
263
|
+
fi
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
# 首次安装必须有 ws-url 和 token
|
|
267
|
+
if [[ -z "$current" && "$CHECK_ONLY" -eq 0 ]]; then
|
|
268
|
+
if [[ -z "$WS_URL" ]]; then
|
|
269
|
+
die "首次安装必须提供 --ws-url。请运行: $SCRIPT_NAME --ws-url <url> --token <token>"
|
|
270
|
+
fi
|
|
271
|
+
if [[ -z "$TOKEN" ]]; then
|
|
272
|
+
die "首次安装必须提供 --token。请运行: $SCRIPT_NAME --ws-url <url> --token <token>"
|
|
273
|
+
fi
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# 升级时复用现有配置
|
|
277
|
+
if [[ -n "$current" ]]; then
|
|
278
|
+
if [[ -z "$WS_URL" ]]; then
|
|
279
|
+
WS_URL="$(existing_ws_url || true)"
|
|
280
|
+
WS_URL="${WS_URL:-}"
|
|
281
|
+
[[ -n "$WS_URL" ]] && log "复用现有 wsUrl: $WS_URL"
|
|
282
|
+
fi
|
|
283
|
+
if [[ -z "$TOKEN" ]]; then
|
|
284
|
+
TOKEN="$(existing_auth_token || true)"
|
|
285
|
+
TOKEN="${TOKEN:-}"
|
|
286
|
+
[[ -n "$TOKEN" ]] && log "复用现有 authToken"
|
|
287
|
+
fi
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
# 执行
|
|
291
|
+
if [[ "$CHECK_ONLY" -eq 1 ]]; then
|
|
292
|
+
if [[ "$should_install" -eq 1 ]]; then
|
|
293
|
+
final_summary="check-only:需要安装 $target,但当前只输出计划"
|
|
294
|
+
else
|
|
295
|
+
final_summary="check-only:当前版本满足要求,无需安装或升级"
|
|
296
|
+
fi
|
|
297
|
+
log "$final_summary"
|
|
298
|
+
elif [[ "$should_install" -eq 1 ]]; then
|
|
299
|
+
if [[ -n "$current" ]]; then
|
|
300
|
+
log "升级流程:先卸载旧插件,再安装新版本"
|
|
301
|
+
xiayou_uninstall_plugin_only
|
|
302
|
+
fi
|
|
303
|
+
run env NPM_CONFIG_LEGACY_PEER_DEPS=true openclaw plugins install "$target"
|
|
304
|
+
final_summary="已安装 $target"
|
|
305
|
+
else
|
|
306
|
+
final_summary="无需安装或升级"
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
# 写入配置
|
|
310
|
+
if [[ "$CHECK_ONLY" -eq 0 ]]; then
|
|
311
|
+
patch_config
|
|
312
|
+
final_summary="${final_summary},已写入 channel 配置"
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
xiayou_status
|
|
316
|
+
phase_end "xiaoyou.install-or-upgrade" "ok" "$final_summary"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
patch_config() {
|
|
320
|
+
[[ -n "$WS_URL" || -n "$TOKEN" ]] || return 0
|
|
321
|
+
|
|
322
|
+
log "写入 xiaoyou channel 配置"
|
|
323
|
+
run openclaw config set "channels.${CHANNEL_KEY}.enabled" true --strict-json
|
|
324
|
+
|
|
325
|
+
if [[ -n "$WS_URL" ]]; then
|
|
326
|
+
run openclaw config set "channels.${CHANNEL_KEY}.wsUrl" "$WS_URL"
|
|
327
|
+
fi
|
|
328
|
+
if [[ -n "$TOKEN" ]]; then
|
|
329
|
+
run openclaw config set "channels.${CHANNEL_KEY}.authToken" "$TOKEN"
|
|
330
|
+
fi
|
|
331
|
+
|
|
332
|
+
run openclaw config set "channels.${CHANNEL_KEY}.dmSecurity" open
|
|
333
|
+
run openclaw config set "channels.${CHANNEL_KEY}.reconnectIntervalMs" 3000 --strict-json
|
|
334
|
+
run openclaw config set "channels.${CHANNEL_KEY}.heartbeatIntervalMs" 30000 --strict-json
|
|
335
|
+
run openclaw config set "channels.${CHANNEL_KEY}.heartbeatTimeoutMs" 10000 --strict-json
|
|
336
|
+
|
|
337
|
+
local config_file
|
|
338
|
+
config_file="$(capture_or_empty openclaw config file)"
|
|
339
|
+
log "已写入配置: ${config_file:-$(openclaw_config_file)}"
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# -----------------------------------------------------------------------------
|
|
343
|
+
# Status
|
|
344
|
+
# -----------------------------------------------------------------------------
|
|
345
|
+
|
|
346
|
+
xiayou_status() {
|
|
347
|
+
phase_start "xiaoyou.status" "检查 xiaoyou channel 状态" "确认插件已被识别且 gateway 在运行"
|
|
348
|
+
log "状态检测"
|
|
349
|
+
|
|
350
|
+
if openclaw_gateway_running; then
|
|
351
|
+
local output
|
|
352
|
+
output="$(capture_timeout_or_empty "$STATUS_TIMEOUT" openclaw status)"
|
|
353
|
+
if [[ -n "$output" ]]; then
|
|
354
|
+
printf '%s\n' "$output"
|
|
355
|
+
phase_end "xiaoyou.status" "ok" "gateway 运行中,已输出状态"
|
|
356
|
+
else
|
|
357
|
+
warn "openclaw status 在 ${STATUS_TIMEOUT}s 内未返回"
|
|
358
|
+
phase_end "xiaoyou.status" "warning" "gateway 运行中但 status 超时"
|
|
359
|
+
fi
|
|
360
|
+
else
|
|
361
|
+
capture_timeout_or_empty "$LIST_TIMEOUT" openclaw plugins list | grep -E "$PLUGIN_NAME|$CHANNEL_KEY" || true
|
|
362
|
+
capture_timeout_or_empty "$STATUS_TIMEOUT" openclaw channels list | grep -Ei "$CHANNEL_KEY|xiaoyou" || true
|
|
363
|
+
warn "未检测到运行中的 OpenClaw gateway;请运行 openclaw gateway 或 openclaw gateway restart"
|
|
364
|
+
phase_end "xiaoyou.status" "warning" "gateway 未运行,已退回到插件/渠道列表检查"
|
|
365
|
+
fi
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
# -----------------------------------------------------------------------------
|
|
369
|
+
# Uninstall
|
|
370
|
+
# -----------------------------------------------------------------------------
|
|
371
|
+
|
|
372
|
+
xiayou_uninstall_plugin_only() {
|
|
373
|
+
# 仅删除插件记录和文件,不删除配置(升级时用)
|
|
374
|
+
if command_exists openclaw; then
|
|
375
|
+
run_or_dry_run openclaw config unset "plugins.entries.${PLUGIN_NAME}" || true
|
|
376
|
+
run_or_dry_run openclaw config unset "plugins.installs.${PLUGIN_NAME}" || true
|
|
377
|
+
fi
|
|
378
|
+
run_or_dry_run rm -rf "$HOME/.openclaw/extensions/${PLUGIN_NAME}" "$HOME"/.openclaw/extensions/.openclaw-* || true
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
xiayou_uninstall() {
|
|
382
|
+
phase_start "xiaoyou.uninstall" "删除 xiaoyou channel 配置、插件记录和扩展目录" "清理所有 xiaoyou 相关状态"
|
|
383
|
+
|
|
384
|
+
if ! openclaw_installed; then
|
|
385
|
+
log "未检测到 OpenClaw,跳过卸载"
|
|
386
|
+
phase_end "xiaoyou.uninstall" "skipped" "未检测到 OpenClaw"
|
|
387
|
+
return 0
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
log "开始卸载 xiaoyou channel"
|
|
391
|
+
if command_exists openclaw; then
|
|
392
|
+
run_or_dry_run openclaw config unset "channels.${CHANNEL_KEY}" || warn "删除 channels.${CHANNEL_KEY} 失败"
|
|
393
|
+
run_or_dry_run openclaw config unset "plugins.entries.${PLUGIN_NAME}" || warn "删除 plugins.entries 失败"
|
|
394
|
+
run_or_dry_run openclaw config unset "plugins.installs.${PLUGIN_NAME}" || warn "删除 plugins.installs 失败"
|
|
395
|
+
fi
|
|
396
|
+
|
|
397
|
+
run_or_dry_run rm -rf "$HOME/.openclaw/extensions/${PLUGIN_NAME}" "$HOME"/.openclaw/extensions/.openclaw-* || warn "删除插件文件失败"
|
|
398
|
+
|
|
399
|
+
if [[ "$CHECK_ONLY" -eq 1 ]]; then
|
|
400
|
+
phase_end "xiaoyou.uninstall" "planned" "check-only:已输出计划,未执行"
|
|
401
|
+
else
|
|
402
|
+
phase_end "xiaoyou.uninstall" "ok" "已完成 xiaoyou channel 卸载"
|
|
403
|
+
fi
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
# -----------------------------------------------------------------------------
|
|
407
|
+
# Entrypoint
|
|
408
|
+
# -----------------------------------------------------------------------------
|
|
409
|
+
|
|
410
|
+
main() {
|
|
411
|
+
phase_start "main.entry" "解析参数并进入安装或卸载分支" "调度入口"
|
|
412
|
+
parse_args "$@"
|
|
413
|
+
validate_ws_url
|
|
414
|
+
|
|
415
|
+
if [[ "$ACTION" == "uninstall" ]]; then
|
|
416
|
+
xiayou_uninstall
|
|
417
|
+
phase_end "main.entry" "ok" "卸载流程完成"
|
|
418
|
+
return 0
|
|
419
|
+
fi
|
|
420
|
+
|
|
421
|
+
install_or_upgrade
|
|
422
|
+
|
|
423
|
+
log "完成。企业服务端应能收到来自 xiaoyou 插件的 WebSocket 连接。"
|
|
424
|
+
phase_end "main.entry" "ok" "安装流程完成"
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
main "$@"
|