jishushell 0.0.1 → 0.4.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/LICENSE +202 -0
- package/README.md +36 -0
- package/THIRD-PARTY-NOTICES +387 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.js +88 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +290 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +226 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +15 -0
- package/dist/constants.js.map +1 -0
- package/dist/control.d.ts +44 -0
- package/dist/control.js +1359 -0
- package/dist/control.js.map +1 -0
- package/dist/crypto-shim.d.ts +1 -0
- package/dist/crypto-shim.js +2 -0
- package/dist/crypto-shim.js.map +1 -0
- package/dist/doctor.d.ts +46 -0
- package/dist/doctor.js +937 -0
- package/dist/doctor.js.map +1 -0
- package/dist/install.d.ts +27 -0
- package/dist/install.js +570 -0
- package/dist/install.js.map +1 -0
- package/dist/routes/auth.d.ts +4 -0
- package/dist/routes/auth.js +151 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/instances.d.ts +2 -0
- package/dist/routes/instances.js +1303 -0
- package/dist/routes/instances.js.map +1 -0
- package/dist/routes/setup.d.ts +2 -0
- package/dist/routes/setup.js +139 -0
- package/dist/routes/setup.js.map +1 -0
- package/dist/routes/system.d.ts +2 -0
- package/dist/routes/system.js +102 -0
- package/dist/routes/system.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +392 -0
- package/dist/server.js.map +1 -0
- package/dist/services/instance-manager.d.ts +67 -0
- package/dist/services/instance-manager.js +1319 -0
- package/dist/services/instance-manager.js.map +1 -0
- package/dist/services/llm-proxy/adapters.d.ts +3 -0
- package/dist/services/llm-proxy/adapters.js +309 -0
- package/dist/services/llm-proxy/adapters.js.map +1 -0
- package/dist/services/llm-proxy/circuit-breaker.d.ts +9 -0
- package/dist/services/llm-proxy/circuit-breaker.js +73 -0
- package/dist/services/llm-proxy/circuit-breaker.js.map +1 -0
- package/dist/services/llm-proxy/encryption.d.ts +6 -0
- package/dist/services/llm-proxy/encryption.js +61 -0
- package/dist/services/llm-proxy/encryption.js.map +1 -0
- package/dist/services/llm-proxy/index.d.ts +24 -0
- package/dist/services/llm-proxy/index.js +708 -0
- package/dist/services/llm-proxy/index.js.map +1 -0
- package/dist/services/llm-proxy/rate-limiter.d.ts +1 -0
- package/dist/services/llm-proxy/rate-limiter.js +39 -0
- package/dist/services/llm-proxy/rate-limiter.js.map +1 -0
- package/dist/services/llm-proxy/sse.d.ts +10 -0
- package/dist/services/llm-proxy/sse.js +378 -0
- package/dist/services/llm-proxy/sse.js.map +1 -0
- package/dist/services/llm-proxy/ssrf.d.ts +16 -0
- package/dist/services/llm-proxy/ssrf.js +185 -0
- package/dist/services/llm-proxy/ssrf.js.map +1 -0
- package/dist/services/llm-proxy/types.d.ts +52 -0
- package/dist/services/llm-proxy/types.js +2 -0
- package/dist/services/llm-proxy/types.js.map +1 -0
- package/dist/services/llm-proxy/usage.d.ts +12 -0
- package/dist/services/llm-proxy/usage.js +108 -0
- package/dist/services/llm-proxy/usage.js.map +1 -0
- package/dist/services/nomad-manager.d.ts +22 -0
- package/dist/services/nomad-manager.js +828 -0
- package/dist/services/nomad-manager.js.map +1 -0
- package/dist/services/plugin-installer.d.ts +22 -0
- package/dist/services/plugin-installer.js +102 -0
- package/dist/services/plugin-installer.js.map +1 -0
- package/dist/services/process-manager.d.ts +25 -0
- package/dist/services/process-manager.js +531 -0
- package/dist/services/process-manager.js.map +1 -0
- package/dist/services/setup-manager.d.ts +93 -0
- package/dist/services/setup-manager.js +1922 -0
- package/dist/services/setup-manager.js.map +1 -0
- package/dist/services/system-monitor.d.ts +1 -0
- package/dist/services/system-monitor.js +79 -0
- package/dist/services/system-monitor.js.map +1 -0
- package/dist/services/telemetry/activation.d.ts +12 -0
- package/dist/services/telemetry/activation.js +75 -0
- package/dist/services/telemetry/activation.js.map +1 -0
- package/dist/services/telemetry/client.d.ts +21 -0
- package/dist/services/telemetry/client.js +47 -0
- package/dist/services/telemetry/client.js.map +1 -0
- package/dist/services/telemetry/device-fingerprint.d.ts +18 -0
- package/dist/services/telemetry/device-fingerprint.js +123 -0
- package/dist/services/telemetry/device-fingerprint.js.map +1 -0
- package/dist/services/telemetry/heartbeat.d.ts +13 -0
- package/dist/services/telemetry/heartbeat.js +81 -0
- package/dist/services/telemetry/heartbeat.js.map +1 -0
- package/dist/services/telemetry/index.d.ts +3 -0
- package/dist/services/telemetry/index.js +4 -0
- package/dist/services/telemetry/index.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/safe-json.d.ts +2 -0
- package/dist/utils/safe-json.js +80 -0
- package/dist/utils/safe-json.js.map +1 -0
- package/dist/utils/ttl-cache.d.ts +29 -0
- package/dist/utils/ttl-cache.js +77 -0
- package/dist/utils/ttl-cache.js.map +1 -0
- package/install/jishu-install.sh +2920 -0
- package/install/jishu-uninstall.sh +811 -0
- package/install/post-install.sh +110 -0
- package/install/post-uninstall.sh +46 -0
- package/package.json +57 -8
- package/public/assets/Dashboard-CAOQDYDR.js +1 -0
- package/public/assets/InitPassword-CkehIkJG.js +1 -0
- package/public/assets/InstanceDetail-CzW2S95J.js +14 -0
- package/public/assets/Login-RkjzTNWg.js +1 -0
- package/public/assets/NewInstance-DdbErdjA.js +1 -0
- package/public/assets/Settings-BUD7zwv9.js +1 -0
- package/public/assets/Setup-RRTIERGG.js +1 -0
- package/public/assets/index-77Ug7feY.css +1 -0
- package/public/assets/index-DfRnVUQR.js +16 -0
- package/public/assets/providers-lBSOjUWy.js +1 -0
- package/public/assets/usePolling-CqQ8hrNc.js +1 -0
- package/public/assets/vendor-i18n-Bvxxh8Di.js +9 -0
- package/public/assets/vendor-react-DONn7uBV.js +59 -0
- package/public/index.html +15 -0
- package/scripts/build-image.sh +55 -0
- package/scripts/run.sh +310 -0
- package/scripts/setup-pi.sh +80 -0
- package/scripts/start-feishu1.js +46 -0
- package/index.js +0 -0
- package/jishushell-0.0.1.tgz +0 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
JISHU_SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
+
# shellcheck source=jishu-install.sh
|
|
6
|
+
source "${JISHU_SCRIPT_DIR}/jishu-install.sh"
|
|
7
|
+
|
|
8
|
+
DO_NODE=0
|
|
9
|
+
DO_DOCKER=0
|
|
10
|
+
DO_DOCKER_CLEAN=0
|
|
11
|
+
DO_NOMAD=0
|
|
12
|
+
DO_OPENCLAW=0
|
|
13
|
+
DO_DATA=0
|
|
14
|
+
AUTO_YES=0
|
|
15
|
+
|
|
16
|
+
# ─── Argument parsing ─────────────────────────────────────────────────────────
|
|
17
|
+
usage() {
|
|
18
|
+
cat <<EOF
|
|
19
|
+
Usage: bash jishu-uninstall.sh [options]
|
|
20
|
+
|
|
21
|
+
Run without options to stop all services and remove them from auto-start.
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--node Remove Node.js versions managed by nvm, and nvm itself
|
|
25
|
+
--docker Remove Docker packages (Compose plugin, docker group)
|
|
26
|
+
--docker-clean Stop & remove all containers, images, volumes, then remove Docker
|
|
27
|
+
--nomad Remove Nomad binary and service registration
|
|
28
|
+
--openclaw Remove the OpenClaw npm package and its Docker image(s)
|
|
29
|
+
--data Delete the ~/.jishushell data directory (instances, config, logs)
|
|
30
|
+
--all Remove all of the above (full uninstall, implies --docker-clean)
|
|
31
|
+
--dry-run Print the removal plan only, do not execute anything
|
|
32
|
+
--yes, -y Skip all confirmation prompts (auto-yes)
|
|
33
|
+
--help, -h Show this help message
|
|
34
|
+
|
|
35
|
+
EOF
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
parse_args() {
|
|
39
|
+
while [[ $# -gt 0 ]]; do
|
|
40
|
+
case "$1" in
|
|
41
|
+
--node) DO_NODE=1 ;;
|
|
42
|
+
--docker) DO_DOCKER=1 ;;
|
|
43
|
+
--docker-clean) DO_DOCKER_CLEAN=1; DO_DOCKER=1 ;;
|
|
44
|
+
--nomad) DO_NOMAD=1 ;;
|
|
45
|
+
--openclaw) DO_OPENCLAW=1 ;;
|
|
46
|
+
--data) DO_DATA=1 ;;
|
|
47
|
+
--all) DO_NODE=1; DO_DOCKER_CLEAN=1; DO_DOCKER=1; DO_NOMAD=1; DO_OPENCLAW=1; DO_DATA=1; AUTO_YES=1 ;;
|
|
48
|
+
--dry-run) DRY_RUN=1 ;;
|
|
49
|
+
--yes|-y) AUTO_YES=1 ;;
|
|
50
|
+
--help|-h) usage; exit 0 ;;
|
|
51
|
+
*) ui_warn "Unknown argument: $1" ;;
|
|
52
|
+
esac
|
|
53
|
+
shift
|
|
54
|
+
done
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# ─── Stop & deregister auto-start services ───────────────────────────────────
|
|
58
|
+
stop_services() {
|
|
59
|
+
ui_section "Stopping services and removing auto-start"
|
|
60
|
+
|
|
61
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
62
|
+
ui_info "[dry-run] Would stop and deregister: com.jishushell.panel, com.jishushell.nomad"
|
|
63
|
+
ui_info "[dry-run] Would: npm uninstall -g jishushell"
|
|
64
|
+
return 0
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
68
|
+
local panel_plist="${HOME}/Library/LaunchAgents/com.jishushell.panel.plist"
|
|
69
|
+
local nomad_plist="${HOME}/Library/LaunchAgents/com.jishushell.nomad.plist"
|
|
70
|
+
|
|
71
|
+
if launchctl list 2>/dev/null | grep -q "com.jishushell.panel"; then
|
|
72
|
+
ui_info "Stopping JishuShell panel..."
|
|
73
|
+
launchctl unload -w "$panel_plist" 2>/dev/null || true
|
|
74
|
+
ui_success "JishuShell panel stopped and removed from auto-start"
|
|
75
|
+
else
|
|
76
|
+
ui_info "JishuShell panel is not running"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if [[ -f "$panel_plist" ]]; then
|
|
80
|
+
rm -f "$panel_plist"
|
|
81
|
+
ui_success "Removed: ${panel_plist}"
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
if launchctl list 2>/dev/null | grep -q "com.jishushell.nomad"; then
|
|
85
|
+
ui_info "Stopping Nomad..."
|
|
86
|
+
launchctl unload -w "$nomad_plist" 2>/dev/null || true
|
|
87
|
+
ui_success "Nomad stopped and removed from auto-start"
|
|
88
|
+
else
|
|
89
|
+
ui_info "Nomad launchd agent is not running"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
if [[ -f "$nomad_plist" ]]; then
|
|
93
|
+
rm -f "$nomad_plist"
|
|
94
|
+
ui_success "Removed: ${nomad_plist}"
|
|
95
|
+
fi
|
|
96
|
+
else
|
|
97
|
+
if command -v systemctl &>/dev/null; then
|
|
98
|
+
for svc in jishushell nomad; do
|
|
99
|
+
if systemctl is-active --quiet "$svc" 2>/dev/null; then
|
|
100
|
+
ui_info "Stopping ${svc}..."
|
|
101
|
+
${SUDO} systemctl stop "$svc" 2>/dev/null || true
|
|
102
|
+
fi
|
|
103
|
+
if systemctl is-enabled --quiet "$svc" 2>/dev/null; then
|
|
104
|
+
ui_info "Disabling ${svc} from auto-start..."
|
|
105
|
+
${SUDO} systemctl disable "$svc" 2>/dev/null || true
|
|
106
|
+
fi
|
|
107
|
+
${SUDO} rm -f "/etc/systemd/system/${svc}.service" 2>/dev/null || true
|
|
108
|
+
done
|
|
109
|
+
${SUDO} systemctl daemon-reload 2>/dev/null || true
|
|
110
|
+
ui_success "Services stopped and removed from auto-start"
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
if command -v npm &>/dev/null && npm list -g jishushell &>/dev/null 2>&1; then
|
|
115
|
+
ui_info "Uninstalling jishushell npm package..."
|
|
116
|
+
npm uninstall -g jishushell 2>/dev/null || true
|
|
117
|
+
ui_success "jishushell npm package removed"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Kill any nomad agent process started directly by jishushell (non-systemd/launchd)
|
|
121
|
+
if pgrep -f "nomad agent" &>/dev/null 2>&1; then
|
|
122
|
+
ui_info "Stopping orphaned Nomad agent process..."
|
|
123
|
+
pkill -TERM -f "nomad agent" 2>/dev/null || true
|
|
124
|
+
local _i=0
|
|
125
|
+
while pgrep -f "nomad agent" &>/dev/null 2>&1 && [[ $_i -lt 10 ]]; do
|
|
126
|
+
sleep 1
|
|
127
|
+
((_i++)) || true
|
|
128
|
+
done
|
|
129
|
+
if pgrep -f "nomad agent" &>/dev/null 2>&1; then
|
|
130
|
+
pkill -KILL -f "nomad agent" 2>/dev/null || true
|
|
131
|
+
fi
|
|
132
|
+
ui_success "Nomad agent stopped"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
local wrapper="${HOME}/.jishushell/bin/jishushell-panel-start"
|
|
136
|
+
if [[ -f "$wrapper" ]]; then
|
|
137
|
+
rm -f "$wrapper"
|
|
138
|
+
ui_success "Removed wrapper: ${wrapper}"
|
|
139
|
+
fi
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# ─── Node.js via nvm ──────────────────────────────────────────────────────────
|
|
143
|
+
uninstall_node() {
|
|
144
|
+
ui_section "Removing Node.js / nvm"
|
|
145
|
+
|
|
146
|
+
local nvm_dir="${NVM_DIR:-$HOME/.nvm}"
|
|
147
|
+
|
|
148
|
+
if [[ -s "$nvm_dir/nvm.sh" ]]; then
|
|
149
|
+
ui_info "Detected nvm installation: $nvm_dir"
|
|
150
|
+
|
|
151
|
+
# shellcheck source=/dev/null
|
|
152
|
+
\. "$nvm_dir/nvm.sh" 2>/dev/null || true
|
|
153
|
+
|
|
154
|
+
local installed_versions
|
|
155
|
+
installed_versions="$(nvm ls --no-colors 2>/dev/null | grep -oP 'v\d+\.\d+\.\d+' || true)"
|
|
156
|
+
|
|
157
|
+
if [[ -n "$installed_versions" ]]; then
|
|
158
|
+
ui_info "Installed Node.js versions:"
|
|
159
|
+
echo "$installed_versions" | while read -r ver; do
|
|
160
|
+
ui_info " $ver"
|
|
161
|
+
done
|
|
162
|
+
if confirm "Remove all listed Node.js versions?"; then
|
|
163
|
+
echo "$installed_versions" | while read -r ver; do
|
|
164
|
+
ui_info "Uninstalling Node.js $ver ..."
|
|
165
|
+
run_cmd nvm uninstall "$ver" 2>/dev/null || true
|
|
166
|
+
done
|
|
167
|
+
fi
|
|
168
|
+
else
|
|
169
|
+
ui_info "No Node.js versions found managed by nvm"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
if confirm "Delete nvm installation directory ($nvm_dir)?"; then
|
|
173
|
+
run_cmd rm -rf "$nvm_dir"
|
|
174
|
+
ui_success "nvm directory removed"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
local shell_configs=("$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.profile" "$HOME/.zshrc")
|
|
178
|
+
for cfg in "${shell_configs[@]}"; do
|
|
179
|
+
if [[ -f "$cfg" ]] && grep -q 'NVM_DIR' "$cfg" 2>/dev/null; then
|
|
180
|
+
ui_info "Cleaning nvm init lines from $cfg ..."
|
|
181
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
182
|
+
ui_info "[dry-run] Would remove NVM_DIR lines from $cfg"
|
|
183
|
+
else
|
|
184
|
+
cp "$cfg" "${cfg}.bak-jishu-uninstall"
|
|
185
|
+
sed -i '/NVM_DIR/d; /nvm\.sh/d; /bash_completion.*nvm/d' "$cfg"
|
|
186
|
+
ui_success "Cleaned $cfg (backup: ${cfg}.bak-jishu-uninstall)"
|
|
187
|
+
fi
|
|
188
|
+
fi
|
|
189
|
+
done
|
|
190
|
+
else
|
|
191
|
+
ui_info "nvm not found ($nvm_dir/nvm.sh does not exist)"
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
if command -v node &>/dev/null && [[ "$DRY_RUN" != "1" || DO_NODE -eq 1 ]]; then
|
|
195
|
+
local node_path
|
|
196
|
+
node_path="$(command -v node 2>/dev/null || true)"
|
|
197
|
+
if [[ "$node_path" == /usr/* || "$node_path" == /bin/* ]]; then
|
|
198
|
+
ui_info "Detected system-level Node.js: $node_path"
|
|
199
|
+
if confirm "Uninstall system-level Node.js via package manager?"; then
|
|
200
|
+
case "$PKG_MANAGER" in
|
|
201
|
+
apt)
|
|
202
|
+
run_sudo apt-get remove -y nodejs npm 2>/dev/null || true
|
|
203
|
+
run_sudo apt-get autoremove -y 2>/dev/null || true
|
|
204
|
+
run_sudo rm -f /etc/apt/sources.list.d/nodesource.list \
|
|
205
|
+
/usr/share/keyrings/nodesource.gpg 2>/dev/null || true
|
|
206
|
+
;;
|
|
207
|
+
dnf|yum)
|
|
208
|
+
run_sudo "$PKG_MANAGER" remove -y nodejs npm 2>/dev/null || true
|
|
209
|
+
;;
|
|
210
|
+
esac
|
|
211
|
+
ui_success "System-level Node.js removed"
|
|
212
|
+
fi
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
if ! command -v node &>/dev/null 2>&1; then
|
|
217
|
+
ui_success "Node.js successfully removed"
|
|
218
|
+
else
|
|
219
|
+
ui_warn "node command still found (you may need to open a new terminal)"
|
|
220
|
+
fi
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# ─── Docker containers / images / volumes cleanup ────────────────────────────
|
|
224
|
+
clean_docker_data() {
|
|
225
|
+
ui_section "Removing Docker containers, images and volumes"
|
|
226
|
+
|
|
227
|
+
if ! command -v docker &>/dev/null; then
|
|
228
|
+
ui_info "Docker is not installed, skipping cleanup"
|
|
229
|
+
return 0
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
233
|
+
ui_info "[dry-run] Would: docker stop all running containers"
|
|
234
|
+
ui_info "[dry-run] Would: docker rm -f all containers"
|
|
235
|
+
ui_info "[dry-run] Would: docker rmi -f all images"
|
|
236
|
+
ui_info "[dry-run] Would: docker volume rm all volumes"
|
|
237
|
+
ui_info "[dry-run] Would: docker network prune -f"
|
|
238
|
+
return 0
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
ui_warn "This will PERMANENTLY delete all Docker containers, images and volumes on this host."
|
|
242
|
+
if ! confirm "Remove ALL Docker containers, images and volumes?"; then
|
|
243
|
+
ui_info "Skipping Docker data cleanup"
|
|
244
|
+
return 0
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
# Stop all running containers
|
|
248
|
+
local running_containers
|
|
249
|
+
running_containers="$(docker ps -q 2>/dev/null || true)"
|
|
250
|
+
if [[ -n "$running_containers" ]]; then
|
|
251
|
+
ui_info "Stopping all running containers..."
|
|
252
|
+
# shellcheck disable=SC2086
|
|
253
|
+
docker stop $running_containers 2>/dev/null || true
|
|
254
|
+
ui_success "All containers stopped"
|
|
255
|
+
else
|
|
256
|
+
ui_info "No running containers"
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
# Remove all containers
|
|
260
|
+
local all_containers
|
|
261
|
+
all_containers="$(docker ps -aq 2>/dev/null || true)"
|
|
262
|
+
if [[ -n "$all_containers" ]]; then
|
|
263
|
+
ui_info "Removing all containers..."
|
|
264
|
+
# shellcheck disable=SC2086
|
|
265
|
+
docker rm -f $all_containers 2>/dev/null || true
|
|
266
|
+
ui_success "All containers removed"
|
|
267
|
+
else
|
|
268
|
+
ui_info "No containers to remove"
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# Remove all images
|
|
272
|
+
local all_images
|
|
273
|
+
all_images="$(docker images -q 2>/dev/null || true)"
|
|
274
|
+
if [[ -n "$all_images" ]]; then
|
|
275
|
+
ui_info "Removing all Docker images..."
|
|
276
|
+
# shellcheck disable=SC2086
|
|
277
|
+
docker rmi -f $all_images 2>/dev/null || true
|
|
278
|
+
ui_success "All images removed"
|
|
279
|
+
else
|
|
280
|
+
ui_info "No images to remove"
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# Remove all volumes
|
|
284
|
+
local all_volumes
|
|
285
|
+
all_volumes="$(docker volume ls -q 2>/dev/null || true)"
|
|
286
|
+
if [[ -n "$all_volumes" ]]; then
|
|
287
|
+
ui_info "Removing all Docker volumes..."
|
|
288
|
+
# shellcheck disable=SC2086
|
|
289
|
+
docker volume rm $all_volumes 2>/dev/null || true
|
|
290
|
+
ui_success "All volumes removed"
|
|
291
|
+
else
|
|
292
|
+
ui_info "No volumes to remove"
|
|
293
|
+
fi
|
|
294
|
+
|
|
295
|
+
# Prune custom networks
|
|
296
|
+
docker network prune -f 2>/dev/null || true
|
|
297
|
+
ui_success "Docker data cleanup complete"
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
# ─── Docker ───────────────────────────────────────────────────────────────────
|
|
301
|
+
uninstall_docker() {
|
|
302
|
+
ui_section "Removing Docker"
|
|
303
|
+
|
|
304
|
+
local _docker_via_snap=0
|
|
305
|
+
if command -v snap &>/dev/null && snap list docker &>/dev/null 2>&1; then
|
|
306
|
+
_docker_via_snap=1
|
|
307
|
+
fi
|
|
308
|
+
if ! command -v docker &>/dev/null \
|
|
309
|
+
&& ! dpkg -l 2>/dev/null | grep -q 'docker\|containerd' \
|
|
310
|
+
&& [[ $_docker_via_snap -eq 0 ]]; then
|
|
311
|
+
ui_info "Docker is not installed, skipping"
|
|
312
|
+
return 0
|
|
313
|
+
fi
|
|
314
|
+
|
|
315
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
316
|
+
ui_info "[dry-run] Would stop and disable docker.socket docker.service"
|
|
317
|
+
if [[ $_docker_via_snap -eq 1 ]]; then
|
|
318
|
+
ui_info "[dry-run] Would: snap remove docker"
|
|
319
|
+
else
|
|
320
|
+
ui_info "[dry-run] Would purge Docker packages (docker-ce, docker-ce-cli, containerd.io, etc.)"
|
|
321
|
+
ui_info "[dry-run] Would remove Docker APT/YUM repo and GPG key"
|
|
322
|
+
fi
|
|
323
|
+
ui_info "[dry-run] Would groupdel docker"
|
|
324
|
+
ui_info "[dry-run] Would remove /var/lib/docker /var/lib/containerd /etc/docker"
|
|
325
|
+
ui_info "[dry-run] Would remove ~/.docker"
|
|
326
|
+
ui_info "[dry-run] Would: systemctl daemon-reload"
|
|
327
|
+
return 0
|
|
328
|
+
fi
|
|
329
|
+
|
|
330
|
+
ui_warn "This will remove Docker packages and the docker group from this host."
|
|
331
|
+
if ! confirm "Confirm removal of Docker?"; then
|
|
332
|
+
ui_info "Cancelled"
|
|
333
|
+
return 0
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
# Stop and disable service — reset failed state first so stop succeeds
|
|
337
|
+
if command -v systemctl &>/dev/null; then
|
|
338
|
+
ui_info "Stopping Docker service..."
|
|
339
|
+
${SUDO} systemctl reset-failed docker.socket docker.service 2>/dev/null || true
|
|
340
|
+
${SUDO} systemctl stop docker docker.socket 2>/dev/null || true
|
|
341
|
+
${SUDO} systemctl disable docker docker.socket 2>/dev/null || true
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
case "$PKG_MANAGER" in
|
|
345
|
+
apt)
|
|
346
|
+
ui_info "Removing Docker packages via apt purge..."
|
|
347
|
+
local purge_pkgs=(
|
|
348
|
+
docker-ce
|
|
349
|
+
docker-ce-cli
|
|
350
|
+
containerd.io
|
|
351
|
+
docker-buildx-plugin
|
|
352
|
+
docker-compose-plugin
|
|
353
|
+
docker-ce-rootless-extras
|
|
354
|
+
docker-model-plugin
|
|
355
|
+
)
|
|
356
|
+
# Only purge packages that are actually installed
|
|
357
|
+
local installed_purge_pkgs=()
|
|
358
|
+
for pkg in "${purge_pkgs[@]}"; do
|
|
359
|
+
if dpkg -l "$pkg" 2>/dev/null | grep -q '^ii'; then
|
|
360
|
+
installed_purge_pkgs+=("$pkg")
|
|
361
|
+
fi
|
|
362
|
+
done
|
|
363
|
+
if [[ ${#installed_purge_pkgs[@]} -gt 0 ]]; then
|
|
364
|
+
ui_info "Packages to purge: ${installed_purge_pkgs[*]}"
|
|
365
|
+
wait_for_apt_lock
|
|
366
|
+
${SUDO} apt-get purge -y "${installed_purge_pkgs[@]}" || true
|
|
367
|
+
else
|
|
368
|
+
ui_warn "None of the expected Docker packages found via dpkg"
|
|
369
|
+
fi
|
|
370
|
+
wait_for_apt_lock
|
|
371
|
+
${SUDO} apt-get autoremove -y || true
|
|
372
|
+
# Remove apt repository and GPG key added by installer
|
|
373
|
+
${SUDO} rm -f /etc/apt/sources.list.d/docker.sources \
|
|
374
|
+
/etc/apt/sources.list.d/docker.list \
|
|
375
|
+
/etc/apt/keyrings/docker.asc \
|
|
376
|
+
/usr/share/keyrings/docker-archive-keyring.gpg \
|
|
377
|
+
/usr/share/keyrings/docker.gpg 2>/dev/null || true
|
|
378
|
+
;;
|
|
379
|
+
dnf|yum)
|
|
380
|
+
ui_info "Removing Docker packages via $PKG_MANAGER..."
|
|
381
|
+
local docker_pkgs
|
|
382
|
+
docker_pkgs="$(rpm -qa 2>/dev/null | grep -E 'docker|containerd' | tr '\n' ' ')"
|
|
383
|
+
if [[ -n "$docker_pkgs" ]]; then
|
|
384
|
+
ui_info "Packages to remove: ${docker_pkgs}"
|
|
385
|
+
# shellcheck disable=SC2086
|
|
386
|
+
${SUDO} "$PKG_MANAGER" remove -y $docker_pkgs || true
|
|
387
|
+
fi
|
|
388
|
+
${SUDO} rm -f /etc/yum.repos.d/docker-ce.repo 2>/dev/null || true
|
|
389
|
+
;;
|
|
390
|
+
esac
|
|
391
|
+
|
|
392
|
+
# Remove Docker installed via snap
|
|
393
|
+
if [[ $_docker_via_snap -eq 1 ]]; then
|
|
394
|
+
ui_info "Removing Docker snap package..."
|
|
395
|
+
${SUDO} snap remove docker 2>/dev/null || true
|
|
396
|
+
if ! snap list docker &>/dev/null 2>&1; then
|
|
397
|
+
ui_success "Docker snap package removed"
|
|
398
|
+
else
|
|
399
|
+
ui_warn "snap remove docker failed — try manually: sudo snap remove docker"
|
|
400
|
+
fi
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
# Verify packages actually removed — try a dynamic cleanup pass for any stragglers
|
|
404
|
+
local remaining_pkgs
|
|
405
|
+
remaining_pkgs="$(dpkg -l 2>/dev/null | awk '/^ii/ && /docker|containerd/ {print $2}' | tr '\n' ' ' || true)"
|
|
406
|
+
if [[ -n "$remaining_pkgs" ]]; then
|
|
407
|
+
ui_warn "Packages still installed after first pass: ${remaining_pkgs}"
|
|
408
|
+
ui_info "Attempting dynamic cleanup..."
|
|
409
|
+
wait_for_apt_lock
|
|
410
|
+
# shellcheck disable=SC2086
|
|
411
|
+
${SUDO} apt-get purge -y $remaining_pkgs 2>/dev/null || true
|
|
412
|
+
wait_for_apt_lock
|
|
413
|
+
${SUDO} apt-get autoremove -y 2>/dev/null || true
|
|
414
|
+
# Re-check
|
|
415
|
+
remaining_pkgs="$(dpkg -l 2>/dev/null | awk '/^ii/ && /docker|containerd/ {print $2}' | tr '\n' ' ' || true)"
|
|
416
|
+
if [[ -n "$remaining_pkgs" ]]; then
|
|
417
|
+
ui_warn "Packages still installed after removal: ${remaining_pkgs}"
|
|
418
|
+
ui_warn "Try manually: sudo apt-get purge -y ${remaining_pkgs}"
|
|
419
|
+
fi
|
|
420
|
+
fi
|
|
421
|
+
|
|
422
|
+
if getent group docker &>/dev/null 2>&1; then
|
|
423
|
+
${SUDO} groupdel docker 2>/dev/null || true
|
|
424
|
+
ui_success "docker group removed"
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
# Remove Docker daemon data and configuration directories
|
|
428
|
+
for dir in /var/lib/docker /var/lib/containerd /etc/docker; do
|
|
429
|
+
if [[ -d "$dir" ]]; then
|
|
430
|
+
local dir_size
|
|
431
|
+
dir_size="$(du -sh "$dir" 2>/dev/null | cut -f1 || echo '?')"
|
|
432
|
+
if confirm "Delete Docker directory ${dir} (${dir_size})?"; then
|
|
433
|
+
${SUDO} rm -rf "$dir" 2>/dev/null || true
|
|
434
|
+
if [[ ! -d "$dir" ]]; then
|
|
435
|
+
ui_success "Removed: ${dir}"
|
|
436
|
+
else
|
|
437
|
+
ui_warn "Could not fully remove: ${dir}"
|
|
438
|
+
fi
|
|
439
|
+
else
|
|
440
|
+
ui_info "Kept: ${dir}"
|
|
441
|
+
fi
|
|
442
|
+
fi
|
|
443
|
+
done
|
|
444
|
+
|
|
445
|
+
# Remove user Docker config directory (~/.docker contains credentials and config)
|
|
446
|
+
if [[ -d "${HOME}/.docker" ]]; then
|
|
447
|
+
if confirm "Delete user Docker config directory (~/.docker)?"; then
|
|
448
|
+
rm -rf "${HOME}/.docker" 2>/dev/null || true
|
|
449
|
+
ui_success "Removed: ${HOME}/.docker"
|
|
450
|
+
else
|
|
451
|
+
ui_info "Kept: ${HOME}/.docker"
|
|
452
|
+
fi
|
|
453
|
+
fi
|
|
454
|
+
|
|
455
|
+
# Reload systemd unit database after removing service units
|
|
456
|
+
if command -v systemctl &>/dev/null; then
|
|
457
|
+
${SUDO} systemctl daemon-reload 2>/dev/null || true
|
|
458
|
+
fi
|
|
459
|
+
|
|
460
|
+
# Final verification — flush shell command cache before checking
|
|
461
|
+
hash -r 2>/dev/null || true
|
|
462
|
+
local docker_path
|
|
463
|
+
docker_path="$(command -v docker 2>/dev/null || true)"
|
|
464
|
+
if [[ -n "$docker_path" && -f "$docker_path" ]]; then
|
|
465
|
+
ui_error "Docker binary still present at: ${docker_path}"
|
|
466
|
+
[[ -n "$remaining_pkgs" ]] && ui_error "Packages not removed: ${remaining_pkgs}"
|
|
467
|
+
return 1
|
|
468
|
+
fi
|
|
469
|
+
ui_success "Docker removed successfully"
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
# ─── Nomad ────────────────────────────────────────────────────────────────────
|
|
473
|
+
uninstall_nomad() {
|
|
474
|
+
ui_section "Removing Nomad"
|
|
475
|
+
|
|
476
|
+
local local_bin="${HOME}/.jishushell/bin/nomad"
|
|
477
|
+
local system_nomad
|
|
478
|
+
system_nomad="$(command -v nomad 2>/dev/null || true)"
|
|
479
|
+
# Ignore if system PATH resolves to our local bin
|
|
480
|
+
[[ "$system_nomad" == "$local_bin" ]] && system_nomad=""
|
|
481
|
+
|
|
482
|
+
local found_local=0
|
|
483
|
+
local found_system=0
|
|
484
|
+
[[ -f "$local_bin" ]] && found_local=1
|
|
485
|
+
[[ -n "$system_nomad" ]] && found_system=1
|
|
486
|
+
|
|
487
|
+
if [[ $found_local -eq 0 && $found_system -eq 0 ]]; then
|
|
488
|
+
ui_info "Nomad is not installed, skipping"
|
|
489
|
+
return 0
|
|
490
|
+
fi
|
|
491
|
+
|
|
492
|
+
if [[ $found_local -eq 1 ]]; then
|
|
493
|
+
local local_ver
|
|
494
|
+
local_ver="$("$local_bin" version 2>/dev/null | head -n1 || echo 'unknown')"
|
|
495
|
+
ui_info "Local Nomad: ${local_ver} → ${local_bin}"
|
|
496
|
+
fi
|
|
497
|
+
if [[ $found_system -eq 1 ]]; then
|
|
498
|
+
local sys_ver
|
|
499
|
+
sys_ver="$(nomad version 2>/dev/null | head -n1 || echo 'unknown')"
|
|
500
|
+
ui_info "System Nomad: ${sys_ver} → ${system_nomad}"
|
|
501
|
+
fi
|
|
502
|
+
|
|
503
|
+
if ! confirm "Confirm removal of Nomad?"; then
|
|
504
|
+
ui_info "Cancelled"
|
|
505
|
+
return 0
|
|
506
|
+
fi
|
|
507
|
+
|
|
508
|
+
# Stop systemd service if running
|
|
509
|
+
if command -v systemctl &>/dev/null; then
|
|
510
|
+
if systemctl is-active --quiet nomad 2>/dev/null; then
|
|
511
|
+
ui_info "Stopping Nomad service..."
|
|
512
|
+
run_sudo systemctl stop nomad 2>/dev/null || true
|
|
513
|
+
fi
|
|
514
|
+
if systemctl is-enabled --quiet nomad 2>/dev/null; then
|
|
515
|
+
ui_info "Disabling Nomad on startup..."
|
|
516
|
+
run_sudo systemctl disable nomad 2>/dev/null || true
|
|
517
|
+
fi
|
|
518
|
+
fi
|
|
519
|
+
|
|
520
|
+
# Remove local binary (no sudo needed)
|
|
521
|
+
if [[ $found_local -eq 1 ]]; then
|
|
522
|
+
ui_info "Removing local Nomad binary: ${local_bin}"
|
|
523
|
+
run_cmd rm -f "$local_bin"
|
|
524
|
+
ui_success "Local Nomad binary removed"
|
|
525
|
+
fi
|
|
526
|
+
|
|
527
|
+
# Remove PATH entry from shell configs written by jishu-install.sh
|
|
528
|
+
local marker="# jishushell-bin-path"
|
|
529
|
+
local shell_configs=("$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.profile" "$HOME/.zshrc")
|
|
530
|
+
for cfg in "${shell_configs[@]}"; do
|
|
531
|
+
if [[ -f "$cfg" ]] && grep -qF "$marker" "$cfg" 2>/dev/null; then
|
|
532
|
+
ui_info "Cleaning JishuShell PATH from ${cfg}..."
|
|
533
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
534
|
+
ui_info "[dry-run] Would remove jishushell-bin-path lines from ${cfg}"
|
|
535
|
+
else
|
|
536
|
+
cp "$cfg" "${cfg}.bak-jishu-uninstall"
|
|
537
|
+
sed -i "/${marker//\//\\/}/d; /jishushell.*bin.*PATH/d; /\.jishushell\/bin/d" "$cfg"
|
|
538
|
+
ui_success "Cleaned ${cfg} (backup: ${cfg}.bak-jishu-uninstall)"
|
|
539
|
+
fi
|
|
540
|
+
fi
|
|
541
|
+
done
|
|
542
|
+
|
|
543
|
+
# Remove system binary if found via package manager
|
|
544
|
+
if [[ $found_system -eq 1 ]]; then
|
|
545
|
+
local removed_via_pkg=0
|
|
546
|
+
case "$PKG_MANAGER" in
|
|
547
|
+
apt)
|
|
548
|
+
if dpkg -l nomad 2>/dev/null | grep -q '^ii'; then
|
|
549
|
+
ui_info "Removing Nomad via apt..."
|
|
550
|
+
run_sudo apt-get remove -y nomad 2>/dev/null || true
|
|
551
|
+
run_sudo apt-get autoremove -y 2>/dev/null || true
|
|
552
|
+
removed_via_pkg=1
|
|
553
|
+
fi
|
|
554
|
+
if [[ $removed_via_pkg -eq 1 ]]; then
|
|
555
|
+
local hashi_sources=(/etc/apt/sources.list.d/hashicorp.list)
|
|
556
|
+
for src in "${hashi_sources[@]}"; do
|
|
557
|
+
if [[ -f "$src" ]]; then
|
|
558
|
+
if confirm "Delete HashiCorp APT repository config ($src)?"; then
|
|
559
|
+
run_sudo rm -f "$src" \
|
|
560
|
+
/usr/share/keyrings/hashicorp-archive-keyring.gpg 2>/dev/null || true
|
|
561
|
+
fi
|
|
562
|
+
fi
|
|
563
|
+
done
|
|
564
|
+
fi
|
|
565
|
+
;;
|
|
566
|
+
dnf|yum)
|
|
567
|
+
if rpm -q nomad &>/dev/null 2>&1; then
|
|
568
|
+
ui_info "Removing Nomad via $PKG_MANAGER..."
|
|
569
|
+
run_sudo "$PKG_MANAGER" remove -y nomad 2>/dev/null || true
|
|
570
|
+
removed_via_pkg=1
|
|
571
|
+
fi
|
|
572
|
+
if [[ $removed_via_pkg -eq 1 ]] && [[ -f /etc/yum.repos.d/hashicorp.repo ]]; then
|
|
573
|
+
if confirm "Delete HashiCorp YUM repository config (/etc/yum.repos.d/hashicorp.repo)?"; then
|
|
574
|
+
run_sudo rm -f /etc/yum.repos.d/hashicorp.repo 2>/dev/null || true
|
|
575
|
+
fi
|
|
576
|
+
fi
|
|
577
|
+
;;
|
|
578
|
+
esac
|
|
579
|
+
|
|
580
|
+
# Remove binary directly if still present and not the local one
|
|
581
|
+
local remaining
|
|
582
|
+
remaining="$(command -v nomad 2>/dev/null || true)"
|
|
583
|
+
if [[ -n "$remaining" && "$remaining" != "$local_bin" ]]; then
|
|
584
|
+
ui_info "Removing remaining system binary: ${remaining}"
|
|
585
|
+
run_sudo rm -f "$remaining" 2>/dev/null || true
|
|
586
|
+
fi
|
|
587
|
+
fi
|
|
588
|
+
|
|
589
|
+
# Remove systemd service files
|
|
590
|
+
run_sudo rm -f /etc/systemd/system/nomad.service \
|
|
591
|
+
/usr/lib/systemd/system/nomad.service 2>/dev/null || true
|
|
592
|
+
|
|
593
|
+
# Nomad JishuShell config dir
|
|
594
|
+
# NOTE: Nomad runs as root and creates root-owned files under data/,
|
|
595
|
+
# so sudo is required to remove the entire tree.
|
|
596
|
+
local jishu_nomad_dir="${HOME}/.jishushell/nomad"
|
|
597
|
+
if [[ -d "$jishu_nomad_dir" ]]; then
|
|
598
|
+
if confirm "Delete Nomad config directory (${jishu_nomad_dir})?"; then
|
|
599
|
+
run_sudo rm -rf "$jishu_nomad_dir"
|
|
600
|
+
ui_success "Nomad config directory removed"
|
|
601
|
+
fi
|
|
602
|
+
fi
|
|
603
|
+
|
|
604
|
+
# System Nomad data dirs (optional)
|
|
605
|
+
if confirm "Delete Nomad system data directories (/etc/nomad.d /var/lib/nomad /var/log/nomad)?"; then
|
|
606
|
+
run_sudo rm -rf /etc/nomad.d /var/lib/nomad /var/log/nomad 2>/dev/null || true
|
|
607
|
+
ui_success "Nomad system data directories removed"
|
|
608
|
+
fi
|
|
609
|
+
|
|
610
|
+
if command -v systemctl &>/dev/null; then
|
|
611
|
+
run_sudo systemctl daemon-reload 2>/dev/null || true
|
|
612
|
+
fi
|
|
613
|
+
|
|
614
|
+
# Final verification
|
|
615
|
+
local nomad_ok=1
|
|
616
|
+
if [[ -f "${HOME}/.jishushell/bin/nomad" ]]; then
|
|
617
|
+
ui_warn "Local Nomad binary still present: ${HOME}/.jishushell/bin/nomad"
|
|
618
|
+
nomad_ok=0
|
|
619
|
+
fi
|
|
620
|
+
local nomad_remaining
|
|
621
|
+
nomad_remaining="$(command -v nomad 2>/dev/null || true)"
|
|
622
|
+
if [[ -n "$nomad_remaining" ]]; then
|
|
623
|
+
ui_warn "Nomad still found in PATH: ${nomad_remaining}"
|
|
624
|
+
nomad_ok=0
|
|
625
|
+
fi
|
|
626
|
+
if [[ $nomad_ok -eq 1 ]]; then
|
|
627
|
+
ui_success "Nomad removed successfully"
|
|
628
|
+
else
|
|
629
|
+
ui_error "Nomad removal incomplete"
|
|
630
|
+
return 1
|
|
631
|
+
fi
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
# ─── OpenClaw ─────────────────────────────────────────────────────────────────
|
|
635
|
+
# Removes: npm package dir + Docker images matching openclaw:* or jishushell-base:*
|
|
636
|
+
uninstall_openclaw() {
|
|
637
|
+
ui_section "Removing OpenClaw"
|
|
638
|
+
|
|
639
|
+
local pkg_dir="${HOME}/.jishushell/packages/openclaw"
|
|
640
|
+
|
|
641
|
+
# ── Remove Docker image(s) ────────────────────────────────────
|
|
642
|
+
if command -v docker &>/dev/null; then
|
|
643
|
+
# Find all local openclaw:* and jishushell-base:* images
|
|
644
|
+
local image_tags
|
|
645
|
+
image_tags="$(docker images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -E '^openclaw:|^jishushell-base:' || true)"
|
|
646
|
+
|
|
647
|
+
if [[ -n "$image_tags" ]]; then
|
|
648
|
+
ui_info "Found OpenClaw/base Docker image(s):"
|
|
649
|
+
echo "$image_tags" | while read -r img; do
|
|
650
|
+
ui_info " $img"
|
|
651
|
+
done
|
|
652
|
+
if confirm "Remove the above OpenClaw Docker image(s)?"; then
|
|
653
|
+
echo "$image_tags" | while read -r img; do
|
|
654
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
655
|
+
ui_info "[dry-run] Would: docker rmi -f ${img}"
|
|
656
|
+
else
|
|
657
|
+
docker rmi -f "$img" 2>/dev/null || ${SUDO} docker rmi -f "$img" 2>/dev/null || true
|
|
658
|
+
if ! docker image inspect "$img" &>/dev/null 2>&1; then
|
|
659
|
+
ui_success "Removed: ${img}"
|
|
660
|
+
else
|
|
661
|
+
ui_warn "Could not remove: ${img}"
|
|
662
|
+
fi
|
|
663
|
+
fi
|
|
664
|
+
done
|
|
665
|
+
else
|
|
666
|
+
ui_info "Docker images kept"
|
|
667
|
+
fi
|
|
668
|
+
else
|
|
669
|
+
ui_info "No local openclaw:* or jishushell-base:* Docker images found"
|
|
670
|
+
fi
|
|
671
|
+
else
|
|
672
|
+
ui_info "Docker not installed — skipping image removal"
|
|
673
|
+
fi
|
|
674
|
+
|
|
675
|
+
# ── Remove npm package directory ──────────────────────────────
|
|
676
|
+
if [[ -d "$pkg_dir" ]]; then
|
|
677
|
+
local size
|
|
678
|
+
size="$(du -sh "$pkg_dir" 2>/dev/null | cut -f1 || echo "?")"
|
|
679
|
+
ui_info "OpenClaw npm package directory: ${pkg_dir} (${size})"
|
|
680
|
+
if confirm "Delete OpenClaw npm package directory (${pkg_dir})?"; then
|
|
681
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
682
|
+
ui_info "[dry-run] Would: rm -rf ${pkg_dir}"
|
|
683
|
+
else
|
|
684
|
+
rm -rf "$pkg_dir"
|
|
685
|
+
ui_success "OpenClaw npm package directory removed"
|
|
686
|
+
fi
|
|
687
|
+
else
|
|
688
|
+
ui_info "Kept ${pkg_dir}"
|
|
689
|
+
fi
|
|
690
|
+
else
|
|
691
|
+
ui_info "OpenClaw npm package directory not found (${pkg_dir})"
|
|
692
|
+
fi
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
# ─── Summary ──────────────────────────────────────────────────────────────────
|
|
696
|
+
show_plan() {
|
|
697
|
+
echo ""
|
|
698
|
+
echo -e "${ACCENT}${BOLD}Uninstall Plan${NC}"
|
|
699
|
+
echo -e "${MUTED}────────────────────────────────${NC}"
|
|
700
|
+
echo -e " ${WARN}·${NC} Stop all running services"
|
|
701
|
+
echo -e " ${WARN}·${NC} Remove services from auto-start (launchd / systemd)"
|
|
702
|
+
echo -e " ${WARN}·${NC} Uninstall jishushell npm package"
|
|
703
|
+
[[ $DO_NODE -eq 1 ]] && echo -e " ${WARN}·${NC} Node.js / nvm"
|
|
704
|
+
[[ $DO_DOCKER_CLEAN -eq 1 ]] && echo -e " ${WARN}·${NC} Remove all Docker containers, images and volumes"
|
|
705
|
+
[[ $DO_DOCKER -eq 1 ]] && echo -e " ${WARN}·${NC} Docker packages, docker group, /var/lib/docker, /var/lib/containerd, /etc/docker, ~/.docker"
|
|
706
|
+
[[ $DO_NOMAD -eq 1 ]] && echo -e " ${WARN}·${NC} Nomad binary and config"
|
|
707
|
+
[[ $DO_OPENCLAW -eq 1 ]] && echo -e " ${WARN}·${NC} OpenClaw npm package + Docker image(s) (openclaw:*, jishushell-base:*)"
|
|
708
|
+
if [[ $DO_DATA -eq 1 ]]; then
|
|
709
|
+
echo -e " ${WARN}·${NC} Data directory (~/.jishushell) — WILL BE DELETED"
|
|
710
|
+
else
|
|
711
|
+
echo -e " ${MUTED}·${NC} Data directory (~/.jishushell) — will ask, default: keep"
|
|
712
|
+
fi
|
|
713
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
714
|
+
echo ""
|
|
715
|
+
echo -e "${WARN} Dry-run mode: no changes will be made${NC}"
|
|
716
|
+
fi
|
|
717
|
+
echo ""
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
721
|
+
# Main
|
|
722
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
723
|
+
main() {
|
|
724
|
+
parse_args "$@"
|
|
725
|
+
|
|
726
|
+
echo -e "${ACCENT}${BOLD}"
|
|
727
|
+
echo " ╔═══════════════════════════════════╗"
|
|
728
|
+
echo " ║ JishuShell Uninstaller ║"
|
|
729
|
+
echo " ╚═══════════════════════════════════╝"
|
|
730
|
+
echo -e "${NC}"
|
|
731
|
+
|
|
732
|
+
detect_os
|
|
733
|
+
check_sudo
|
|
734
|
+
|
|
735
|
+
show_plan
|
|
736
|
+
|
|
737
|
+
if ! confirm "This will stop all JishuShell services and remove them from auto-start. Proceed?"; then
|
|
738
|
+
ui_info "Cancelled"
|
|
739
|
+
exit 0
|
|
740
|
+
fi
|
|
741
|
+
|
|
742
|
+
local uninstall_errors=0
|
|
743
|
+
|
|
744
|
+
stop_services || uninstall_errors=1
|
|
745
|
+
|
|
746
|
+
[[ $DO_NODE -eq 1 ]] && { uninstall_node || uninstall_errors=1; }
|
|
747
|
+
[[ $DO_OPENCLAW -eq 1 ]] && { uninstall_openclaw || uninstall_errors=1; }
|
|
748
|
+
[[ $DO_NOMAD -eq 1 ]] && { uninstall_nomad || uninstall_errors=1; }
|
|
749
|
+
[[ $DO_DOCKER_CLEAN -eq 1 ]] && { clean_docker_data || uninstall_errors=1; }
|
|
750
|
+
[[ $DO_DOCKER -eq 1 ]] && { uninstall_docker || uninstall_errors=1; }
|
|
751
|
+
|
|
752
|
+
local jishu_home="${HOME}/.jishushell"
|
|
753
|
+
if [[ -d "$jishu_home" ]]; then
|
|
754
|
+
local size
|
|
755
|
+
size="$(du -sh "$jishu_home" 2>/dev/null | cut -f1 || echo "?")"
|
|
756
|
+
echo ""
|
|
757
|
+
ui_info "Data directory: ${jishu_home} (${size})"
|
|
758
|
+
# Auto-delete when --data flag is set (non-interactive, e.g. postuninstall)
|
|
759
|
+
local _delete_data=0
|
|
760
|
+
if [[ $DO_DATA -eq 1 ]]; then
|
|
761
|
+
_delete_data=1
|
|
762
|
+
else
|
|
763
|
+
ui_info "This contains your instances, config, and Nomad data."
|
|
764
|
+
if confirm "Delete data directory? (default: keep)"; then
|
|
765
|
+
_delete_data=1
|
|
766
|
+
fi
|
|
767
|
+
fi
|
|
768
|
+
if [[ $_delete_data -eq 1 ]]; then
|
|
769
|
+
if [[ "$DRY_RUN" == "1" ]]; then
|
|
770
|
+
ui_info "[dry-run] Would: docker rm any containers bind-mounted from ${jishu_home}"
|
|
771
|
+
ui_info "[dry-run] Would: ${SUDO} rm -rf ${jishu_home}"
|
|
772
|
+
else
|
|
773
|
+
# On macOS, Docker Desktop keeps VirtioFS shares open for containers that are
|
|
774
|
+
# stopped but not removed (docker rm). Those open shares prevent rm -rf from
|
|
775
|
+
# deleting the bind-mounted directories. Force-remove any such containers first.
|
|
776
|
+
if command -v docker &>/dev/null; then
|
|
777
|
+
local _containers_to_rm
|
|
778
|
+
_containers_to_rm="$(docker ps -a --format '{{.ID}}' 2>/dev/null | xargs -I{} sh -c \
|
|
779
|
+
'docker inspect {} --format "{{.ID}} {{range .Mounts}}{{.Source}} {{end}}" 2>/dev/null' \
|
|
780
|
+
| grep -F "$jishu_home" | awk '{print $1}' || true)"
|
|
781
|
+
if [[ -n "$_containers_to_rm" ]]; then
|
|
782
|
+
ui_info "Removing Docker containers with bind-mounts from ${jishu_home}..."
|
|
783
|
+
echo "$_containers_to_rm" | xargs docker rm -f 2>/dev/null || true
|
|
784
|
+
fi
|
|
785
|
+
fi
|
|
786
|
+
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
787
|
+
${SUDO} chflags -R nouchg,noschg "$jishu_home" 2>/dev/null || true
|
|
788
|
+
fi
|
|
789
|
+
${SUDO} rm -rf "$jishu_home" || true
|
|
790
|
+
if [[ ! -d "$jishu_home" ]]; then
|
|
791
|
+
ui_success "Data directory removed"
|
|
792
|
+
else
|
|
793
|
+
ui_warn "Could not remove ${jishu_home}"
|
|
794
|
+
uninstall_errors=1
|
|
795
|
+
fi
|
|
796
|
+
fi
|
|
797
|
+
else
|
|
798
|
+
ui_info "Data directory kept: ${jishu_home}"
|
|
799
|
+
fi
|
|
800
|
+
fi
|
|
801
|
+
|
|
802
|
+
echo ""
|
|
803
|
+
if [[ $uninstall_errors -eq 0 ]]; then
|
|
804
|
+
echo -e "${SUCCESS}${BOLD}Done.${NC}"
|
|
805
|
+
else
|
|
806
|
+
echo -e "${WARN}${BOLD}Some steps could not be completed — review the output above.${NC}"
|
|
807
|
+
fi
|
|
808
|
+
echo ""
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
main "$@"
|