lightclawbot 1.1.0 → 1.1.2-beta.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/dist/public/data/scripts/manifest.json +11 -0
- package/dist/public/data/scripts/upgrade.156d7999.sh +384 -0
- package/dist/public/data/scripts/upgrade.sh +384 -0
- package/dist/src/upload-tool.d.ts.map +1 -1
- package/dist/src/upload-tool.js +10 -5
- package/dist/src/upload-tool.js.map +1 -1
- package/package.json +2 -5
- package/skills/lightclaw-cron/SKILL.md +2 -1
- package/dist/src/socket-handlers.d.ts +0 -21
- package/dist/src/socket-handlers.d.ts.map +0 -1
- package/dist/src/socket-handlers.js +0 -122
- package/dist/src/socket-handlers.js.map +0 -1
- package/dist/src/socket-registry.d.ts +0 -53
- package/dist/src/socket-registry.d.ts.map +0 -1
- package/dist/src/socket-registry.js +0 -111
- package/dist/src/socket-registry.js.map +0 -1
- package/skills/lightclaw-media/SKILL.md +0 -250
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# ========== lightclawbot 插件快速安装/升级脚本 ==========
|
|
5
|
+
# 用途:跳过 openclaw plugins install 的慢路径,直接安装/升级 lightclawbot 插件
|
|
6
|
+
# 前提:openclaw 已安装且可用,pnpm 或 npm 已安装(不依赖 jq,JSON 操作统一用 node)
|
|
7
|
+
# 支持:首次安装 / 重装 / 升级,自动保留已有的 channels 配置
|
|
8
|
+
#
|
|
9
|
+
# 输出规范:stdout 输出多行,供前端逐行解析
|
|
10
|
+
# - 步骤进度:STEP:{"step":"step_id","message":"描述"}:
|
|
11
|
+
# 7 处 step_log 调用 分别在环境检查、版本检查、下载、解压、配置更新、设备审批、重启网关前输出
|
|
12
|
+
# STEP:{"step":"env_check","message":"checking environment"}
|
|
13
|
+
# STEP:{"step":"version_check","message":"checking version info"}
|
|
14
|
+
# STEP:{"step":"download","message":"downloading plugin"}
|
|
15
|
+
# STEP:{"step":"extract","message":"extracting and installing"}
|
|
16
|
+
# STEP:{"step":"config_update","message":"updating configuration"}
|
|
17
|
+
# STEP:{"step":"devices_approve","message":"approving devices"}
|
|
18
|
+
# STEP:{"step":"gateway_restart","message":"restarting gateway"}
|
|
19
|
+
# - 最终成功:RESULT:{"status":"ok","version":"x.y.z"}
|
|
20
|
+
# - 最终失败:RESULT:{"status":"error","reason":"..."}
|
|
21
|
+
#
|
|
22
|
+
# 使用方式:
|
|
23
|
+
# 本地执行: bash scripts/upgrade.sh
|
|
24
|
+
# CDN 执行: bash <(curl -fsSL https://your-cdn.com/upgrade.sh)
|
|
25
|
+
# 传入参数: APIKEY="sk-xxx" bash <(curl -fsSL https://your-cdn.com/upgrade.sh)
|
|
26
|
+
# 跳过重启: RESTART_GATEWAY=false APIKEY="sk-xxx" bash <(curl -fsSL https://your-cdn.com/upgrade.sh)
|
|
27
|
+
|
|
28
|
+
# ========== 工具函数 ==========
|
|
29
|
+
|
|
30
|
+
# 输出步骤进度,供前端逐行解析
|
|
31
|
+
step_log() {
|
|
32
|
+
local step="$1"
|
|
33
|
+
local message="$2"
|
|
34
|
+
echo "STEP:{\"step\":\"${step}\",\"message\":\"${message}\"}"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
result_exit() {
|
|
38
|
+
local reason="$1"
|
|
39
|
+
echo "RESULT:{\"status\":\"error\",\"reason\":\"${reason}\"}"
|
|
40
|
+
exit 1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
result_ok() {
|
|
44
|
+
echo "RESULT:{\"status\":\"ok\",\"version\":\"${1}\"}"
|
|
45
|
+
exit 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# semver 比较:left >= right 返回 0,否则返回 1,解析失败返回 2
|
|
49
|
+
version_gte() {
|
|
50
|
+
local left="$1"
|
|
51
|
+
local right="$2"
|
|
52
|
+
VERSION_LEFT="$left" VERSION_RIGHT="$right" node - <<'NODE'
|
|
53
|
+
function parseSemver(value) {
|
|
54
|
+
const match = String(value || "").trim().match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
|
|
55
|
+
if (!match) return null;
|
|
56
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
57
|
+
}
|
|
58
|
+
const left = parseSemver(process.env.VERSION_LEFT);
|
|
59
|
+
const right = parseSemver(process.env.VERSION_RIGHT);
|
|
60
|
+
if (!left || !right) process.exit(2);
|
|
61
|
+
for (let i = 0; i < 3; i++) {
|
|
62
|
+
if (left[i] > right[i]) process.exit(0);
|
|
63
|
+
if (left[i] < right[i]) process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
process.exit(0);
|
|
66
|
+
NODE
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# 获取本机 openclaw 版本号(纯数字 x.y.z 格式)
|
|
70
|
+
get_openclaw_version() {
|
|
71
|
+
if ! command -v openclaw &>/dev/null; then
|
|
72
|
+
echo ""
|
|
73
|
+
return
|
|
74
|
+
fi
|
|
75
|
+
local raw
|
|
76
|
+
raw=$(openclaw -v 2>/dev/null || true)
|
|
77
|
+
echo "$raw" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# ========== 配置 ==========
|
|
81
|
+
|
|
82
|
+
id="lightclawbot"
|
|
83
|
+
spec="lightclawbot"
|
|
84
|
+
cfg="$HOME/.openclaw/openclaw.json"
|
|
85
|
+
plugin_dir="$HOME/.openclaw/extensions/${id}"
|
|
86
|
+
|
|
87
|
+
# npm 源:使用腾讯镜像源(可通过 NPM_REGISTRY 环境变量覆盖)
|
|
88
|
+
NPM_REGISTRY="${NPM_REGISTRY:-https://mirrors.tencent.com/npm/}"
|
|
89
|
+
# fallback 源:首选失败时兜底(可通过 NPM_FALLBACK 环境变量覆盖)
|
|
90
|
+
NPM_FALLBACK="${NPM_FALLBACK:-https://registry.npmjs.org}"
|
|
91
|
+
|
|
92
|
+
# API Key:优先读取环境变量,为空则保留配置文件中已有的值
|
|
93
|
+
# 用法:APIKEY="sk-xxx" bash <(curl -fsSL https://your-cdn.com/upgrade.sh)
|
|
94
|
+
APIKEY="${APIKEY:-}"
|
|
95
|
+
|
|
96
|
+
# 是否在安装/升级后重启 Gateway:默认 true,传入 false 可跳过重启
|
|
97
|
+
# 用法:RESTART_GATEWAY=false bash <(curl -fsSL https://your-cdn.com/upgrade.sh)
|
|
98
|
+
RESTART_GATEWAY="${RESTART_GATEWAY:-true}"
|
|
99
|
+
|
|
100
|
+
# openclaw 新老版本分界线:>= 此版本使用最新插件,< 此版本锁定 LEGACY_PLUGIN_VERSION
|
|
101
|
+
OPENCLAW_BREAKING_VERSION="2026.3.22"
|
|
102
|
+
LEGACY_PLUGIN_VERSION="1.0.8"
|
|
103
|
+
|
|
104
|
+
# openclaw = 此版本需要执行 devices approve
|
|
105
|
+
OPENCLAW_DEVICES_APPROVE_VERSION="2026.3.28"
|
|
106
|
+
|
|
107
|
+
# ========== 环境加载 ==========
|
|
108
|
+
# bash xxx.sh 启动的是非交互式 shell,不会自动 source ~/.bashrc,
|
|
109
|
+
# 如果用户通过 nvm 安装 node,脚本中的 node/pnpm/openclaw 都找不到。
|
|
110
|
+
|
|
111
|
+
export NVM_DIR="$HOME/.nvm"
|
|
112
|
+
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
113
|
+
|
|
114
|
+
if [ -z "$PNPM_HOME" ] && [ -d "$HOME/.local/share/pnpm" ]; then
|
|
115
|
+
export PNPM_HOME="$HOME/.local/share/pnpm"
|
|
116
|
+
export PATH="$PNPM_HOME:$PATH"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
[ ! -t 1 ] && export CI=true
|
|
120
|
+
|
|
121
|
+
# ========== 前置检查 ==========
|
|
122
|
+
|
|
123
|
+
step_log "env_check" "checking environment"
|
|
124
|
+
|
|
125
|
+
# 1) 探测包管理器:优先 pnpm,fallback npm,都没有则报错
|
|
126
|
+
if command -v pnpm &>/dev/null; then
|
|
127
|
+
PKG_MGR="pnpm"
|
|
128
|
+
elif command -v npm &>/dev/null; then
|
|
129
|
+
PKG_MGR="npm"
|
|
130
|
+
else
|
|
131
|
+
result_exit "npm_not_found"
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# 2) 检查 openclaw 是否可用
|
|
135
|
+
if ! openclaw -v &>/dev/null; then
|
|
136
|
+
result_exit "openclaw_not_available"
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# 3) 设置 npm/pnpm 源(确保后续 pack/install 都走镜像源)
|
|
140
|
+
npm config set registry "$NPM_REGISTRY" 2>/dev/null || true
|
|
141
|
+
[ "$PKG_MGR" = "pnpm" ] && pnpm config set registry "$NPM_REGISTRY" 2>/dev/null || true
|
|
142
|
+
|
|
143
|
+
# 4) 检查 APIKEY
|
|
144
|
+
if [ -z "$APIKEY" ]; then
|
|
145
|
+
result_exit "apikey_empty"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# ========== 安装 / 升级 lightclawbot ==========
|
|
149
|
+
|
|
150
|
+
step_log "version_check" "checking version info"
|
|
151
|
+
|
|
152
|
+
# ---------- 检查是否已安装,获取本地版本 ----------
|
|
153
|
+
local_version=""
|
|
154
|
+
if [ -d "$plugin_dir" ] && [ -f "$plugin_dir/package.json" ]; then
|
|
155
|
+
local_version=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync(process.argv[1],'utf8')).version||'')}catch(e){console.log('')}" "$plugin_dir/package.json" 2>/dev/null || true)
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# ---------- 获取 openclaw 版本,确定目标插件版本 ----------
|
|
159
|
+
openclaw_version=$(get_openclaw_version)
|
|
160
|
+
target_spec="$spec"
|
|
161
|
+
|
|
162
|
+
if [ -n "$openclaw_version" ]; then
|
|
163
|
+
if version_gte "$openclaw_version" "$OPENCLAW_BREAKING_VERSION"; then
|
|
164
|
+
# openclaw >= 2026.3.22 → 安装最新版插件
|
|
165
|
+
target_spec="$spec"
|
|
166
|
+
else
|
|
167
|
+
# openclaw < 2026.3.22 → 锁定旧版插件
|
|
168
|
+
target_spec="${spec}@${LEGACY_PLUGIN_VERSION}"
|
|
169
|
+
fi
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# ---------- 查询远程目标版本 ----------
|
|
173
|
+
remote_version=""
|
|
174
|
+
|
|
175
|
+
if [ -n "$openclaw_version" ] && ! version_gte "$openclaw_version" "$OPENCLAW_BREAKING_VERSION"; then
|
|
176
|
+
# 旧版 openclaw:版本已锁定
|
|
177
|
+
remote_version="$LEGACY_PLUGIN_VERSION"
|
|
178
|
+
else
|
|
179
|
+
remote_version=$(npm view "$spec" version 2>/dev/null || true)
|
|
180
|
+
|
|
181
|
+
if [ -z "$remote_version" ]; then
|
|
182
|
+
remote_version=$(npm view "$spec" version --registry "$NPM_FALLBACK" 2>/dev/null || true)
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# ---------- 判断安装模式 ----------
|
|
187
|
+
install_mode="install"
|
|
188
|
+
if [ -n "$local_version" ]; then
|
|
189
|
+
if [ -n "$remote_version" ] && [ "$local_version" = "$remote_version" ]; then
|
|
190
|
+
install_mode="up-to-date"
|
|
191
|
+
else
|
|
192
|
+
install_mode="upgrade"
|
|
193
|
+
fi
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
if [ "$install_mode" != "up-to-date" ]; then
|
|
197
|
+
# ---------- 清理旧版本 ----------
|
|
198
|
+
rm -rf "$plugin_dir"
|
|
199
|
+
|
|
200
|
+
step_log "download" "downloading plugin"
|
|
201
|
+
|
|
202
|
+
# ---------- npm pack 下载 tgz ----------
|
|
203
|
+
tmp_dir=$(mktemp -d /tmp/openclaw-plugin-XXXXXX)
|
|
204
|
+
|
|
205
|
+
tgz_file=$(cd "$tmp_dir" && npm pack "$target_spec" 2>/dev/null | tail -n1)
|
|
206
|
+
if [ -z "$tgz_file" ] || [ ! -f "$tmp_dir/$tgz_file" ]; then
|
|
207
|
+
tgz_file=$(cd "$tmp_dir" && npm pack "$target_spec" --registry "$NPM_FALLBACK" 2>/dev/null | tail -n1)
|
|
208
|
+
fi
|
|
209
|
+
if [ -z "$tgz_file" ] || [ ! -f "$tmp_dir/$tgz_file" ]; then
|
|
210
|
+
rm -rf "$tmp_dir"
|
|
211
|
+
result_exit "download_failed"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
step_log "extract" "extracting and installing"
|
|
215
|
+
|
|
216
|
+
# ---------- 解压到插件目录 ----------
|
|
217
|
+
mkdir -p "$plugin_dir"
|
|
218
|
+
tar -xzf "$tmp_dir/$tgz_file" -C "$plugin_dir" --strip-components=1
|
|
219
|
+
rm -rf "$tmp_dir"
|
|
220
|
+
|
|
221
|
+
# ---------- 安装生产依赖 ----------
|
|
222
|
+
# lightclawbot 声明了 bundledDependencies,npm pack 产出的 tgz 已包含所有依赖
|
|
223
|
+
has_unbundled_deps=$(node -e '
|
|
224
|
+
const pkg = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
|
|
225
|
+
const deps = Object.keys(pkg.dependencies || {});
|
|
226
|
+
const bundled = pkg.bundledDependencies || pkg.bundleDependencies || [];
|
|
227
|
+
console.log(deps.length > 0 && bundled.length < deps.length ? "true" : "false");
|
|
228
|
+
' "$plugin_dir/package.json")
|
|
229
|
+
|
|
230
|
+
if [ "$has_unbundled_deps" = true ]; then
|
|
231
|
+
(cd "$plugin_dir" && CI=true $PKG_MGR install --prod) >/dev/null 2>&1
|
|
232
|
+
fi
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
# ========== 更新配置文件 ==========
|
|
236
|
+
|
|
237
|
+
step_log "config_update" "updating configuration"
|
|
238
|
+
|
|
239
|
+
# 确保配置文件存在
|
|
240
|
+
if [ ! -f "$cfg" ]; then
|
|
241
|
+
mkdir -p "$(dirname "$cfg")"
|
|
242
|
+
echo '{}' > "$cfg"
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
# 校验配置文件是合法 JSON(用户可能手动编辑弄坏了格式)
|
|
246
|
+
if ! node -e "JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))" "$cfg" 2>/dev/null; then
|
|
247
|
+
result_exit "config_json_invalid"
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# ---------- 单次 node 调用完成所有配置更新 ----------
|
|
251
|
+
# 一次启动 V8,通过环境变量安全传参,
|
|
252
|
+
# 顺序完成 plugins.entries / installs / deny / allow / channels 全部配置修改,
|
|
253
|
+
# 减少文件 I/O 次数(只读一次 + 写一次)。
|
|
254
|
+
|
|
255
|
+
version=$(UPGRADE_CFG="$cfg" UPGRADE_ID="$id" UPGRADE_SPEC="$spec" \
|
|
256
|
+
UPGRADE_PLUGIN_DIR="$plugin_dir" UPGRADE_APIKEY="$APIKEY" \
|
|
257
|
+
node -e '
|
|
258
|
+
const fs = require("fs");
|
|
259
|
+
const cfgPath = process.env.UPGRADE_CFG;
|
|
260
|
+
const pluginId = process.env.UPGRADE_ID;
|
|
261
|
+
const spec = process.env.UPGRADE_SPEC;
|
|
262
|
+
const pluginDir = process.env.UPGRADE_PLUGIN_DIR;
|
|
263
|
+
const envApiKey = process.env.UPGRADE_APIKEY || "";
|
|
264
|
+
|
|
265
|
+
function fail(reason) {
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// 读取配置
|
|
270
|
+
let cfg;
|
|
271
|
+
try {
|
|
272
|
+
cfg = JSON.parse(fs.readFileSync(cfgPath, "utf8"));
|
|
273
|
+
} catch (e) {
|
|
274
|
+
fail("config_read_failed");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 读取插件版本
|
|
278
|
+
let version = "unknown";
|
|
279
|
+
try {
|
|
280
|
+
const pkg = JSON.parse(fs.readFileSync(pluginDir + "/package.json", "utf8"));
|
|
281
|
+
version = pkg.version || "unknown";
|
|
282
|
+
} catch (e) {}
|
|
283
|
+
|
|
284
|
+
// ---------- 1) 确保 plugins 基础结构存在 & 全局插件系统启用 ----------
|
|
285
|
+
if (!cfg.plugins) cfg.plugins = {};
|
|
286
|
+
// 确保全局插件系统生效(plugins.enabled 默认 true,仅显式 false 时需修复)
|
|
287
|
+
if (cfg.plugins.enabled === false) {
|
|
288
|
+
cfg.plugins.enabled = true;
|
|
289
|
+
}
|
|
290
|
+
if (!cfg.plugins.entries) cfg.plugins.entries = {};
|
|
291
|
+
if (!cfg.plugins.installs) cfg.plugins.installs = {};
|
|
292
|
+
|
|
293
|
+
// plugins.entries:启用插件
|
|
294
|
+
cfg.plugins.entries[pluginId] = { enabled: true };
|
|
295
|
+
|
|
296
|
+
// plugins.installs:安装记录
|
|
297
|
+
cfg.plugins.installs[pluginId] = {
|
|
298
|
+
source: "npm",
|
|
299
|
+
spec: spec,
|
|
300
|
+
installPath: pluginDir,
|
|
301
|
+
version: version,
|
|
302
|
+
installedAt: new Date().toISOString().replace(/\.\d{3}Z$/, ".000Z")
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// ---------- 2) 黑名单修复 ----------
|
|
306
|
+
if (Array.isArray(cfg.plugins.deny)) {
|
|
307
|
+
const idx = cfg.plugins.deny.indexOf(pluginId);
|
|
308
|
+
if (idx !== -1) {
|
|
309
|
+
cfg.plugins.deny.splice(idx, 1);
|
|
310
|
+
if (cfg.plugins.deny.length === 0) {
|
|
311
|
+
delete cfg.plugins.deny;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ---------- 3) 白名单添加 ----------
|
|
317
|
+
if (Array.isArray(cfg.plugins.allow)) {
|
|
318
|
+
if (!cfg.plugins.allow.includes(pluginId)) {
|
|
319
|
+
cfg.plugins.allow.push(pluginId);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ---------- 4) channel 配置:智能合并 ----------
|
|
324
|
+
if (!cfg.channels) cfg.channels = {};
|
|
325
|
+
const ch = cfg.channels[pluginId] || {};
|
|
326
|
+
|
|
327
|
+
// 迁移旧的 apiKey -> apiKeys
|
|
328
|
+
let apiKeys = Array.isArray(ch.apiKeys) ? [...ch.apiKeys] : [];
|
|
329
|
+
if (ch.apiKey && typeof ch.apiKey === "string") {
|
|
330
|
+
if (!apiKeys.includes(ch.apiKey)) {
|
|
331
|
+
apiKeys.push(ch.apiKey);
|
|
332
|
+
}
|
|
333
|
+
delete ch.apiKey;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// 如果通过环境变量传入了 APIKEY,确保它在 apiKeys 数组中(去重)
|
|
337
|
+
if (envApiKey && !apiKeys.includes(envApiKey)) {
|
|
338
|
+
apiKeys.push(envApiKey);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
ch.enabled = true;
|
|
342
|
+
ch.apiKeys = apiKeys;
|
|
343
|
+
cfg.channels[pluginId] = ch;
|
|
344
|
+
|
|
345
|
+
// ---------- 5) 写回配置文件 ----------
|
|
346
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
347
|
+
|
|
348
|
+
// 输出版本号到 stdout,供 shell 接收
|
|
349
|
+
process.stdout.write(version);
|
|
350
|
+
') || result_exit "config_update_failed"
|
|
351
|
+
|
|
352
|
+
# ========== 插件 >= 1.1.0 时需要重新安装依赖并注册 ==========
|
|
353
|
+
|
|
354
|
+
# if version_gte "$version" "1.1.0"; then
|
|
355
|
+
# (cd "$plugin_dir" && pnpm install) >/dev/null 2>&1 || true
|
|
356
|
+
# openclaw gateway install --force >/dev/null 2>&1 || true
|
|
357
|
+
|
|
358
|
+
# # 小内存机器(<3GB)自动注入 NODE_OPTIONS 限制堆内存,避免 OOM
|
|
359
|
+
# GATEWAY_SERVICE="$HOME/.config/systemd/user/openclaw-gateway.service"
|
|
360
|
+
# TOTAL_MEM_KB=$(awk '/MemTotal/ {print $2}' /proc/meminfo 2>/dev/null || echo "0")
|
|
361
|
+
# if [ "$TOTAL_MEM_KB" -gt 0 ] && [ "$TOTAL_MEM_KB" -lt 3000000 ] \
|
|
362
|
+
# && [ -f "$GATEWAY_SERVICE" ] \
|
|
363
|
+
# && ! grep -q 'max-old-space-size' "$GATEWAY_SERVICE"; then
|
|
364
|
+
# sed -i '/\[Service\]/a Environment="NODE_OPTIONS=--max-old-space-size=1500"' "$GATEWAY_SERVICE"
|
|
365
|
+
# systemctl --user daemon-reload
|
|
366
|
+
# fi
|
|
367
|
+
# fi
|
|
368
|
+
|
|
369
|
+
# ========== 设备审批(openclaw == 2026.3.28)==========
|
|
370
|
+
|
|
371
|
+
if [ -n "$openclaw_version" ] && [ "$openclaw_version" = "$OPENCLAW_DEVICES_APPROVE_VERSION" ]; then
|
|
372
|
+
step_log "devices_approve" "approving devices"
|
|
373
|
+
openclaw devices approve >/dev/null 2>&1 || true
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
# ========== 重启 Gateway ==========
|
|
377
|
+
|
|
378
|
+
if [ "$RESTART_GATEWAY" = "true" ]; then
|
|
379
|
+
step_log "gateway_restart" "restarting gateway"
|
|
380
|
+
openclaw gateway restart >/dev/null 2>&1 || true
|
|
381
|
+
fi
|
|
382
|
+
|
|
383
|
+
# stdout 最后一行 RESULT,供前端解析最终结果
|
|
384
|
+
result_ok "$version"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-tool.d.ts","sourceRoot":"","sources":["../../src/upload-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,0BAA0B,CAAC;AAShF,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;CAY5B,CAAC;AAMF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"upload-tool.d.ts","sourceRoot":"","sources":["../../src/upload-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAgB,MAAM,0BAA0B,CAAC;AAShF,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAExD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;CAY5B,CAAC;AAMF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CA4I/D"}
|
package/dist/src/upload-tool.js
CHANGED
|
@@ -23,7 +23,7 @@ export const uploadToolSchema = {
|
|
|
23
23
|
items: { type: "string" },
|
|
24
24
|
minItems: 1,
|
|
25
25
|
maxItems: 5,
|
|
26
|
-
description: "
|
|
26
|
+
description: "需要上传的本地文件绝对路径数组,文件必须已写入磁盘,最多 5 个文件",
|
|
27
27
|
},
|
|
28
28
|
},
|
|
29
29
|
required: ["paths"],
|
|
@@ -35,14 +35,19 @@ export function registerUploadTool(api) {
|
|
|
35
35
|
// 通过闭包捕获 api.logger,tool ctx 中没有 log
|
|
36
36
|
const log = api.logger;
|
|
37
37
|
api.registerTool((ctx) => {
|
|
38
|
+
// 硬隔离:非 lightclawbot 通道时直接返回 null,框架不会暴露此工具
|
|
39
|
+
if (ctx.messageChannel !== "lightclawbot") {
|
|
40
|
+
// log.warn(`[lightclaw_upload_file] channel=${ctx.messageChannel}, skip..."`);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
38
43
|
const defaultAccountId = ctx.agentAccountId;
|
|
39
44
|
const sessionKey = ctx.sessionKey;
|
|
45
|
+
// log.warn(`[lightclaw_upload_file] channel=${ctx.messageChannel}, contiue..."`);
|
|
40
46
|
return {
|
|
41
47
|
name: UPLOAD_TOOL_NAME,
|
|
42
|
-
description: "
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"Supports up to 5 files at once. Returns a public download URL for each uploaded file.",
|
|
48
|
+
description: "将本地文件上传到云端临时存储并返回下载链接。" +
|
|
49
|
+
"当需要把生成的文件(图片、文档、代码包等)交付给用户时,必须使用此工具。" +
|
|
50
|
+
"文件必须先写入磁盘,然后传入绝对路径。单次最多 5 个文件,超出请分批调用。",
|
|
46
51
|
parameters: uploadToolSchema,
|
|
47
52
|
async execute(_toolCallId, params) {
|
|
48
53
|
// 每次 execute 时动态解析 apiKey(多 key 模式下通过 sessionKey 直接获取)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-tool.js","sourceRoot":"","sources":["../../src/upload-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,+DAA+D;AAC/D,8BAA8B;AAC9B,+DAA+D;AAE/D,MAAM,CAAC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAExD,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,QAAiB;IACvB,UAAU,EAAE;QACV,KAAK,EAAE;YACL,IAAI,EAAE,OAAgB;YACtB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE;YAClC,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,CAAC;YACX,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"upload-tool.js","sourceRoot":"","sources":["../../src/upload-tool.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightclawbot",
|
|
3
|
-
"version": "1.1.0",
|
|
3
|
+
"version": "1.1.2-beta.0",
|
|
4
4
|
"description": "LightClawBot channel plugin with message support, cron jobs, and proactive messaging",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -23,9 +23,6 @@
|
|
|
23
23
|
"install": {
|
|
24
24
|
"npmSpec": "lightclawbot",
|
|
25
25
|
"defaultChoice": "npm"
|
|
26
|
-
},
|
|
27
|
-
"bundle": {
|
|
28
|
-
"stageRuntimeDependencies": true
|
|
29
26
|
}
|
|
30
27
|
},
|
|
31
28
|
"scripts": {
|
|
@@ -54,7 +51,7 @@
|
|
|
54
51
|
"openclaw": ">=2026.3.22"
|
|
55
52
|
},
|
|
56
53
|
"devDependencies": {
|
|
57
|
-
"openclaw": "
|
|
54
|
+
"openclaw": "*",
|
|
58
55
|
"typescript": "^5.7.0"
|
|
59
56
|
}
|
|
60
57
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lightclawbot-cron
|
|
3
|
-
description: LightClawBot
|
|
3
|
+
description: 仅限 lightclawbot 通道使用。LightClawBot 定时任务提醒,支持一次性提醒、周期性任务,可设置、查询、取消提醒。当消息来源不是 lightclawbot 时,禁止调用本技能。
|
|
4
|
+
metadata: { "openclaw": { "requires": { "config": ["channels.lightclawbot.apiKeys"] } } }
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# LightClawBot 智能提醒
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LightClaw — Socket.IO 事件处理器
|
|
3
|
-
*
|
|
4
|
-
* 将 socket 事件监听(message:private、history:request、sessions:request)
|
|
5
|
-
* 从 gateway 主逻辑中解耦。
|
|
6
|
-
*/
|
|
7
|
-
import type { Socket } from "socket.io-client";
|
|
8
|
-
import type { GatewayContext, QueuedMessage } from "./types.js";
|
|
9
|
-
export interface SocketHandlerDeps {
|
|
10
|
-
account: GatewayContext["account"];
|
|
11
|
-
botClientId: string;
|
|
12
|
-
log?: GatewayContext["log"];
|
|
13
|
-
enqueueMessage: (msg: QueuedMessage) => void;
|
|
14
|
-
/** 收到入站事件时调用,通知框架更新 lastEventAt */
|
|
15
|
-
onEvent?: () => void;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* 绑定所有 Socket.IO 事件监听器
|
|
19
|
-
*/
|
|
20
|
-
export declare function bindSocketHandlers(socket: Socket, deps: SocketHandlerDeps): void;
|
|
21
|
-
//# sourceMappingURL=socket-handlers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"socket-handlers.d.ts","sourceRoot":"","sources":["../../src/socket-handlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAC;AAcpF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAC5B,cAAc,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CA6HhF"}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LightClaw — Socket.IO 事件处理器
|
|
3
|
-
*
|
|
4
|
-
* 将 socket 事件监听(message:private、history:request、sessions:request)
|
|
5
|
-
* 从 gateway 主逻辑中解耦。
|
|
6
|
-
*/
|
|
7
|
-
import { CHANNEL_KEY, EVENT_MESSAGE_PRIVATE, EVENT_HISTORY_REQUEST, EVENT_HISTORY_RESPONSE, EVENT_SESSIONS_REQUEST, EVENT_SESSIONS_RESPONSE, DEFAULT_HISTORY_LIMIT, } from "./config.js";
|
|
8
|
-
import { isDuplicate, debounceHistoryRequest, generateMsgId } from "./dedup.js";
|
|
9
|
-
import { getAssistantRuntime } from "./runtime.js";
|
|
10
|
-
import { readSessionHistoryWithCron, listSessions } from "./history/index.js";
|
|
11
|
-
/**
|
|
12
|
-
* 绑定所有 Socket.IO 事件监听器
|
|
13
|
-
*/
|
|
14
|
-
export function bindSocketHandlers(socket, deps) {
|
|
15
|
-
const { account, botClientId, log, enqueueMessage, onEvent } = deps;
|
|
16
|
-
// ---- 接收用户消息 ----
|
|
17
|
-
socket.on(EVENT_MESSAGE_PRIVATE, (data, ack) => {
|
|
18
|
-
ack?.();
|
|
19
|
-
log?.info(`[${CHANNEL_KEY}] Received private message: ${JSON.stringify(data)},botClientId:${botClientId}`);
|
|
20
|
-
// 回环防御:过滤自身发出的消息
|
|
21
|
-
if (data.from === botClientId)
|
|
22
|
-
return;
|
|
23
|
-
// 跳过控制消息(typing / stream 信号),只处理真实用户消息
|
|
24
|
-
if (data.kind && data.kind !== "text")
|
|
25
|
-
return;
|
|
26
|
-
// 无内容跳过
|
|
27
|
-
const hasContent = data.content?.trim();
|
|
28
|
-
const hasFiles = data.files && data.files.length > 0;
|
|
29
|
-
if (!hasContent && !hasFiles)
|
|
30
|
-
return;
|
|
31
|
-
// 去重
|
|
32
|
-
if (isDuplicate(data.msgId))
|
|
33
|
-
return;
|
|
34
|
-
// 通知框架收到入站事件(更新 lastEventAt,防止 stale-socket 误判)
|
|
35
|
-
onEvent?.();
|
|
36
|
-
log?.info(`[${CHANNEL_KEY}] Message from ${data.from}: "${(data.content || "").slice(0, 60)}" files=${data.files?.length ?? 0}`);
|
|
37
|
-
enqueueMessage({
|
|
38
|
-
senderId: data.from,
|
|
39
|
-
text: data.content || "",
|
|
40
|
-
messageId: data.msgId,
|
|
41
|
-
files: data.files ?? [],
|
|
42
|
-
timestamp: data.timestamp,
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
// ---- 历史消息请求 ----
|
|
46
|
-
socket.on(EVENT_HISTORY_REQUEST, (data, ack) => {
|
|
47
|
-
ack?.();
|
|
48
|
-
if (!data?.from) {
|
|
49
|
-
log?.warn(`[${CHANNEL_KEY}] History request missing userId, ignoring`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// 回环防御:忽略 bot 自身发出的请求
|
|
53
|
-
if (data.from === botClientId)
|
|
54
|
-
return;
|
|
55
|
-
// 去重:如果有 msgId,走消息级去重
|
|
56
|
-
if (data.msgId && isDuplicate(data.msgId)) {
|
|
57
|
-
log?.warn(`[${CHANNEL_KEY}] Duplicate history request (msgId), ignoring`);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
// 防抖:同一用户高频请求只处理最后一条
|
|
61
|
-
debounceHistoryRequest(data.from, () => {
|
|
62
|
-
// 通知框架收到入站事件(更新 lastEventAt,防止 stale-socket 误判)
|
|
63
|
-
onEvent?.();
|
|
64
|
-
try {
|
|
65
|
-
const pluginRuntime = getAssistantRuntime();
|
|
66
|
-
const currentCfg = pluginRuntime.config.loadConfig();
|
|
67
|
-
const route = pluginRuntime.channel.routing.resolveAgentRoute({
|
|
68
|
-
cfg: currentCfg,
|
|
69
|
-
channel: CHANNEL_KEY,
|
|
70
|
-
accountId: account.accountId,
|
|
71
|
-
peer: { kind: "direct", id: data.from },
|
|
72
|
-
});
|
|
73
|
-
const sessionKey = route?.sessionKey ?? `${CHANNEL_KEY}:dm:${data.from}`;
|
|
74
|
-
const messages = readSessionHistoryWithCron(sessionKey, {
|
|
75
|
-
limit: data.limit ?? DEFAULT_HISTORY_LIMIT,
|
|
76
|
-
chatOnly: data.chatOnly ?? true,
|
|
77
|
-
includeCron: true,
|
|
78
|
-
});
|
|
79
|
-
log?.info(`[${CHANNEL_KEY}] History request: userId=${data.from} sessionKey=${sessionKey} found=${messages.length}`);
|
|
80
|
-
socket.emit(EVENT_HISTORY_RESPONSE, {
|
|
81
|
-
msgId: generateMsgId(),
|
|
82
|
-
from: botClientId,
|
|
83
|
-
to: data.from,
|
|
84
|
-
sessionKey,
|
|
85
|
-
messages: messages.filter(msg => !!msg.content.trim() || (msg.files && msg.files.length > 0)),
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
log?.error(`[${CHANNEL_KEY}] History request error: ${err}`);
|
|
90
|
-
socket.emit(EVENT_HISTORY_RESPONSE, {
|
|
91
|
-
msgId: generateMsgId(),
|
|
92
|
-
from: botClientId,
|
|
93
|
-
to: data.from,
|
|
94
|
-
sessionKey: "",
|
|
95
|
-
messages: [],
|
|
96
|
-
error: err instanceof Error ? err.message : String(err),
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
// ---- 会话列表请求 ----
|
|
102
|
-
socket.on(EVENT_SESSIONS_REQUEST, (data) => {
|
|
103
|
-
// 通知框架收到入站事件(更新 lastEventAt,防止 stale-socket 误判)
|
|
104
|
-
onEvent?.();
|
|
105
|
-
try {
|
|
106
|
-
const sessions = listSessions();
|
|
107
|
-
socket.emit(EVENT_SESSIONS_RESPONSE, {
|
|
108
|
-
requestId: data.requestId,
|
|
109
|
-
sessions,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
catch (err) {
|
|
113
|
-
log?.error(`[${CHANNEL_KEY}] Sessions list error: ${err}`);
|
|
114
|
-
socket.emit(EVENT_SESSIONS_RESPONSE, {
|
|
115
|
-
requestId: data.requestId,
|
|
116
|
-
sessions: [],
|
|
117
|
-
error: err instanceof Error ? err.message : String(err),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=socket-handlers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"socket-handlers.js","sourceRoot":"","sources":["../../src/socket-handlers.ts"],"names":[],"mappings":"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"}
|