jishushell 0.4.2-beta2 → 0.4.10
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/Dockerfile.openclaw-slim +58 -0
- package/INSTALL-NOTICE +7 -1
- package/dist/auth.js +3 -3
- package/dist/auth.js.map +1 -1
- package/dist/cli.js +517 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +21 -4
- package/dist/config.js +88 -54
- package/dist/config.js.map +1 -1
- package/dist/control.js +5 -5
- package/dist/control.js.map +1 -1
- package/dist/doctor.js +47 -14
- package/dist/doctor.js.map +1 -1
- package/dist/install.d.ts +1 -1
- package/dist/install.js +15 -29
- package/dist/install.js.map +1 -1
- package/dist/routes/backup.d.ts +2 -0
- package/dist/routes/backup.js +370 -0
- package/dist/routes/backup.js.map +1 -0
- package/dist/routes/instances.d.ts +1 -0
- package/dist/routes/instances.js +51 -11
- package/dist/routes/instances.js.map +1 -1
- package/dist/routes/setup.js +3 -5
- package/dist/routes/setup.js.map +1 -1
- package/dist/server.js +29 -1
- package/dist/server.js.map +1 -1
- package/dist/services/backup-manager.d.ts +253 -0
- package/dist/services/backup-manager.js +2014 -0
- package/dist/services/backup-manager.js.map +1 -0
- package/dist/services/backup-verify.d.ts +26 -0
- package/dist/services/backup-verify.js +240 -0
- package/dist/services/backup-verify.js.map +1 -0
- package/dist/services/instance-manager.d.ts +24 -4
- package/dist/services/instance-manager.js +218 -49
- package/dist/services/instance-manager.js.map +1 -1
- package/dist/services/nomad-manager.js +72 -131
- package/dist/services/nomad-manager.js.map +1 -1
- package/dist/services/process-manager.js +4 -3
- package/dist/services/process-manager.js.map +1 -1
- package/dist/services/setup-manager.d.ts +4 -2
- package/dist/services/setup-manager.js +268 -129
- package/dist/services/setup-manager.js.map +1 -1
- package/dist/utils/fs.d.ts +85 -0
- package/dist/utils/fs.js +111 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/safe-json.d.ts +2 -0
- package/dist/utils/safe-json.js +22 -16
- package/dist/utils/safe-json.js.map +1 -1
- package/install/jishu-install-china.sh +3092 -0
- package/install/jishu-install.sh +310 -108
- package/install/jishu-uninstall.sh +276 -391
- package/install/post-install.sh +9 -0
- package/openclaw-entry.sh +15 -0
- package/package.json +4 -1
- package/public/assets/Dashboard-DhsrzJ4F.js +1 -0
- package/public/assets/{InitPassword-CslWYy8G.js → InitPassword-BjubiVdd.js} +1 -1
- package/public/assets/InstanceDetail-DMcywsof.js +17 -0
- package/public/assets/{Login-d45wtgVA.js → Login-CUoEZOWR.js} +1 -1
- package/public/assets/NewInstance-Bk0G4EiJ.js +1 -0
- package/public/assets/Settings-D5tHL_h5.js +1 -0
- package/public/assets/Setup-4t6E3Rut.js +1 -0
- package/public/assets/index-BJ47MWpF.css +1 -0
- package/public/assets/index-DbX85irc.js +16 -0
- package/public/assets/{usePolling-CqQ8hrNc.js → usePolling-CK0DfI4h.js} +1 -1
- package/public/assets/{vendor-i18n-Bvxxh8Di.js → vendor-i18n-CfW0RvgE.js} +1 -1
- package/public/assets/vendor-react-B1-3Yrt-.js +59 -0
- package/public/index.html +4 -4
- package/public/assets/Dashboard-Dxsq690N.js +0 -1
- package/public/assets/InstanceDetail-DmEkMj-t.js +0 -14
- package/public/assets/NewInstance-Czp5-AJe.js +0 -1
- package/public/assets/Settings-BKMGck05.js +0 -1
- package/public/assets/Setup-D3rfLWjZ.js +0 -1
- package/public/assets/index-77Ug7feY.css +0 -1
- package/public/assets/index-DkDnIohs.js +0 -16
- package/public/assets/vendor-react-DONn7uBV.js +0 -59
package/install/jishu-install.sh
CHANGED
|
@@ -224,7 +224,7 @@ SKIP_OPENCLAW="${SKIP_OPENCLAW:-0}" # default=0 (install); use --skip 4 or --sk
|
|
|
224
224
|
SKIP_JISHUSHELL="${SKIP_JISHUSHELL:-0}" # 1=skip install_jishushell
|
|
225
225
|
SKIP_JISHUSHELL_SERVICE="${SKIP_JISHUSHELL_SERVICE:-0}" # 1=skip service registration
|
|
226
226
|
OPENCLAW_NPM_VERSION="${OPENCLAW_NPM_VERSION:-latest}" # openclaw npm package version
|
|
227
|
-
OPENCLAW_DOCKER_TAG="${OPENCLAW_DOCKER_TAG:-
|
|
227
|
+
OPENCLAW_DOCKER_TAG="${OPENCLAW_DOCKER_TAG:-ghcr.io/x-aijishu/openclaw-runtime:latest}" # pre-built image from registry
|
|
228
228
|
OPENCLAW_IMAGE="" # set dynamically after pull/build
|
|
229
229
|
AUTO_YES="${AUTO_YES:-0}"
|
|
230
230
|
DOCKER_CMD_PREFIX="" # Set to "sg docker -c" when group activated via sg
|
|
@@ -405,18 +405,33 @@ detect_os() {
|
|
|
405
405
|
ui_success "OS: ${OS_NAME} (package manager: ${PKG_MANAGER})"
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
# Detect CPU architecture. Sets: ARCH (
|
|
408
|
+
# Detect CPU architecture. Sets: ARCH (arm64)
|
|
409
|
+
# Only Arm-family (aarch64, arm64, armv7l) and Apple Silicon (Darwin/arm64)
|
|
410
|
+
# are supported. x86_64, i686, riscv, mips, s390x, ppc, etc. are rejected.
|
|
409
411
|
detect_arch() {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
aarch64|arm64)
|
|
412
|
+
local raw_arch
|
|
413
|
+
raw_arch="$(uname -m)"
|
|
414
|
+
case "$raw_arch" in
|
|
415
|
+
aarch64|arm64)
|
|
416
|
+
ARCH="arm64"
|
|
417
|
+
;;
|
|
418
|
+
armv7l|armv8l|armhf)
|
|
419
|
+
# 32-bit Arm — may work but not officially tested
|
|
420
|
+
ARCH="arm64"
|
|
421
|
+
ui_warn "32-bit Arm detected (${raw_arch}). 64-bit OS on a 64-bit board is strongly recommended."
|
|
422
|
+
;;
|
|
414
423
|
*)
|
|
415
|
-
ui_error "Unsupported CPU architecture: $
|
|
424
|
+
ui_error "Unsupported CPU architecture: ${raw_arch}"
|
|
425
|
+
ui_error ""
|
|
426
|
+
ui_error "JishuShell runs exclusively on Arm-based devices (aarch64 / arm64)."
|
|
427
|
+
ui_error "Supported examples: Raspberry Pi 4/5, Orange Pi 5, Jetson Orin,"
|
|
428
|
+
ui_error " Rockchip RK3588, Apple Silicon Mac (arm64 macOS)."
|
|
429
|
+
ui_error ""
|
|
430
|
+
ui_error "x86_64 / i686 / RISC-V / MIPS / s390x / PowerPC are not supported."
|
|
416
431
|
exit 1
|
|
417
432
|
;;
|
|
418
433
|
esac
|
|
419
|
-
ui_success "Architecture: ${ARCH}"
|
|
434
|
+
ui_success "Architecture: ${ARCH} (${raw_arch})"
|
|
420
435
|
}
|
|
421
436
|
|
|
422
437
|
# Verify sudo access. Sets: SUDO ("" if root, "sudo" otherwise)
|
|
@@ -446,7 +461,7 @@ check_sudo() {
|
|
|
446
461
|
# This ensures 'sudo docker' works even after a long Docker install step
|
|
447
462
|
# without prompting for the password again.
|
|
448
463
|
if [[ -z "${_SUDO_KEEPALIVE_PID:-}" ]]; then
|
|
449
|
-
( while true; do sudo -n true 2>/dev/null; sleep 60; done ) &
|
|
464
|
+
( while true; do sudo -n true 2>/dev/null; sleep 60; done ) &>/dev/null &
|
|
450
465
|
_SUDO_KEEPALIVE_PID=$!
|
|
451
466
|
disown "$_SUDO_KEEPALIVE_PID" 2>/dev/null || true
|
|
452
467
|
fi
|
|
@@ -925,6 +940,41 @@ _ensure_nvm_shell_config() {
|
|
|
925
940
|
install_docker() {
|
|
926
941
|
ui_stage "Docker"
|
|
927
942
|
|
|
943
|
+
# ── macOS: use private Colima instance ─────────────────────────────────────
|
|
944
|
+
if [[ "$OS" == "macos" ]]; then
|
|
945
|
+
local need_brew=0
|
|
946
|
+
local need_profile=0
|
|
947
|
+
|
|
948
|
+
if ! command -v docker &>/dev/null || ! command -v colima &>/dev/null; then
|
|
949
|
+
need_brew=1
|
|
950
|
+
need_profile=1
|
|
951
|
+
elif ! _colima list 2>/dev/null | grep -q "${_COLIMA_PROFILE}"; then
|
|
952
|
+
need_profile=1
|
|
953
|
+
fi
|
|
954
|
+
|
|
955
|
+
if [[ $need_brew -eq 1 ]]; then
|
|
956
|
+
if ! _do_install_docker; then
|
|
957
|
+
ui_error "Colima installation failed"
|
|
958
|
+
return 1
|
|
959
|
+
fi
|
|
960
|
+
elif [[ $need_profile -eq 1 ]]; then
|
|
961
|
+
ui_info "Starting Colima VM (profile: ${_COLIMA_PROFILE})..."
|
|
962
|
+
mkdir -p "${_COLIMA_HOME}"
|
|
963
|
+
_colima start "${_COLIMA_PROFILE}" \
|
|
964
|
+
--vm-type vz --mount-type virtiofs --network-address \
|
|
965
|
+
--activate=false --cpu 2 --memory 4 --disk 60 >/dev/null \
|
|
966
|
+
|| { ui_warn "colima start failed — run 'COLIMA_HOME=${_COLIMA_HOME} colima start ${_COLIMA_PROFILE}' manually"; return 1; }
|
|
967
|
+
export DOCKER_HOST="unix://${_COLIMA_SOCKET}"
|
|
968
|
+
ui_success "Colima is running"
|
|
969
|
+
else
|
|
970
|
+
ui_success "Docker and Colima already configured"
|
|
971
|
+
fi
|
|
972
|
+
|
|
973
|
+
_ensure_docker_running
|
|
974
|
+
return 0
|
|
975
|
+
fi
|
|
976
|
+
|
|
977
|
+
# ── Linux: standard Docker Engine ──────────────────────────────────────────
|
|
928
978
|
local need_install_docker=0
|
|
929
979
|
local need_install_compose=0
|
|
930
980
|
|
|
@@ -948,8 +998,6 @@ install_docker() {
|
|
|
948
998
|
:
|
|
949
999
|
elif command -v docker-compose &>/dev/null; then
|
|
950
1000
|
:
|
|
951
|
-
elif [[ "$OS" == "macos" ]]; then
|
|
952
|
-
:
|
|
953
1001
|
else
|
|
954
1002
|
need_install_compose=1
|
|
955
1003
|
fi
|
|
@@ -962,8 +1010,6 @@ install_docker() {
|
|
|
962
1010
|
|
|
963
1011
|
if [[ $need_install_docker -eq 1 ]]; then
|
|
964
1012
|
ui_info "Docker not found — installing..."
|
|
965
|
-
# _do_install_docker installs docker-compose-plugin in the same apt command,
|
|
966
|
-
# so Compose V2 will be available immediately after — no separate step needed.
|
|
967
1013
|
if ! _do_install_docker; then
|
|
968
1014
|
ui_warn "Official Docker install script failed — trying system package manager fallback..."
|
|
969
1015
|
if ! _do_install_docker_apt_fallback; then
|
|
@@ -971,7 +1017,6 @@ install_docker() {
|
|
|
971
1017
|
return 1
|
|
972
1018
|
fi
|
|
973
1019
|
fi
|
|
974
|
-
# Compose is bundled; skip the separate install step
|
|
975
1020
|
need_install_compose=0
|
|
976
1021
|
fi
|
|
977
1022
|
|
|
@@ -995,13 +1040,23 @@ _do_install_docker() {
|
|
|
995
1040
|
fi
|
|
996
1041
|
|
|
997
1042
|
if [[ "$OS" == "macos" ]]; then
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1043
|
+
ui_info "Installing docker and colima via Homebrew..."
|
|
1044
|
+
if ! command -v brew &>/dev/null; then
|
|
1045
|
+
ui_warn "Homebrew not found. Install it from https://brew.sh then re-run this script."
|
|
1046
|
+
return 1
|
|
1002
1047
|
fi
|
|
1003
|
-
|
|
1004
|
-
|
|
1048
|
+
brew install -q docker colima || { ui_warn "brew install failed"; return 1; }
|
|
1049
|
+
ui_success "docker and colima installed"
|
|
1050
|
+
|
|
1051
|
+
mkdir -p "${_COLIMA_HOME}"
|
|
1052
|
+
ui_info "Starting Colima VM (profile: ${_COLIMA_PROFILE})..."
|
|
1053
|
+
_colima start "${_COLIMA_PROFILE}" \
|
|
1054
|
+
--vm-type vz --mount-type virtiofs --network-address \
|
|
1055
|
+
--activate=false --cpu 2 --memory 4 --disk 60 >/dev/null \
|
|
1056
|
+
|| { ui_warn "colima start failed — run 'COLIMA_HOME=${_COLIMA_HOME} colima start ${_COLIMA_PROFILE}' manually"; return 1; }
|
|
1057
|
+
ui_success "Colima is running"
|
|
1058
|
+
export DOCKER_HOST="unix://${_COLIMA_SOCKET}"
|
|
1059
|
+
return 0
|
|
1005
1060
|
fi
|
|
1006
1061
|
|
|
1007
1062
|
# Step 1: download
|
|
@@ -1096,7 +1151,7 @@ _do_install_docker_apt_fallback() {
|
|
|
1096
1151
|
fi
|
|
1097
1152
|
|
|
1098
1153
|
if [[ "$OS" == "macos" ]]; then
|
|
1099
|
-
ui_warn "No apt/dnf fallback available on macOS —
|
|
1154
|
+
ui_warn "No apt/dnf fallback available on macOS — install via Homebrew: brew install docker colima"
|
|
1100
1155
|
return 1
|
|
1101
1156
|
fi
|
|
1102
1157
|
|
|
@@ -1157,17 +1212,30 @@ _ensure_docker_running() {
|
|
|
1157
1212
|
fi
|
|
1158
1213
|
|
|
1159
1214
|
if [[ "$OS" == "macos" ]]; then
|
|
1215
|
+
export DOCKER_HOST="unix://${_COLIMA_SOCKET}"
|
|
1216
|
+
if ! docker info &>/dev/null 2>&1; then
|
|
1217
|
+
ui_info "Starting Colima VM..."
|
|
1218
|
+
mkdir -p "${_COLIMA_HOME}"
|
|
1219
|
+
if ! _colima start "${_COLIMA_PROFILE}" \
|
|
1220
|
+
--vm-type vz --mount-type virtiofs --network-address \
|
|
1221
|
+
--activate=false --cpu 2 --memory 4 --disk 60 >/dev/null; then
|
|
1222
|
+
ui_warn "colima start failed"
|
|
1223
|
+
ui_info "Run manually: COLIMA_HOME=${_COLIMA_HOME} colima start ${_COLIMA_PROFILE}"
|
|
1224
|
+
return 1
|
|
1225
|
+
fi
|
|
1226
|
+
fi
|
|
1160
1227
|
local waited=0
|
|
1228
|
+
local timeout=120
|
|
1161
1229
|
while ! docker info &>/dev/null 2>&1; do
|
|
1162
|
-
if [[ $waited -ge
|
|
1163
|
-
ui_warn "Docker daemon did not become ready within
|
|
1164
|
-
ui_info "
|
|
1230
|
+
if [[ $waited -ge $timeout ]]; then
|
|
1231
|
+
ui_warn "Docker daemon did not become ready within ${timeout} seconds"
|
|
1232
|
+
ui_info "Run: COLIMA_HOME=${_COLIMA_HOME} colima status ${_COLIMA_PROFILE}"
|
|
1165
1233
|
return 1
|
|
1166
1234
|
fi
|
|
1167
|
-
sleep
|
|
1168
|
-
(( waited
|
|
1235
|
+
sleep 2
|
|
1236
|
+
(( waited += 2 )) || true
|
|
1169
1237
|
done
|
|
1170
|
-
|
|
1238
|
+
ui_success "Docker daemon is ready"
|
|
1171
1239
|
return 0
|
|
1172
1240
|
fi
|
|
1173
1241
|
|
|
@@ -1303,6 +1371,21 @@ docker_exec() {
|
|
|
1303
1371
|
fi
|
|
1304
1372
|
}
|
|
1305
1373
|
|
|
1374
|
+
# Private Colima wrapper — runs colima with COLIMA_HOME scoped to JishuShell's
|
|
1375
|
+
# data directory so the VM, socket, and all state are fully isolated from any
|
|
1376
|
+
# user-level Docker Desktop or default Colima installation.
|
|
1377
|
+
#
|
|
1378
|
+
# Usage: _colima start jishushell --vm-type vz ...
|
|
1379
|
+
# _colima stop jishushell
|
|
1380
|
+
# _colima status jishushell
|
|
1381
|
+
_COLIMA_HOME="${JISHUSHELL_HOME}/colima"
|
|
1382
|
+
_COLIMA_PROFILE="jishushell"
|
|
1383
|
+
_COLIMA_SOCKET="${_COLIMA_HOME}/${_COLIMA_PROFILE}/docker.sock"
|
|
1384
|
+
|
|
1385
|
+
_colima() {
|
|
1386
|
+
COLIMA_HOME="${_COLIMA_HOME}" command colima "$@"
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1306
1389
|
# ─── 3. Nomad ────────────────────────────────────────────────────────────────
|
|
1307
1390
|
|
|
1308
1391
|
install_nomad() {
|
|
@@ -1531,17 +1614,29 @@ _install_nomad_binary() {
|
|
|
1531
1614
|
ui_success "Nomad installed: v${installed_version} → ${dest}"
|
|
1532
1615
|
}
|
|
1533
1616
|
|
|
1534
|
-
# Add ~/.jishushell/bin to PATH in shell startup files and current session
|
|
1617
|
+
# Add ~/.jishushell/bin and npm global bin to PATH in shell startup files and current session
|
|
1535
1618
|
_ensure_jishushell_bin_in_path() {
|
|
1536
1619
|
local bin_dir="${JISHUSHELL_BIN_DIR}"
|
|
1537
1620
|
local marker="# jishushell-bin-path"
|
|
1621
|
+
|
|
1622
|
+
# Also ensure npm global bin is in PATH (for `npm install -g` with custom prefix)
|
|
1623
|
+
local npm_bin=""
|
|
1624
|
+
if command -v npm &>/dev/null; then
|
|
1625
|
+
npm_bin="$(npm config get prefix 2>/dev/null)/bin"
|
|
1626
|
+
fi
|
|
1627
|
+
|
|
1628
|
+
# Build PATH line: include npm global bin if it differs from jishushell bin
|
|
1538
1629
|
local init_line="export PATH=\"${bin_dir}:\$PATH\""
|
|
1630
|
+
if [[ -n "$npm_bin" && "$npm_bin" != "$bin_dir" && -d "$npm_bin" ]]; then
|
|
1631
|
+
init_line="export PATH=\"${bin_dir}:${npm_bin}:\$PATH\""
|
|
1632
|
+
export PATH="${npm_bin}:${PATH}"
|
|
1633
|
+
fi
|
|
1539
1634
|
|
|
1540
1635
|
# Export for the current running shell immediately
|
|
1541
1636
|
export PATH="${bin_dir}:${PATH}"
|
|
1542
1637
|
|
|
1543
1638
|
if [[ "$DRY_RUN" == "1" ]]; then
|
|
1544
|
-
ui_info "[dry-run] Would add
|
|
1639
|
+
ui_info "[dry-run] Would add PATH entries in shell startup files"
|
|
1545
1640
|
return 0
|
|
1546
1641
|
fi
|
|
1547
1642
|
|
|
@@ -1550,7 +1645,7 @@ _ensure_jishushell_bin_in_path() {
|
|
|
1550
1645
|
for rc in "${rc_files[@]}"; do
|
|
1551
1646
|
if [[ -f "$rc" ]] && ! grep -qF "$marker" "$rc" 2>/dev/null; then
|
|
1552
1647
|
printf '\n%s\n%s\n' "$marker" "$init_line" >> "$rc"
|
|
1553
|
-
ui_info "Added
|
|
1648
|
+
ui_info "Added PATH entries in ${rc}"
|
|
1554
1649
|
added=1
|
|
1555
1650
|
fi
|
|
1556
1651
|
done
|
|
@@ -1587,6 +1682,14 @@ _ensure_nomad_hcl() {
|
|
|
1587
1682
|
# Dirs are created by the current user — no sudo needed
|
|
1588
1683
|
chown -R "${REAL_USER}:${REAL_GID:-${REAL_USER}}" "${JISHUSHELL_HOME}" 2>/dev/null || true
|
|
1589
1684
|
|
|
1685
|
+
# Loopback interface name: lo0 on macOS, lo on Linux.
|
|
1686
|
+
# Forces Nomad to fingerprint 127.0.0.1 as the node IP so Docker port
|
|
1687
|
+
# publishing binds to loopback instead of the LAN IP. On macOS+Colima the
|
|
1688
|
+
# LAN IP doesn't exist inside the Lima VM, causing "cannot assign requested
|
|
1689
|
+
# address" when Docker tries to bind to it.
|
|
1690
|
+
local loopback_iface="lo"
|
|
1691
|
+
[[ "$OS" == "macos" ]] && loopback_iface="lo0"
|
|
1692
|
+
|
|
1590
1693
|
cat > "$config_file" << NOMAD_HCL
|
|
1591
1694
|
data_dir = "${nomad_data_dir}"
|
|
1592
1695
|
|
|
@@ -1608,6 +1711,7 @@ server {
|
|
|
1608
1711
|
client {
|
|
1609
1712
|
enabled = true
|
|
1610
1713
|
servers = ["127.0.0.1:4647"]
|
|
1714
|
+
network_interface = "${loopback_iface}"
|
|
1611
1715
|
alloc_dir = "${nomad_alloc_dir}"
|
|
1612
1716
|
|
|
1613
1717
|
drain_on_shutdown {
|
|
@@ -1805,10 +1909,10 @@ _install_nomad_launchd() {
|
|
|
1805
1909
|
|
|
1806
1910
|
mkdir -p "${HOME}/Library/LaunchAgents"
|
|
1807
1911
|
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1912
|
+
# Always use JishuShell's private Colima socket — hardcoded, not runtime-detected.
|
|
1913
|
+
# Colima may not be running yet when the plist is written; runtime fallback would
|
|
1914
|
+
# pick the wrong socket (Docker Desktop or /var/run/docker.sock).
|
|
1915
|
+
local docker_sock="${_COLIMA_SOCKET}"
|
|
1812
1916
|
|
|
1813
1917
|
cat > "$plist_path" << PLIST
|
|
1814
1918
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -1870,6 +1974,54 @@ fs.writeFileSync(p, JSON.stringify(cfg, null, 2));
|
|
|
1870
1974
|
" 2>/dev/null || true
|
|
1871
1975
|
}
|
|
1872
1976
|
|
|
1977
|
+
_read_openclaw_image_from_panel() {
|
|
1978
|
+
local panel_file="${JISHUSHELL_HOME}/panel.json"
|
|
1979
|
+
node -e "
|
|
1980
|
+
const fs = require('fs');
|
|
1981
|
+
const p = '${panel_file}';
|
|
1982
|
+
try {
|
|
1983
|
+
const cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
1984
|
+
if (typeof cfg.openclaw_image === 'string' && cfg.openclaw_image.trim()) {
|
|
1985
|
+
process.stdout.write(cfg.openclaw_image.trim());
|
|
1986
|
+
}
|
|
1987
|
+
} catch {}
|
|
1988
|
+
" 2>/dev/null || true
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
_pin_openclaw_image_if_needed() {
|
|
1992
|
+
local image="$1"
|
|
1993
|
+
if [[ -z "${image}" ]]; then
|
|
1994
|
+
return 1
|
|
1995
|
+
fi
|
|
1996
|
+
if [[ ! "${image}" =~ :(latest|slim)$ ]]; then
|
|
1997
|
+
printf '%s' "${image}"
|
|
1998
|
+
return 0
|
|
1999
|
+
fi
|
|
2000
|
+
|
|
2001
|
+
local version=""
|
|
2002
|
+
version="$(docker_exec run --rm --entrypoint node "${image}" -p "require('/app/node_modules/openclaw/package.json').version" 2>/dev/null | tr -d '\r\n')"
|
|
2003
|
+
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
|
2004
|
+
printf '%s' "${image}"
|
|
2005
|
+
return 0
|
|
2006
|
+
fi
|
|
2007
|
+
|
|
2008
|
+
local repo="${image%:*}"
|
|
2009
|
+
local pinned="${repo}:${version}"
|
|
2010
|
+
if docker_exec image inspect "${pinned}" &>/dev/null 2>&1; then
|
|
2011
|
+
printf '%s' "${pinned}"
|
|
2012
|
+
return 0
|
|
2013
|
+
fi
|
|
2014
|
+
|
|
2015
|
+
if docker_exec tag "${image}" "${pinned}" &>/dev/null 2>&1; then
|
|
2016
|
+
docker_exec rmi "${image}" &>/dev/null 2>&1 || true
|
|
2017
|
+
printf '%s' "${pinned}"
|
|
2018
|
+
return 0
|
|
2019
|
+
fi
|
|
2020
|
+
|
|
2021
|
+
printf '%s' "${image}"
|
|
2022
|
+
return 0
|
|
2023
|
+
}
|
|
2024
|
+
|
|
1873
2025
|
# Install OpenClaw npm package on the host (for process manager / raw_exec modes).
|
|
1874
2026
|
# Skipped when using official Docker image.
|
|
1875
2027
|
_install_openclaw_npm() {
|
|
@@ -1921,25 +2073,15 @@ install_openclaw() {
|
|
|
1921
2073
|
return 1
|
|
1922
2074
|
fi
|
|
1923
2075
|
|
|
2076
|
+
local docker_tag="${OPENCLAW_DOCKER_TAG}"
|
|
2077
|
+
local configured_tag=""
|
|
2078
|
+
|
|
1924
2079
|
if [[ "$DRY_RUN" == "1" ]]; then
|
|
1925
|
-
ui_info "[dry-run] Would:
|
|
1926
|
-
ui_info "[dry-run] Would: docker build -t jishushell-openclaw:<version> (npm package + Python)"
|
|
2080
|
+
ui_info "[dry-run] Would: docker pull ${docker_tag} (fallback: local build)"
|
|
1927
2081
|
return 0
|
|
1928
2082
|
fi
|
|
1929
2083
|
|
|
1930
|
-
# ── Step 1:
|
|
1931
|
-
_install_openclaw_npm || return 1
|
|
1932
|
-
|
|
1933
|
-
# Resolve versioned tag from installed package (e.g. jishushell-openclaw:2026.3.31)
|
|
1934
|
-
local pkg_dir="${JISHUSHELL_HOME}/packages/openclaw"
|
|
1935
|
-
local oc_ver
|
|
1936
|
-
oc_ver="$(node -p "require('${pkg_dir}/lib/node_modules/openclaw/package.json').version" 2>/dev/null || echo "")"
|
|
1937
|
-
local docker_tag="${OPENCLAW_DOCKER_TAG}"
|
|
1938
|
-
if [[ -n "$oc_ver" ]]; then
|
|
1939
|
-
docker_tag="jishushell-openclaw:${oc_ver}"
|
|
1940
|
-
fi
|
|
1941
|
-
|
|
1942
|
-
# ── Step 2: Ensure Docker daemon is accessible ────────────────────────────
|
|
2084
|
+
# ── Step 1: Ensure Docker daemon is accessible ────────────────────────────
|
|
1943
2085
|
if ! docker_exec info &>/dev/null 2>&1; then
|
|
1944
2086
|
if command -v sg &>/dev/null 2>/dev/null && sg docker -c "docker info" &>/dev/null 2>&1; then
|
|
1945
2087
|
DOCKER_CMD_PREFIX="sg docker -c"
|
|
@@ -1950,7 +2092,7 @@ install_openclaw() {
|
|
|
1950
2092
|
else
|
|
1951
2093
|
ui_warn "Docker daemon is not reachable"
|
|
1952
2094
|
if [[ "$OS" == "macos" ]]; then
|
|
1953
|
-
ui_warn "
|
|
2095
|
+
ui_warn "Run: COLIMA_HOME=${_COLIMA_HOME} colima start ${_COLIMA_PROFILE}"
|
|
1954
2096
|
else
|
|
1955
2097
|
ui_warn "Ensure Docker is running: sudo systemctl start docker"
|
|
1956
2098
|
fi
|
|
@@ -1958,49 +2100,90 @@ install_openclaw() {
|
|
|
1958
2100
|
fi
|
|
1959
2101
|
fi
|
|
1960
2102
|
|
|
1961
|
-
# ── Step
|
|
2103
|
+
# ── Step 2: Reuse the currently configured pinned image if it already
|
|
2104
|
+
# exists locally. This avoids re-pulling :latest on machines where the
|
|
2105
|
+
# running JishuShell service has already migrated panel.json from a mutable
|
|
2106
|
+
# tag (e.g. :latest) to an immutable version tag (e.g. :2026.4.9).
|
|
2107
|
+
configured_tag="$(_read_openclaw_image_from_panel)"
|
|
2108
|
+
if [[ -n "${configured_tag}" ]] && docker_exec image inspect "${configured_tag}" &>/dev/null 2>&1; then
|
|
2109
|
+
OPENCLAW_IMAGE="$(_pin_openclaw_image_if_needed "${configured_tag}")"
|
|
2110
|
+
_save_openclaw_image_to_panel "${OPENCLAW_IMAGE}"
|
|
2111
|
+
ui_success "Docker image ${OPENCLAW_IMAGE} already exists — reusing configured image"
|
|
2112
|
+
return 0
|
|
2113
|
+
fi
|
|
2114
|
+
|
|
2115
|
+
# ── Step 3: Skip if the requested install tag already exists ─────────────
|
|
1962
2116
|
if docker_exec image inspect "${docker_tag}" &>/dev/null 2>&1; then
|
|
1963
|
-
OPENCLAW_IMAGE="${docker_tag}"
|
|
1964
|
-
_save_openclaw_image_to_panel "${
|
|
1965
|
-
ui_success "Docker image ${
|
|
2117
|
+
OPENCLAW_IMAGE="$(_pin_openclaw_image_if_needed "${docker_tag}")"
|
|
2118
|
+
_save_openclaw_image_to_panel "${OPENCLAW_IMAGE}"
|
|
2119
|
+
ui_success "Docker image ${OPENCLAW_IMAGE} already exists — skipping"
|
|
1966
2120
|
return 0
|
|
1967
2121
|
fi
|
|
1968
2122
|
|
|
1969
|
-
# ── Step 4:
|
|
1970
|
-
|
|
2123
|
+
# ── Step 4: Pull from registry, fallback to local build ──────────────────
|
|
2124
|
+
ui_info "Pulling OpenClaw Docker image: ${docker_tag} ..."
|
|
2125
|
+
log_detail ""
|
|
2126
|
+
log_detail "[$(date '+%H:%M:%S')] docker pull ${docker_tag}"
|
|
2127
|
+
if log_cmd docker_exec pull "${docker_tag}"; then
|
|
2128
|
+
OPENCLAW_IMAGE="$(_pin_openclaw_image_if_needed "${docker_tag}")"
|
|
2129
|
+
_save_openclaw_image_to_panel "${OPENCLAW_IMAGE}"
|
|
2130
|
+
ui_success "OpenClaw Docker image pulled: ${OPENCLAW_IMAGE}"
|
|
2131
|
+
return 0
|
|
2132
|
+
fi
|
|
2133
|
+
|
|
2134
|
+
# ── Step 3b: Fallback — build locally using bundled Dockerfile ────
|
|
2135
|
+
ui_warn "Pull failed, falling back to local build..."
|
|
2136
|
+
|
|
2137
|
+
# Locate the bundled Dockerfile.openclaw-slim + openclaw-entry.sh.
|
|
2138
|
+
# Both ship at the npm package root, alongside the install/ directory,
|
|
2139
|
+
# so from this script's perspective they are one level up.
|
|
2140
|
+
local script_dir
|
|
2141
|
+
if [[ -n "${BASH_SOURCE[0]:-}" ]]; then
|
|
2142
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
2143
|
+
else
|
|
2144
|
+
script_dir="${PWD}"
|
|
2145
|
+
fi
|
|
2146
|
+
local dockerfile_src="${script_dir}/../Dockerfile.openclaw-slim"
|
|
2147
|
+
local entrypoint_src="${script_dir}/../openclaw-entry.sh"
|
|
2148
|
+
|
|
2149
|
+
if [[ ! -f "${dockerfile_src}" || ! -f "${entrypoint_src}" ]]; then
|
|
2150
|
+
ui_error "Bundled build files not found near ${script_dir}/.."
|
|
2151
|
+
ui_error "Expected: Dockerfile.openclaw-slim and openclaw-entry.sh"
|
|
2152
|
+
return 1
|
|
2153
|
+
fi
|
|
2154
|
+
|
|
2155
|
+
local build_ctx
|
|
2156
|
+
build_ctx="$(mktemp -d)"
|
|
2157
|
+
trap "rm -rf '${build_ctx}'" EXIT
|
|
2158
|
+
|
|
2159
|
+
cp "${dockerfile_src}" "${build_ctx}/Dockerfile.openclaw-slim"
|
|
2160
|
+
cp "${entrypoint_src}" "${build_ctx}/openclaw-entry.sh"
|
|
1971
2161
|
|
|
1972
|
-
#
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
RUN ln -sf /app/node_modules/openclaw/openclaw.mjs /app/openclaw.mjs && \
|
|
1984
|
-
ln -sf /app/node_modules/openclaw/openclaw.mjs /usr/local/bin/openclaw && \
|
|
1985
|
-
cp /app/node_modules/openclaw/package.json /app/package.json 2>/dev/null || true
|
|
1986
|
-
USER node
|
|
1987
|
-
CMD ["node", "openclaw.mjs", "gateway", "--allow-unconfigured"]
|
|
1988
|
-
DOCKERFILE
|
|
1989
|
-
|
|
1990
|
-
ui_info "Building Docker image: ${docker_tag} (npm package + Python)..."
|
|
2162
|
+
# Query current OpenClaw version from npm so the --build-arg busts the
|
|
2163
|
+
# Docker layer cache for the `RUN npm install openclaw@${ver}` step.
|
|
2164
|
+
# Fall back to "latest" if npm is unreachable.
|
|
2165
|
+
local openclaw_ver
|
|
2166
|
+
openclaw_ver="$(npm view openclaw version 2>/dev/null)"
|
|
2167
|
+
if [[ -z "${openclaw_ver}" ]]; then
|
|
2168
|
+
openclaw_ver="latest"
|
|
2169
|
+
fi
|
|
2170
|
+
log_detail "Resolved OpenClaw version for build: ${openclaw_ver}"
|
|
2171
|
+
|
|
2172
|
+
ui_info "Building OpenClaw Docker image locally: ${docker_tag} (openclaw@${openclaw_ver}) ..."
|
|
1991
2173
|
log_detail ""
|
|
1992
|
-
log_detail "[$(date '+%H:%M:%S')] docker build -t ${docker_tag} ${
|
|
1993
|
-
if log_cmd docker_exec build --network=host
|
|
2174
|
+
log_detail "[$(date '+%H:%M:%S')] docker build --network=host --build-arg OPENCLAW_VERSION=${openclaw_ver} -f Dockerfile.openclaw-slim -t ${docker_tag} ${build_ctx}"
|
|
2175
|
+
if log_cmd docker_exec build --network=host \
|
|
2176
|
+
--build-arg "OPENCLAW_VERSION=${openclaw_ver}" \
|
|
2177
|
+
-f "${build_ctx}/Dockerfile.openclaw-slim" \
|
|
2178
|
+
-t "${docker_tag}" "${build_ctx}"; then
|
|
1994
2179
|
OPENCLAW_IMAGE="${docker_tag}"
|
|
1995
2180
|
_save_openclaw_image_to_panel "${docker_tag}"
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
fi
|
|
2000
|
-
rm -f "${pkg_dir}/Dockerfile"
|
|
2001
|
-
ui_success "OpenClaw Docker image built: ${docker_tag} (with Python)"
|
|
2181
|
+
rm -rf "${build_ctx}"
|
|
2182
|
+
trap - EXIT
|
|
2183
|
+
ui_success "OpenClaw Docker image built: ${docker_tag}"
|
|
2002
2184
|
else
|
|
2003
|
-
rm -
|
|
2185
|
+
rm -rf "${build_ctx}"
|
|
2186
|
+
trap - EXIT
|
|
2004
2187
|
ui_error "Failed to build OpenClaw Docker image"
|
|
2005
2188
|
return 1
|
|
2006
2189
|
fi
|
|
@@ -2043,7 +2226,7 @@ show_install_plan() {
|
|
|
2043
2226
|
ui_kv "Node.js" "$(if [[ $SKIP_NODE -eq 1 ]]; then echo 'skip'; else echo "v${NODE_VERSION} via nvm v${NVM_VERSION}"; fi)"
|
|
2044
2227
|
ui_kv "Docker" "$(if [[ $SKIP_DOCKER -eq 1 ]]; then echo 'skip'; else echo 'latest stable'; fi)"
|
|
2045
2228
|
ui_kv "Nomad" "$(if [[ $SKIP_NOMAD -eq 1 ]]; then echo 'skip'; else echo "v${NOMAD_VERSION}"; fi)"
|
|
2046
|
-
ui_kv "OpenClaw" "$(if [[ \"${SKIP_OPENCLAW}\" == \"1\" ]]; then echo 'skip'; else echo \"
|
|
2229
|
+
ui_kv "OpenClaw" "$(if [[ \"${SKIP_OPENCLAW}\" == \"1\" ]]; then echo 'skip'; else echo \"docker pull ${OPENCLAW_DOCKER_TAG}\"; fi)"
|
|
2047
2230
|
if [[ $with_jishushell -eq 1 ]]; then
|
|
2048
2231
|
local _plan_jishu
|
|
2049
2232
|
if [[ $SKIP_JISHUSHELL -eq 1 ]]; then
|
|
@@ -2114,7 +2297,15 @@ show_summary() {
|
|
|
2114
2297
|
fi
|
|
2115
2298
|
|
|
2116
2299
|
if [[ "${SKIP_OPENCLAW}" != "1" ]]; then
|
|
2117
|
-
|
|
2300
|
+
local _summary_openclaw_image=""
|
|
2301
|
+
_summary_openclaw_image="$(_read_openclaw_image_from_panel)"
|
|
2302
|
+
if [[ -z "${_summary_openclaw_image}" && -n "${OPENCLAW_IMAGE}" ]]; then
|
|
2303
|
+
_summary_openclaw_image="${OPENCLAW_IMAGE}"
|
|
2304
|
+
fi
|
|
2305
|
+
|
|
2306
|
+
if [[ -n "${_summary_openclaw_image}" ]] && docker_exec image inspect "${_summary_openclaw_image}" &>/dev/null 2>&1; then
|
|
2307
|
+
ui_kv "OpenClaw" "✓ ${_summary_openclaw_image}"
|
|
2308
|
+
elif [[ -n "${OPENCLAW_IMAGE}" ]] && docker_exec image inspect "${OPENCLAW_IMAGE}" &>/dev/null 2>&1; then
|
|
2118
2309
|
ui_kv "OpenClaw" "✓ ${OPENCLAW_IMAGE}"
|
|
2119
2310
|
elif [[ "$DRY_RUN" == "1" ]]; then
|
|
2120
2311
|
ui_kv "OpenClaw" "- dry-run"
|
|
@@ -2462,7 +2653,9 @@ WantedBy=multi-user.target"
|
|
|
2462
2653
|
${SUDO} systemctl restart jishushell 2>/dev/null || true
|
|
2463
2654
|
ui_success "JishuShell systemd service updated and restarted"
|
|
2464
2655
|
else
|
|
2465
|
-
|
|
2656
|
+
# Package may have been upgraded — always restart to pick up new code
|
|
2657
|
+
${SUDO} systemctl restart jishushell 2>/dev/null || true
|
|
2658
|
+
ui_success "JishuShell systemd service restarted"
|
|
2466
2659
|
fi
|
|
2467
2660
|
}
|
|
2468
2661
|
|
|
@@ -2672,7 +2865,7 @@ Steps:
|
|
|
2672
2865
|
1 Node.js (via nvm)
|
|
2673
2866
|
2 Docker
|
|
2674
2867
|
3 Nomad
|
|
2675
|
-
4 OpenClaw (
|
|
2868
|
+
4 OpenClaw (docker pull / local build)
|
|
2676
2869
|
5 JishuShell
|
|
2677
2870
|
6 JishuShell service registration (autostart)
|
|
2678
2871
|
|
|
@@ -2735,27 +2928,37 @@ _prompt_install_confirm() {
|
|
|
2735
2928
|
echo -e " commercial use, competitive offerings, or redistribution."
|
|
2736
2929
|
echo ""
|
|
2737
2930
|
|
|
2738
|
-
if [[ $SKIP_DOCKER -eq 0 ]]; then
|
|
2931
|
+
if [[ $SKIP_DOCKER -eq 0 && "$OS" == "linux" ]]; then
|
|
2739
2932
|
echo -e " ${BOLD}Docker Engine${NC}"
|
|
2740
|
-
echo -e " ${MUTED}
|
|
2741
|
-
echo -e " ${MUTED}
|
|
2742
|
-
echo -e " ${MUTED}
|
|
2743
|
-
echo -e " ${MUTED}
|
|
2933
|
+
echo -e " ${MUTED} Docker Engine (container runtime — Linux)${NC}"
|
|
2934
|
+
echo -e " ${MUTED} URL : https://github.com/moby/moby${NC}"
|
|
2935
|
+
echo -e " ${MUTED} License : Apache License, Version 2.0${NC}"
|
|
2936
|
+
echo -e " ${MUTED} Author : Docker, Inc.${NC}"
|
|
2937
|
+
echo -e " ${MUTED} https://github.com/moby/moby/blob/master/LICENSE${NC}"
|
|
2938
|
+
echo ""
|
|
2939
|
+
fi
|
|
2940
|
+
if [[ $SKIP_DOCKER -eq 0 && "$OS" == "macos" ]]; then
|
|
2941
|
+
echo -e " ${BOLD}Colima${NC}"
|
|
2942
|
+
echo -e " ${MUTED} Colima (container runtime — macOS)${NC}"
|
|
2943
|
+
echo -e " ${MUTED} URL : https://github.com/abiosoft/colima${NC}"
|
|
2944
|
+
echo -e " ${MUTED} License : MIT License${NC}"
|
|
2945
|
+
echo -e " ${MUTED} https://github.com/abiosoft/colima/blob/main/LICENSE${NC}"
|
|
2946
|
+
echo -e " ${MUTED} Author : Abiola Ibrahim${NC}"
|
|
2744
2947
|
echo ""
|
|
2745
2948
|
fi
|
|
2746
2949
|
if [[ $SKIP_NOMAD -eq 0 ]]; then
|
|
2747
|
-
echo -e " ${BOLD}Nomad
|
|
2748
|
-
echo -e " ${MUTED}
|
|
2749
|
-
echo -e " ${MUTED}
|
|
2750
|
-
echo -e " ${MUTED}
|
|
2751
|
-
echo -e " ${MUTED}
|
|
2752
|
-
echo -e " ${MUTED}
|
|
2950
|
+
echo -e " ${BOLD}Nomad${NC}"
|
|
2951
|
+
echo -e " ${MUTED} Nomad v${NOMAD_VERSION}+ (>= 1.7.0)${NC}"
|
|
2952
|
+
echo -e " ${MUTED} URL : https://github.com/hashicorp/nomad${NC}"
|
|
2953
|
+
echo -e " ${MUTED} License : Business Source License 1.1 (BSL 1.1)${NC}"
|
|
2954
|
+
echo -e " ${MUTED} https://github.com/hashicorp/nomad/blob/main/LICENSE${NC}"
|
|
2955
|
+
echo -e " ${MUTED} Licensor: International Business Machines Corporation (IBM)${NC}"
|
|
2956
|
+
echo -e " ${MUTED} Work : Nomad Version 1.7.0 or later. (c) 2024 IBM Corp.${NC}"
|
|
2753
2957
|
echo ""
|
|
2754
2958
|
fi
|
|
2755
|
-
echo -e " ${
|
|
2756
|
-
echo -e "
|
|
2757
|
-
echo -e "
|
|
2758
|
-
echo -e " ${MUTED}sudo privileges are required to write to system directories.${NC}"
|
|
2959
|
+
echo -e " ${ACCENT}─────────────────────────────────────────────────────────${NC}"
|
|
2960
|
+
echo -e " By continuing you acknowledge that you have read the above"
|
|
2961
|
+
echo -e " notices and agree to each package's license terms."
|
|
2759
2962
|
echo ""
|
|
2760
2963
|
} >/dev/tty
|
|
2761
2964
|
|
|
@@ -2767,6 +2970,9 @@ _prompt_install_confirm() {
|
|
|
2767
2970
|
exit 0
|
|
2768
2971
|
;;
|
|
2769
2972
|
esac
|
|
2973
|
+
|
|
2974
|
+
echo "" >/dev/tty
|
|
2975
|
+
echo -e " ${INFO}sudo privileges are required to write to system directories.${NC}" >/dev/tty
|
|
2770
2976
|
echo "" >/dev/tty
|
|
2771
2977
|
}
|
|
2772
2978
|
|
|
@@ -2885,7 +3091,7 @@ _jishu_install_main() {
|
|
|
2885
3091
|
# so the keepalive's early sudo -n true calls are intentional no-ops.
|
|
2886
3092
|
if [[ $EUID -ne 0 ]] && command -v sudo &>/dev/null; then
|
|
2887
3093
|
if [[ -z "${_SUDO_KEEPALIVE_PID:-}" ]]; then
|
|
2888
|
-
( while true; do sudo -n true 2>/dev/null; sleep 60; done ) &
|
|
3094
|
+
( while true; do sudo -n true 2>/dev/null; sleep 60; done ) &>/dev/null &
|
|
2889
3095
|
_SUDO_KEEPALIVE_PID=$!
|
|
2890
3096
|
disown "$_SUDO_KEEPALIVE_PID" 2>/dev/null || true
|
|
2891
3097
|
fi
|
|
@@ -2900,10 +3106,6 @@ _jishu_install_main() {
|
|
|
2900
3106
|
detect_os
|
|
2901
3107
|
detect_arch
|
|
2902
3108
|
show_install_plan --with-jishushell
|
|
2903
|
-
if [[ "$OS" == "macos" ]]; then
|
|
2904
|
-
ui_warn "macOS is not supported yet — coming soon!"
|
|
2905
|
-
exit 0
|
|
2906
|
-
fi
|
|
2907
3109
|
_prompt_install_confirm
|
|
2908
3110
|
check_sudo
|
|
2909
3111
|
ensure_prerequisites
|