@blockrun/clawrouter 0.12.111 → 0.12.113
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/package.json +1 -1
- package/scripts/reinstall.sh +156 -2
- package/scripts/update.sh +142 -2
package/package.json
CHANGED
package/scripts/reinstall.sh
CHANGED
|
@@ -62,6 +62,20 @@ run_dependency_install() {
|
|
|
62
62
|
|
|
63
63
|
trap restore_previous_install EXIT
|
|
64
64
|
|
|
65
|
+
# Pre-flight: validate openclaw.json is parseable before touching anything
|
|
66
|
+
validate_config() {
|
|
67
|
+
local config_path="$HOME/.openclaw/openclaw.json"
|
|
68
|
+
if [ ! -f "$config_path" ]; then return 0; fi
|
|
69
|
+
if ! node -e "JSON.parse(require('fs').readFileSync('$config_path','utf8'))" 2>/dev/null; then
|
|
70
|
+
echo ""
|
|
71
|
+
echo "✗ openclaw.json is corrupt (invalid JSON)."
|
|
72
|
+
echo " Fix it first: openclaw doctor --fix"
|
|
73
|
+
echo " Then re-run this script."
|
|
74
|
+
echo ""
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
65
79
|
kill_port_processes() {
|
|
66
80
|
local port="$1"
|
|
67
81
|
local pids=""
|
|
@@ -87,6 +101,9 @@ kill_port_processes() {
|
|
|
87
101
|
echo "🦞 ClawRouter Reinstall"
|
|
88
102
|
echo ""
|
|
89
103
|
|
|
104
|
+
# Pre-flight: fail fast if config is corrupt
|
|
105
|
+
validate_config
|
|
106
|
+
|
|
90
107
|
# 0. Back up wallet key BEFORE removing anything
|
|
91
108
|
echo "→ Backing up wallet..."
|
|
92
109
|
if [ -f "$WALLET_FILE" ]; then
|
|
@@ -312,8 +329,47 @@ if [ -d "$CREDS_DIR" ] && [ "$(ls -A "$CREDS_DIR" 2>/dev/null)" ]; then
|
|
|
312
329
|
echo " ✓ Backed up OpenClaw credentials"
|
|
313
330
|
fi
|
|
314
331
|
|
|
332
|
+
# Extract channel config (Telegram tokens, etc.) from openclaw.json before install
|
|
333
|
+
# openclaw plugins install can overwrite config and wipe channel settings
|
|
334
|
+
CHANNEL_CONFIG_BACKUP=""
|
|
335
|
+
if [ -f "$CONFIG_PATH" ]; then
|
|
336
|
+
CHANNEL_CONFIG_BACKUP="$(mktemp)"
|
|
337
|
+
node -e "
|
|
338
|
+
const fs = require('fs');
|
|
339
|
+
try {
|
|
340
|
+
const config = JSON.parse(fs.readFileSync('$CONFIG_PATH', 'utf8'));
|
|
341
|
+
// Save channels block and gateway block (gateway.mode etc.)
|
|
342
|
+
const preserved = {};
|
|
343
|
+
if (config.channels) preserved.channels = config.channels;
|
|
344
|
+
if (config.gateway) preserved.gateway = config.gateway;
|
|
345
|
+
fs.writeFileSync('$CHANNEL_CONFIG_BACKUP', JSON.stringify(preserved, null, 2));
|
|
346
|
+
const channelCount = Object.keys(config.channels || {}).length;
|
|
347
|
+
if (channelCount > 0) console.log(' ✓ Preserved config for channels: ' + Object.keys(config.channels).join(', '));
|
|
348
|
+
} catch (e) { fs.writeFileSync('$CHANNEL_CONFIG_BACKUP', '{}'); }
|
|
349
|
+
"
|
|
350
|
+
fi
|
|
351
|
+
|
|
315
352
|
echo "→ Installing ClawRouter..."
|
|
316
|
-
openclaw plugins install
|
|
353
|
+
# Run with timeout — openclaw plugins install may hang after printing
|
|
354
|
+
# "Installed plugin: clawrouter" in OpenClaw v2026.4.5 (parallel plugin loading).
|
|
355
|
+
# 120s is enough for slow connections; the install itself completes in ~30s.
|
|
356
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
357
|
+
timeout 120 openclaw plugins install @blockrun/clawrouter || {
|
|
358
|
+
exit_code=$?
|
|
359
|
+
if [ $exit_code -eq 124 ]; then
|
|
360
|
+
echo " (install command timed out — this is normal with OpenClaw v2026.4.5)"
|
|
361
|
+
echo " Plugin was installed successfully before the hang."
|
|
362
|
+
else
|
|
363
|
+
exit $exit_code
|
|
364
|
+
fi
|
|
365
|
+
}
|
|
366
|
+
else
|
|
367
|
+
openclaw plugins install @blockrun/clawrouter
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
# Install is complete — clear the rollback trap immediately.
|
|
371
|
+
# From this point on, Ctrl+C or errors should NOT roll back the install.
|
|
372
|
+
trap - EXIT INT TERM
|
|
317
373
|
|
|
318
374
|
# Restore credentials after plugin install (always restore to preserve user's channels)
|
|
319
375
|
if [ -n "$CREDS_BACKUP" ] && [ -d "$CREDS_BACKUP" ]; then
|
|
@@ -323,6 +379,59 @@ if [ -n "$CREDS_BACKUP" ] && [ -d "$CREDS_BACKUP" ]; then
|
|
|
323
379
|
rm -rf "$(dirname "$CREDS_BACKUP")"
|
|
324
380
|
fi
|
|
325
381
|
|
|
382
|
+
# Restore channel config (Telegram tokens etc.) that may have been wiped by plugin install
|
|
383
|
+
if [ -n "$CHANNEL_CONFIG_BACKUP" ] && [ -f "$CHANNEL_CONFIG_BACKUP" ] && [ -f "$CONFIG_PATH" ]; then
|
|
384
|
+
node -e "
|
|
385
|
+
const fs = require('fs');
|
|
386
|
+
function atomicWrite(filePath, data) {
|
|
387
|
+
const tmpPath = filePath + '.tmp.' + process.pid;
|
|
388
|
+
fs.writeFileSync(tmpPath, data);
|
|
389
|
+
fs.renameSync(tmpPath, filePath);
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
const config = JSON.parse(fs.readFileSync('$CONFIG_PATH', 'utf8'));
|
|
393
|
+
const preserved = JSON.parse(fs.readFileSync('$CHANNEL_CONFIG_BACKUP', 'utf8'));
|
|
394
|
+
let changed = false;
|
|
395
|
+
|
|
396
|
+
// Restore channels block if it was wiped or is now empty
|
|
397
|
+
if (preserved.channels && Object.keys(preserved.channels).length > 0) {
|
|
398
|
+
if (!config.channels || Object.keys(config.channels).length === 0) {
|
|
399
|
+
config.channels = preserved.channels;
|
|
400
|
+
changed = true;
|
|
401
|
+
console.log(' ✓ Restored channel config (Telegram/WhatsApp/etc.)');
|
|
402
|
+
} else {
|
|
403
|
+
// Merge: restore any channels that are now missing
|
|
404
|
+
let merged = 0;
|
|
405
|
+
for (const [ch, val] of Object.entries(preserved.channels)) {
|
|
406
|
+
if (!config.channels[ch]) {
|
|
407
|
+
config.channels[ch] = val;
|
|
408
|
+
merged++;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (merged > 0) {
|
|
412
|
+
changed = true;
|
|
413
|
+
console.log(' ✓ Merged ' + merged + ' missing channel(s) back into config');
|
|
414
|
+
} else {
|
|
415
|
+
console.log(' Channel config intact');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Restore gateway.mode if missing
|
|
421
|
+
if (preserved.gateway?.mode && (!config.gateway || !config.gateway.mode)) {
|
|
422
|
+
if (!config.gateway) config.gateway = {};
|
|
423
|
+
config.gateway.mode = preserved.gateway.mode;
|
|
424
|
+
changed = true;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (changed) atomicWrite('$CONFIG_PATH', JSON.stringify(config, null, 2));
|
|
428
|
+
} catch (e) {
|
|
429
|
+
console.log(' Warning: could not restore channel config:', e.message);
|
|
430
|
+
}
|
|
431
|
+
"
|
|
432
|
+
rm -f "$CHANNEL_CONFIG_BACKUP"
|
|
433
|
+
fi
|
|
434
|
+
|
|
326
435
|
# 6.1. Verify installation and force-update if openclaw installed a stale cached version
|
|
327
436
|
echo "→ Verifying installation..."
|
|
328
437
|
DIST_PATH="$PLUGIN_DIR/dist/index.js"
|
|
@@ -552,6 +661,21 @@ if (fs.existsSync(configPath)) {
|
|
|
552
661
|
}
|
|
553
662
|
"
|
|
554
663
|
|
|
664
|
+
# Clean up stale plugin backups — these cause "duplicate plugin" warnings on restart
|
|
665
|
+
echo "→ Cleaning up stale plugin backups..."
|
|
666
|
+
CLEANED=0
|
|
667
|
+
for backup_dir in "$HOME/.openclaw/extensions/clawrouter.backup."*; do
|
|
668
|
+
if [ -d "$backup_dir" ]; then
|
|
669
|
+
rm -rf "$backup_dir"
|
|
670
|
+
CLEANED=$((CLEANED + 1))
|
|
671
|
+
fi
|
|
672
|
+
done
|
|
673
|
+
if [ "$CLEANED" -gt 0 ]; then
|
|
674
|
+
echo " ✓ Removed $CLEANED stale backup(s)"
|
|
675
|
+
else
|
|
676
|
+
echo " ✓ No stale backups found"
|
|
677
|
+
fi
|
|
678
|
+
|
|
555
679
|
# Final: verify wallet survived reinstall
|
|
556
680
|
echo "→ Verifying wallet integrity..."
|
|
557
681
|
if [ -f "$WALLET_FILE" ]; then
|
|
@@ -578,7 +702,37 @@ fi
|
|
|
578
702
|
echo ""
|
|
579
703
|
echo "✓ Done! Smart routing enabled by default."
|
|
580
704
|
echo ""
|
|
581
|
-
|
|
705
|
+
|
|
706
|
+
# Auto-restart gateway so new version is active immediately
|
|
707
|
+
echo "→ Restarting gateway..."
|
|
708
|
+
RESTART_OK=false
|
|
709
|
+
if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1 || \
|
|
710
|
+
systemctl --user is-enabled openclaw-gateway.service >/dev/null 2>&1; then
|
|
711
|
+
if systemctl --user restart openclaw-gateway.service 2>/dev/null; then
|
|
712
|
+
# Wait up to 15s for ClawRouter proxy port to come up
|
|
713
|
+
for i in $(seq 1 15); do
|
|
714
|
+
sleep 1
|
|
715
|
+
if curl -sf --connect-timeout 1 http://localhost:8402/v1/models >/dev/null 2>&1; then
|
|
716
|
+
RESTART_OK=true
|
|
717
|
+
break
|
|
718
|
+
fi
|
|
719
|
+
done
|
|
720
|
+
if $RESTART_OK; then
|
|
721
|
+
echo " ✓ Gateway restarted — ClawRouter active on port 8402"
|
|
722
|
+
else
|
|
723
|
+
echo " ⚠ Gateway restarted but port 8402 not yet up (may still be starting)"
|
|
724
|
+
echo " Check: systemctl --user status openclaw-gateway.service"
|
|
725
|
+
fi
|
|
726
|
+
else
|
|
727
|
+
echo " ⚠ systemctl restart failed. Run manually: openclaw gateway restart"
|
|
728
|
+
fi
|
|
729
|
+
elif command -v openclaw >/dev/null 2>&1; then
|
|
730
|
+
# Fallback: use openclaw CLI restart (background, don't hang)
|
|
731
|
+
openclaw gateway restart &>/dev/null &
|
|
732
|
+
echo " ✓ Gateway restart triggered"
|
|
733
|
+
else
|
|
734
|
+
echo " Run: openclaw gateway restart"
|
|
735
|
+
fi
|
|
582
736
|
echo ""
|
|
583
737
|
echo "Model aliases available:"
|
|
584
738
|
echo " /model sonnet → claude-sonnet-4.6"
|
package/scripts/update.sh
CHANGED
|
@@ -71,9 +71,27 @@ run_dependency_install() {
|
|
|
71
71
|
|
|
72
72
|
trap restore_previous_install EXIT
|
|
73
73
|
|
|
74
|
+
# Pre-flight: validate openclaw.json is parseable before touching anything
|
|
75
|
+
validate_config() {
|
|
76
|
+
local config_path="$HOME/.openclaw/openclaw.json"
|
|
77
|
+
if [ ! -f "$config_path" ]; then return 0; fi
|
|
78
|
+
if ! node -e "JSON.parse(require('fs').readFileSync('$config_path','utf8'))" 2>/dev/null; then
|
|
79
|
+
echo ""
|
|
80
|
+
echo "✗ openclaw.json is corrupt (invalid JSON)."
|
|
81
|
+
echo " Fix it first: openclaw doctor --fix"
|
|
82
|
+
echo " Then re-run this script."
|
|
83
|
+
echo ""
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
# ── Step 1: Back up wallet key ─────────────────────────────────
|
|
75
89
|
echo "🦞 ClawRouter Update"
|
|
76
90
|
echo ""
|
|
91
|
+
|
|
92
|
+
# Pre-flight: fail fast if config is corrupt
|
|
93
|
+
validate_config
|
|
94
|
+
|
|
77
95
|
echo "→ Checking wallet..."
|
|
78
96
|
|
|
79
97
|
if [ -f "$WALLET_FILE" ]; then
|
|
@@ -200,8 +218,46 @@ if [ -d "$CREDS_DIR" ] && [ "$(ls -A "$CREDS_DIR" 2>/dev/null)" ]; then
|
|
|
200
218
|
echo " ✓ Backed up OpenClaw credentials"
|
|
201
219
|
fi
|
|
202
220
|
|
|
221
|
+
# Extract channel config (Telegram tokens, etc.) from openclaw.json before install
|
|
222
|
+
# openclaw plugins install can overwrite config and wipe channel settings
|
|
223
|
+
CHANNEL_CONFIG_BACKUP=""
|
|
224
|
+
if [ -f "$CONFIG_PATH" ]; then
|
|
225
|
+
CHANNEL_CONFIG_BACKUP="$(mktemp)"
|
|
226
|
+
node -e "
|
|
227
|
+
const fs = require('fs');
|
|
228
|
+
try {
|
|
229
|
+
const config = JSON.parse(fs.readFileSync('$CONFIG_PATH', 'utf8'));
|
|
230
|
+
const preserved = {};
|
|
231
|
+
if (config.channels) preserved.channels = config.channels;
|
|
232
|
+
if (config.gateway) preserved.gateway = config.gateway;
|
|
233
|
+
fs.writeFileSync('$CHANNEL_CONFIG_BACKUP', JSON.stringify(preserved, null, 2));
|
|
234
|
+
const channelCount = Object.keys(config.channels || {}).length;
|
|
235
|
+
if (channelCount > 0) console.log(' ✓ Preserved config for channels: ' + Object.keys(config.channels).join(', '));
|
|
236
|
+
} catch (e) { fs.writeFileSync('$CHANNEL_CONFIG_BACKUP', '{}'); }
|
|
237
|
+
"
|
|
238
|
+
fi
|
|
239
|
+
|
|
203
240
|
echo "→ Installing latest ClawRouter..."
|
|
204
|
-
openclaw plugins install
|
|
241
|
+
# Run with timeout — openclaw plugins install may hang after printing
|
|
242
|
+
# "Installed plugin: clawrouter" in OpenClaw v2026.4.5 (parallel plugin loading).
|
|
243
|
+
# 120s is enough for slow connections; the install itself completes in ~30s.
|
|
244
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
245
|
+
timeout 120 openclaw plugins install @blockrun/clawrouter || {
|
|
246
|
+
exit_code=$?
|
|
247
|
+
if [ $exit_code -eq 124 ]; then
|
|
248
|
+
echo " (install command timed out — this is normal with OpenClaw v2026.4.5)"
|
|
249
|
+
echo " Plugin was installed successfully before the hang."
|
|
250
|
+
else
|
|
251
|
+
exit $exit_code
|
|
252
|
+
fi
|
|
253
|
+
}
|
|
254
|
+
else
|
|
255
|
+
openclaw plugins install @blockrun/clawrouter
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
# Install is complete — clear the rollback trap immediately.
|
|
259
|
+
# From this point on, Ctrl+C or errors should NOT roll back the install.
|
|
260
|
+
trap - EXIT INT TERM
|
|
205
261
|
|
|
206
262
|
# Restore credentials after plugin install (always restore to preserve user's channels)
|
|
207
263
|
if [ -n "$CREDS_BACKUP" ] && [ -d "$CREDS_BACKUP" ]; then
|
|
@@ -211,6 +267,46 @@ if [ -n "$CREDS_BACKUP" ] && [ -d "$CREDS_BACKUP" ]; then
|
|
|
211
267
|
rm -rf "$(dirname "$CREDS_BACKUP")"
|
|
212
268
|
fi
|
|
213
269
|
|
|
270
|
+
# Restore channel config (Telegram tokens etc.) that may have been wiped by plugin install
|
|
271
|
+
if [ -n "$CHANNEL_CONFIG_BACKUP" ] && [ -f "$CHANNEL_CONFIG_BACKUP" ] && [ -f "$CONFIG_PATH" ]; then
|
|
272
|
+
node -e "
|
|
273
|
+
const fs = require('fs');
|
|
274
|
+
function atomicWrite(filePath, data) {
|
|
275
|
+
const tmpPath = filePath + '.tmp.' + process.pid;
|
|
276
|
+
fs.writeFileSync(tmpPath, data);
|
|
277
|
+
fs.renameSync(tmpPath, filePath);
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
const config = JSON.parse(fs.readFileSync('$CONFIG_PATH', 'utf8'));
|
|
281
|
+
const preserved = JSON.parse(fs.readFileSync('$CHANNEL_CONFIG_BACKUP', 'utf8'));
|
|
282
|
+
let changed = false;
|
|
283
|
+
if (preserved.channels && Object.keys(preserved.channels).length > 0) {
|
|
284
|
+
if (!config.channels || Object.keys(config.channels).length === 0) {
|
|
285
|
+
config.channels = preserved.channels;
|
|
286
|
+
changed = true;
|
|
287
|
+
console.log(' ✓ Restored channel config (Telegram/WhatsApp/etc.)');
|
|
288
|
+
} else {
|
|
289
|
+
let merged = 0;
|
|
290
|
+
for (const [ch, val] of Object.entries(preserved.channels)) {
|
|
291
|
+
if (!config.channels[ch]) { config.channels[ch] = val; merged++; }
|
|
292
|
+
}
|
|
293
|
+
if (merged > 0) { changed = true; console.log(' ✓ Merged ' + merged + ' missing channel(s) back into config'); }
|
|
294
|
+
else { console.log(' Channel config intact'); }
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (preserved.gateway?.mode && (!config.gateway || !config.gateway.mode)) {
|
|
298
|
+
if (!config.gateway) config.gateway = {};
|
|
299
|
+
config.gateway.mode = preserved.gateway.mode;
|
|
300
|
+
changed = true;
|
|
301
|
+
}
|
|
302
|
+
if (changed) atomicWrite('$CONFIG_PATH', JSON.stringify(config, null, 2));
|
|
303
|
+
} catch (e) {
|
|
304
|
+
console.log(' Warning: could not restore channel config:', e.message);
|
|
305
|
+
}
|
|
306
|
+
"
|
|
307
|
+
rm -f "$CHANNEL_CONFIG_BACKUP"
|
|
308
|
+
fi
|
|
309
|
+
|
|
214
310
|
# ── Step 4b: Verify version — force-update if openclaw served a stale cache ──
|
|
215
311
|
force_install_from_npm() {
|
|
216
312
|
local version="$1"
|
|
@@ -438,6 +534,21 @@ if (fs.existsSync(configPath)) {
|
|
|
438
534
|
}
|
|
439
535
|
"
|
|
440
536
|
|
|
537
|
+
# Clean up stale plugin backups — these cause "duplicate plugin" warnings on restart
|
|
538
|
+
echo "→ Cleaning up stale plugin backups..."
|
|
539
|
+
CLEANED=0
|
|
540
|
+
for backup_dir in "$HOME/.openclaw/extensions/clawrouter.backup."*; do
|
|
541
|
+
if [ -d "$backup_dir" ]; then
|
|
542
|
+
rm -rf "$backup_dir"
|
|
543
|
+
CLEANED=$((CLEANED + 1))
|
|
544
|
+
fi
|
|
545
|
+
done
|
|
546
|
+
if [ "$CLEANED" -gt 0 ]; then
|
|
547
|
+
echo " ✓ Removed $CLEANED stale backup(s)"
|
|
548
|
+
else
|
|
549
|
+
echo " ✓ No stale backups found"
|
|
550
|
+
fi
|
|
551
|
+
|
|
441
552
|
# ── Summary ─────────────────────────────────────────────────────
|
|
442
553
|
echo ""
|
|
443
554
|
echo "✓ ClawRouter updated successfully!"
|
|
@@ -461,7 +572,36 @@ if [ -f "$WALLET_FILE" ]; then
|
|
|
461
572
|
fi
|
|
462
573
|
|
|
463
574
|
echo ""
|
|
464
|
-
|
|
575
|
+
|
|
576
|
+
# Auto-restart gateway so new version is active immediately
|
|
577
|
+
echo "→ Restarting gateway..."
|
|
578
|
+
RESTART_OK=false
|
|
579
|
+
if systemctl --user is-active openclaw-gateway.service >/dev/null 2>&1 || \
|
|
580
|
+
systemctl --user is-enabled openclaw-gateway.service >/dev/null 2>&1; then
|
|
581
|
+
if systemctl --user restart openclaw-gateway.service 2>/dev/null; then
|
|
582
|
+
for i in $(seq 1 15); do
|
|
583
|
+
sleep 1
|
|
584
|
+
if curl -sf --connect-timeout 1 http://localhost:8402/v1/models >/dev/null 2>&1; then
|
|
585
|
+
RESTART_OK=true
|
|
586
|
+
break
|
|
587
|
+
fi
|
|
588
|
+
done
|
|
589
|
+
if $RESTART_OK; then
|
|
590
|
+
echo " ✓ Gateway restarted — ClawRouter active on port 8402"
|
|
591
|
+
else
|
|
592
|
+
echo " ⚠ Gateway restarted but port 8402 not yet up (may still be starting)"
|
|
593
|
+
echo " Check: systemctl --user status openclaw-gateway.service"
|
|
594
|
+
fi
|
|
595
|
+
else
|
|
596
|
+
echo " ⚠ systemctl restart failed. Run manually: openclaw gateway restart"
|
|
597
|
+
fi
|
|
598
|
+
elif command -v openclaw >/dev/null 2>&1; then
|
|
599
|
+
openclaw gateway restart &>/dev/null &
|
|
600
|
+
echo " ✓ Gateway restart triggered"
|
|
601
|
+
else
|
|
602
|
+
echo " Run: openclaw gateway restart"
|
|
603
|
+
fi
|
|
604
|
+
|
|
465
605
|
echo ""
|
|
466
606
|
echo " Commands:"
|
|
467
607
|
echo " npx @blockrun/clawrouter report # daily usage report"
|