openclaw-xiaoyou 1.2.0 → 1.2.2
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/docs/SKILL.md +32 -32
- package/docs/install-xiaoyou.sh +100 -24
- package/package.json +1 -1
- package/setup-entry.ts +1 -1
- package/src/channel.ts +70 -15
package/docs/SKILL.md
CHANGED
|
@@ -5,48 +5,48 @@ description: Use when users want to install, upgrade, uninstall, configure, or t
|
|
|
5
5
|
|
|
6
6
|
# 小优 Channel 安装入口
|
|
7
7
|
|
|
8
|
-
小优 channel
|
|
8
|
+
小优 channel 安装、升级、卸载统一使用远程脚本�?
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
https://d10.tfdl.net/public/2026-05-06/
|
|
11
|
+
https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
不要�?OpenClaw 的底层安装命令拆散执行。除非远程脚本失败且需要排障,否则直接调用 `install-xiaoyou.sh`�?
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## 触发�?
|
|
17
17
|
|
|
18
18
|
- "安装小优" / "小优安装"
|
|
19
19
|
- "小优接入" / "接入小优"
|
|
20
20
|
- "配置 xiaoyou" / "xiaoyou 配置"
|
|
21
21
|
- "升级小优" / "更新小优"
|
|
22
22
|
- "卸载小优" / "移除小优"
|
|
23
|
-
- "
|
|
23
|
+
- "我想用小�? / "启用小优"
|
|
24
24
|
- "小优 channel" / "xiaoyou channel"
|
|
25
25
|
|
|
26
26
|
## 标准执行
|
|
27
27
|
|
|
28
|
-
优先直接通过 `curl | bash`
|
|
28
|
+
优先直接通过 `curl | bash` 执行远程脚本�?
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
31
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s -- --ws-url ws://aiws-sim.haiersmarthomes.com:11055/xiaoyou/claw --token <AccessToken>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
### 参数说明
|
|
35
35
|
|
|
36
36
|
| 参数 | 必填 | 说明 |
|
|
37
37
|
|------|------|------|
|
|
38
|
-
| `--ws-url <url>` |
|
|
39
|
-
| `--token <token>` |
|
|
40
|
-
| `--version <ver>` |
|
|
41
|
-
| `--check-only` |
|
|
42
|
-
| `uninstall` |
|
|
38
|
+
| `--ws-url <url>` | �?首次安装 | 企业 WebSocket 服务地址,默�?`ws://aiws-sim.haiersmarthomes.com:11055/xiaoyou/claw` |
|
|
39
|
+
| `--token <token>` | �?首次安装 | 企业服务认证 Token |
|
|
40
|
+
| `--version <ver>` | �?| 指定 openclaw-xiaoyou 版本,默�?latest |
|
|
41
|
+
| `--check-only` | �?| 只输出计划,不执行真实改�?|
|
|
42
|
+
| `uninstall` | �?| 卸载小优 channel |
|
|
43
43
|
|
|
44
44
|
### 首次安装
|
|
45
45
|
|
|
46
|
-
用户必须提供 `--ws-url`
|
|
46
|
+
用户必须提供 `--ws-url` �?`--token`�?
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
49
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s -- --ws-url ws://aiws-sim.haiersmarthomes.com:11055/xiaoyou/claw --token my-enterprise-token
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
### 升级
|
|
@@ -54,30 +54,30 @@ curl -fsSL https://d10.tfdl.net/public/2026-05-06/e466d49d-4c5c-4fca-88dd-d69a38
|
|
|
54
54
|
已安装后的升级可以不传参数,脚本会复用现有配置:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
57
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s --
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
如果升级时传�?`--ws-url` �?`--token`,会覆盖现有配置�?
|
|
61
61
|
|
|
62
62
|
### 指定版本
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
65
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s -- --version 1.0.2 --ws-url ws://aiws-sim.haiersmarthomes.com:11055/xiaoyou/claw --token my-token
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
## 卸载
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
71
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s -- uninstall
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
卸载会删�?xiaoyou channel 配置、插件记录和扩展目录�?
|
|
75
75
|
|
|
76
76
|
## 预检
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
80
|
-
curl -fsSL https://d10.tfdl.net/public/2026-05-06/
|
|
79
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s -- --check-only
|
|
80
|
+
curl -fsSL https://d10.tfdl.net/public/2026-05-06/14dbf63d-d0aa-4b5d-bdd6-47eddb455f36/install-xiaoyou.sh | bash -s -- uninstall --check-only
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
## 失败处理
|
|
@@ -89,22 +89,22 @@ curl -fsSL https://d10.tfdl.net/public/2026-05-06/e466d49d-4c5c-4fca-88dd-d69a38
|
|
|
89
89
|
| 缺少 `--token` | 要求用户提供企业服务认证 Token |
|
|
90
90
|
| 未检测到 OpenClaw | 提示用户先安装并启动 OpenClaw |
|
|
91
91
|
| npm latest 查询失败 | 可让脚本继续幂等安装,或指定 `--version` |
|
|
92
|
-
| wsUrl
|
|
92
|
+
| wsUrl 格式不合�?| 地址必须�?`ws://` �?`wss://` 开�?|
|
|
93
93
|
|
|
94
|
-
##
|
|
94
|
+
## 脚本做了什�?
|
|
95
95
|
|
|
96
|
-
1.
|
|
97
|
-
2. 安装/升级 `openclaw-xiaoyou` 插件(`openclaw plugins install openclaw-xiaoyou@latest
|
|
98
|
-
3. 写入 channel
|
|
96
|
+
1. 检�?OpenClaw 是否已安装并运行
|
|
97
|
+
2. 安装/升级 `openclaw-xiaoyou` 插件(`openclaw plugins install openclaw-xiaoyou@latest`�?
|
|
98
|
+
3. 写入 channel 配置�?`~/.openclaw/openclaw.json`�?
|
|
99
99
|
- `channels.xiaoyou.enabled = true`
|
|
100
100
|
- `channels.xiaoyou.wsUrl = <用户提供的地址>`
|
|
101
|
-
- `channels.xiaoyou.authToken =
|
|
101
|
+
- `channels.xiaoyou.authToken = <用户提供�?token>`
|
|
102
102
|
- `channels.xiaoyou.dmSecurity = open`
|
|
103
|
-
4. 检查插件状态和 gateway
|
|
103
|
+
4. 检查插件状态和 gateway 运行状�?
|
|
104
104
|
|
|
105
105
|
## 完成定义
|
|
106
106
|
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
- 安装场景下,`openclaw xiaoyou status` 显示 connected
|
|
110
|
-
- 企业服务端能收到来自 xiaoyou
|
|
107
|
+
- 脚本退出码�?0�?
|
|
108
|
+
- 日志显示安装、升级或卸载流程完成�?
|
|
109
|
+
- 安装场景下,`openclaw xiaoyou status` 显示 connected�?
|
|
110
|
+
- 企业服务端能收到来自 xiaoyou 插件�?WebSocket 连接�?
|
package/docs/install-xiaoyou.sh
CHANGED
|
@@ -323,24 +323,57 @@ install_or_upgrade() {
|
|
|
323
323
|
patch_config() {
|
|
324
324
|
[[ -n "$WS_URL" || -n "$TOKEN" ]] || return 0
|
|
325
325
|
|
|
326
|
-
log "写入 xiaoyou channel
|
|
327
|
-
run openclaw config set "channels.${CHANNEL_KEY}.enabled" true --strict-json
|
|
326
|
+
log "写入 xiaoyou channel 配置(直接修改配置文件)"
|
|
328
327
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
fi
|
|
332
|
-
if [[ -n "$TOKEN" ]]; then
|
|
333
|
-
run openclaw config set "channels.${CHANNEL_KEY}.authToken" "$TOKEN"
|
|
334
|
-
fi
|
|
328
|
+
local config_file
|
|
329
|
+
config_file="$(openclaw_config_file)"
|
|
335
330
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
run openclaw config set "channels.${CHANNEL_KEY}.heartbeatTimeoutMs" 10000 --strict-json
|
|
331
|
+
if [[ ! -f "$config_file" ]]; then
|
|
332
|
+
die "配置文件不存在: $config_file"
|
|
333
|
+
fi
|
|
340
334
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
335
|
+
# 使用 python3 直接写入配置,绕过 openclaw config set 的 channel id 校验
|
|
336
|
+
python3 -c "
|
|
337
|
+
import json, sys
|
|
338
|
+
|
|
339
|
+
config_file = '$config_file'
|
|
340
|
+
ws_url = '$WS_URL'
|
|
341
|
+
token = '$TOKEN'
|
|
342
|
+
|
|
343
|
+
try:
|
|
344
|
+
with open(config_file, 'r') as f:
|
|
345
|
+
cfg = json.load(f)
|
|
346
|
+
except Exception as e:
|
|
347
|
+
print(f'[xiaoyou-install][error] 无法读取配置文件: {e}', file=sys.stderr)
|
|
348
|
+
sys.exit(1)
|
|
349
|
+
|
|
350
|
+
# 确保 channels 对象存在
|
|
351
|
+
cfg.setdefault('channels', {})
|
|
352
|
+
|
|
353
|
+
# 写入 xiaoyou channel 配置
|
|
354
|
+
xiaoyou = cfg['channels'].get('xiaoyou', {})
|
|
355
|
+
xiaoyou['enabled'] = True
|
|
356
|
+
if ws_url:
|
|
357
|
+
xiaoyou['wsUrl'] = ws_url
|
|
358
|
+
if token:
|
|
359
|
+
xiaoyou['authToken'] = token
|
|
360
|
+
xiaoyou.setdefault('dmSecurity', 'open')
|
|
361
|
+
xiaoyou.setdefault('allowFrom', ['*'])
|
|
362
|
+
xiaoyou.setdefault('reconnectIntervalMs', 3000)
|
|
363
|
+
xiaoyou.setdefault('heartbeatIntervalMs', 30000)
|
|
364
|
+
xiaoyou.setdefault('heartbeatTimeoutMs', 10000)
|
|
365
|
+
cfg['channels']['xiaoyou'] = xiaoyou
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
with open(config_file, 'w') as f:
|
|
369
|
+
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
|
370
|
+
print('[xiaoyou-install] 配置写入成功')
|
|
371
|
+
except Exception as e:
|
|
372
|
+
print(f'[xiaoyou-install][error] 写入配置失败: {e}', file=sys.stderr)
|
|
373
|
+
sys.exit(1)
|
|
374
|
+
" || die "写入配置失败"
|
|
375
|
+
|
|
376
|
+
log "已写入配置: $config_file"
|
|
344
377
|
}
|
|
345
378
|
|
|
346
379
|
# -----------------------------------------------------------------------------
|
|
@@ -375,11 +408,31 @@ xiayou_status() {
|
|
|
375
408
|
|
|
376
409
|
xiayou_uninstall_plugin_only() {
|
|
377
410
|
# 仅删除插件记录和文件,不删除配置(升级时用)
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
411
|
+
local config_file
|
|
412
|
+
config_file="$(openclaw_config_file)"
|
|
413
|
+
|
|
414
|
+
if [[ -f "$config_file" ]] && command_exists python3; then
|
|
415
|
+
python3 -c "
|
|
416
|
+
import json
|
|
417
|
+
config_file = '$config_file'
|
|
418
|
+
with open(config_file, 'r') as f:
|
|
419
|
+
cfg = json.load(f)
|
|
420
|
+
changed = False
|
|
421
|
+
for key in ['xiaoyou', 'openclaw-xiaoyou']:
|
|
422
|
+
if cfg.get('plugins', {}).get('entries', {}).pop(key, None): changed = True
|
|
423
|
+
if cfg.get('plugins', {}).get('installs', {}).pop(key, None): changed = True
|
|
424
|
+
allow = cfg.get('plugins', {}).get('allow', [])
|
|
425
|
+
if key in allow:
|
|
426
|
+
allow.remove(key)
|
|
427
|
+
changed = True
|
|
428
|
+
if changed:
|
|
429
|
+
with open(config_file, 'w') as f:
|
|
430
|
+
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
|
431
|
+
print('[xiaoyou-install] 已清理插件注册记录')
|
|
432
|
+
" || true
|
|
381
433
|
fi
|
|
382
|
-
|
|
434
|
+
|
|
435
|
+
run_or_dry_run rm -rf "$HOME/.openclaw/extensions/xiaoyou" "$HOME/.openclaw/extensions/openclaw-xiaoyou" "$HOME"/.openclaw/extensions/.openclaw-* || true
|
|
383
436
|
}
|
|
384
437
|
|
|
385
438
|
xiayou_uninstall() {
|
|
@@ -392,13 +445,29 @@ xiayou_uninstall() {
|
|
|
392
445
|
fi
|
|
393
446
|
|
|
394
447
|
log "开始卸载 xiaoyou channel"
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
448
|
+
|
|
449
|
+
local config_file
|
|
450
|
+
config_file="$(openclaw_config_file)"
|
|
451
|
+
|
|
452
|
+
if [[ -f "$config_file" ]] && command_exists python3; then
|
|
453
|
+
run_or_dry_run python3 -c "
|
|
454
|
+
import json
|
|
455
|
+
config_file = '$config_file'
|
|
456
|
+
with open(config_file, 'r') as f:
|
|
457
|
+
cfg = json.load(f)
|
|
458
|
+
cfg.get('channels', {}).pop('xiaoyou', None)
|
|
459
|
+
for key in ['xiaoyou', 'openclaw-xiaoyou']:
|
|
460
|
+
cfg.get('plugins', {}).get('entries', {}).pop(key, None)
|
|
461
|
+
cfg.get('plugins', {}).get('installs', {}).pop(key, None)
|
|
462
|
+
allow = cfg.get('plugins', {}).get('allow', [])
|
|
463
|
+
if key in allow: allow.remove(key)
|
|
464
|
+
with open(config_file, 'w') as f:
|
|
465
|
+
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
|
466
|
+
print('[xiaoyou-install] 已清理所有 xiaoyou 配置')
|
|
467
|
+
" || warn "清理配置失败"
|
|
399
468
|
fi
|
|
400
469
|
|
|
401
|
-
run_or_dry_run rm -rf "$HOME/.openclaw/extensions
|
|
470
|
+
run_or_dry_run rm -rf "$HOME/.openclaw/extensions/xiaoyou" "$HOME/.openclaw/extensions/openclaw-xiaoyou" "$HOME"/.openclaw/extensions/.openclaw-* || warn "删除插件文件失败"
|
|
402
471
|
|
|
403
472
|
if [[ "$CHECK_ONLY" -eq 1 ]]; then
|
|
404
473
|
phase_end "xiaoyou.uninstall" "planned" "check-only:已输出计划,未执行"
|
|
@@ -424,6 +493,13 @@ main() {
|
|
|
424
493
|
|
|
425
494
|
install_or_upgrade
|
|
426
495
|
|
|
496
|
+
# 重启 gateway 让插件和配置生效
|
|
497
|
+
if [[ "$CHECK_ONLY" -eq 0 ]] && openclaw_gateway_running; then
|
|
498
|
+
log "重启 gateway 以加载插件和配置..."
|
|
499
|
+
run openclaw gateway restart || warn "gateway 重启失败,请手动执行: openclaw gateway restart"
|
|
500
|
+
sleep 5
|
|
501
|
+
fi
|
|
502
|
+
|
|
427
503
|
log "完成。企业服务端应能收到来自 xiaoyou 插件的 WebSocket 连接。"
|
|
428
504
|
phase_end "main.entry" "ok" "安装流程完成"
|
|
429
505
|
}
|
package/package.json
CHANGED
package/setup-entry.ts
CHANGED
|
@@ -13,6 +13,6 @@ export default {
|
|
|
13
13
|
description: "Bridge OpenClaw to enterprise services via WebSocket",
|
|
14
14
|
setup: {
|
|
15
15
|
resolveAccount: xiayouPlugin.config.resolveAccount,
|
|
16
|
-
|
|
16
|
+
isConfigured: xiayouPlugin.config.isConfigured,
|
|
17
17
|
},
|
|
18
18
|
};
|
package/src/channel.ts
CHANGED
|
@@ -128,24 +128,79 @@ export const xiayouPlugin = {
|
|
|
128
128
|
account: resolved,
|
|
129
129
|
logger,
|
|
130
130
|
onMessage: async (msg) => {
|
|
131
|
-
const
|
|
132
|
-
if (!
|
|
133
|
-
logger.error("[xiaoyou] runtime not available, cannot dispatch");
|
|
131
|
+
const rt = getRuntime();
|
|
132
|
+
if (!rt || !rt.channel) {
|
|
133
|
+
logger.error("[xiaoyou] runtime.channel not available, cannot dispatch");
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
|
|
137
|
+
const senderId = msg.senderId;
|
|
138
|
+
const senderName = msg.senderName ?? msg.senderId;
|
|
139
|
+
const conversationId = msg.conversationId;
|
|
140
|
+
const text = msg.text ?? "";
|
|
141
|
+
const accountId = account?.accountId || "default";
|
|
142
|
+
|
|
143
|
+
// 1. 路由
|
|
144
|
+
const route = rt.channel.routing.resolveAgentRoute({
|
|
145
|
+
cfg: getChannelConfig(cfg) || {},
|
|
146
|
+
channel: "xiaoyou",
|
|
147
|
+
accountId,
|
|
148
|
+
peer: { kind: "direct", id: senderId },
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// 2. 格式化入站消息
|
|
152
|
+
const fromLabel = `${senderName} (${senderId})`;
|
|
153
|
+
const envelopeOptions = rt.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
154
|
+
const body = rt.channel.reply.formatInboundEnvelope({
|
|
155
|
+
channel: "Xiaoyou",
|
|
156
|
+
from: fromLabel,
|
|
157
|
+
timestamp: Date.now(),
|
|
158
|
+
body: text,
|
|
141
159
|
chatType: "direct",
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
sender: { name: senderName, id: senderId },
|
|
161
|
+
envelope: envelopeOptions,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// 3. 构建上下文
|
|
165
|
+
const inboundCtx = rt.channel.reply.finalizeInboundContext({
|
|
166
|
+
Body: body,
|
|
167
|
+
RawBody: text,
|
|
168
|
+
CommandBody: text,
|
|
169
|
+
From: conversationId,
|
|
170
|
+
To: conversationId,
|
|
171
|
+
SessionKey: route.sessionKey,
|
|
172
|
+
AccountId: accountId,
|
|
173
|
+
ChatType: "direct",
|
|
174
|
+
ConversationLabel: fromLabel,
|
|
175
|
+
SenderName: senderName,
|
|
176
|
+
SenderId: senderId,
|
|
177
|
+
Provider: "xiaoyou",
|
|
178
|
+
Surface: "xiaoyou",
|
|
179
|
+
MessageSid: `xiaoyou-${Date.now()}`,
|
|
180
|
+
Timestamp: Date.now(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// 4. 分发并获取回复
|
|
184
|
+
await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
185
|
+
ctx: inboundCtx,
|
|
186
|
+
cfg,
|
|
187
|
+
dispatcherOptions: {
|
|
188
|
+
responsePrefix: "",
|
|
189
|
+
deliver: async (payload: any) => {
|
|
190
|
+
const textToSend = payload.markdown || payload.text;
|
|
191
|
+
if (!textToSend) return;
|
|
192
|
+
if (_client && _client.isConnected()) {
|
|
193
|
+
_client.sendReply({
|
|
194
|
+
type: "reply",
|
|
195
|
+
conversationId,
|
|
196
|
+
messageId: `xiaoyou-${Date.now()}`,
|
|
197
|
+
text: textToSend,
|
|
198
|
+
timestamp: Date.now(),
|
|
199
|
+
});
|
|
200
|
+
logger.info(`[xiaoyou] reply sent to ${conversationId}`);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
},
|
|
149
204
|
});
|
|
150
205
|
},
|
|
151
206
|
});
|