jishushell 0.4.2 → 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.
Files changed (83) hide show
  1. package/Dockerfile.openclaw-slim +58 -0
  2. package/INSTALL-NOTICE +47 -0
  3. package/dist/auth.js +3 -3
  4. package/dist/auth.js.map +1 -1
  5. package/dist/cli.js +517 -1
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config.d.ts +21 -4
  8. package/dist/config.js +88 -54
  9. package/dist/config.js.map +1 -1
  10. package/dist/control.js +5 -5
  11. package/dist/control.js.map +1 -1
  12. package/dist/doctor.js +47 -14
  13. package/dist/doctor.js.map +1 -1
  14. package/dist/install.d.ts +1 -1
  15. package/dist/install.js +15 -29
  16. package/dist/install.js.map +1 -1
  17. package/dist/routes/backup.d.ts +2 -0
  18. package/dist/routes/backup.js +370 -0
  19. package/dist/routes/backup.js.map +1 -0
  20. package/dist/routes/instances.d.ts +1 -0
  21. package/dist/routes/instances.js +51 -11
  22. package/dist/routes/instances.js.map +1 -1
  23. package/dist/routes/setup.js +3 -5
  24. package/dist/routes/setup.js.map +1 -1
  25. package/dist/server.js +29 -1
  26. package/dist/server.js.map +1 -1
  27. package/dist/services/backup-manager.d.ts +253 -0
  28. package/dist/services/backup-manager.js +2014 -0
  29. package/dist/services/backup-manager.js.map +1 -0
  30. package/dist/services/backup-verify.d.ts +26 -0
  31. package/dist/services/backup-verify.js +240 -0
  32. package/dist/services/backup-verify.js.map +1 -0
  33. package/dist/services/instance-manager.d.ts +24 -4
  34. package/dist/services/instance-manager.js +218 -49
  35. package/dist/services/instance-manager.js.map +1 -1
  36. package/dist/services/nomad-manager.js +72 -131
  37. package/dist/services/nomad-manager.js.map +1 -1
  38. package/dist/services/process-manager.js +4 -3
  39. package/dist/services/process-manager.js.map +1 -1
  40. package/dist/services/setup-manager.d.ts +4 -2
  41. package/dist/services/setup-manager.js +268 -129
  42. package/dist/services/setup-manager.js.map +1 -1
  43. package/dist/services/telemetry/activation.js +10 -7
  44. package/dist/services/telemetry/activation.js.map +1 -1
  45. package/dist/services/telemetry/client.js +7 -18
  46. package/dist/services/telemetry/client.js.map +1 -1
  47. package/dist/services/telemetry/heartbeat.js +12 -6
  48. package/dist/services/telemetry/heartbeat.js.map +1 -1
  49. package/dist/utils/fs.d.ts +85 -0
  50. package/dist/utils/fs.js +111 -0
  51. package/dist/utils/fs.js.map +1 -0
  52. package/dist/utils/safe-json.d.ts +2 -0
  53. package/dist/utils/safe-json.js +22 -16
  54. package/dist/utils/safe-json.js.map +1 -1
  55. package/install/jishu-install-china.sh +3092 -0
  56. package/install/jishu-install.sh +310 -108
  57. package/install/jishu-uninstall.sh +276 -391
  58. package/install/post-install.sh +23 -0
  59. package/openclaw-entry.sh +15 -0
  60. package/package.json +7 -4
  61. package/public/assets/Dashboard-DhsrzJ4F.js +1 -0
  62. package/public/assets/{InitPassword-CkehIkJG.js → InitPassword-BjubiVdd.js} +1 -1
  63. package/public/assets/InstanceDetail-DMcywsof.js +17 -0
  64. package/public/assets/{Login-RkjzTNWg.js → Login-CUoEZOWR.js} +1 -1
  65. package/public/assets/NewInstance-Bk0G4EiJ.js +1 -0
  66. package/public/assets/Settings-D5tHL_h5.js +1 -0
  67. package/public/assets/Setup-4t6E3Rut.js +1 -0
  68. package/public/assets/index-BJ47MWpF.css +1 -0
  69. package/public/assets/index-DbX85irc.js +16 -0
  70. package/public/assets/logo-black-theme-DywLAtFy.png +0 -0
  71. package/public/assets/logo-white-theme-DXffFAWw.png +0 -0
  72. package/public/assets/{usePolling-CqQ8hrNc.js → usePolling-CK0DfI4h.js} +1 -1
  73. package/public/assets/{vendor-i18n-Bvxxh8Di.js → vendor-i18n-CfW0RvgE.js} +1 -1
  74. package/public/assets/vendor-react-B1-3Yrt-.js +59 -0
  75. package/public/index.html +4 -4
  76. package/public/assets/Dashboard-CAOQDYDR.js +0 -1
  77. package/public/assets/InstanceDetail-CzW2S95J.js +0 -14
  78. package/public/assets/NewInstance-DdbErdjA.js +0 -1
  79. package/public/assets/Settings-BUD7zwv9.js +0 -1
  80. package/public/assets/Setup-RRTIERGG.js +0 -1
  81. package/public/assets/index-77Ug7feY.css +0 -1
  82. package/public/assets/index-DfRnVUQR.js +0 -16
  83. package/public/assets/vendor-react-DONn7uBV.js +0 -59
@@ -5,12 +5,8 @@ JISHU_SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
5
  # shellcheck source=jishu-install.sh
6
6
  source "${JISHU_SCRIPT_DIR}/jishu-install.sh"
7
7
 
8
- DO_NODE=0
9
8
  DO_DOCKER=0
10
- DO_DOCKER_CLEAN=0
11
9
  DO_NOMAD=0
12
- DO_OPENCLAW=0
13
- DO_DATA=0
14
10
  AUTO_YES=0
15
11
 
16
12
  # ─── Argument parsing ─────────────────────────────────────────────────────────
@@ -18,16 +14,16 @@ usage() {
18
14
  cat <<EOF
19
15
  Usage: bash jishu-uninstall.sh [options]
20
16
 
21
- Run without options to stop all services and remove them from auto-start.
17
+ Run without options to stop all JishuShell services, clean up runtime
18
+ artifacts, and optionally delete the data directory (~/.jishushell).
19
+
20
+ System-installed tools (colima, docker, nomad, Node.js) are never removed
21
+ unless you explicitly pass --docker or --nomad.
22
22
 
23
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)
24
+ --docker Also uninstall Docker/Colima system packages (brew/apt/dnf)
25
+ --nomad Also uninstall Nomad system package (brew/apt/dnf)
26
+ --all Full uninstall: default cleanup + --docker + --nomad + --yes
31
27
  --dry-run Print the removal plan only, do not execute anything
32
28
  --yes, -y Skip all confirmation prompts (auto-yes)
33
29
  --help, -h Show this help message
@@ -38,13 +34,9 @@ EOF
38
34
  parse_args() {
39
35
  while [[ $# -gt 0 ]]; do
40
36
  case "$1" in
41
- --node) DO_NODE=1 ;;
42
37
  --docker) DO_DOCKER=1 ;;
43
- --docker-clean) DO_DOCKER_CLEAN=1; DO_DOCKER=1 ;;
44
38
  --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 ;;
39
+ --all) DO_DOCKER=1; DO_NOMAD=1; AUTO_YES=1 ;;
48
40
  --dry-run) DRY_RUN=1 ;;
49
41
  --yes|-y) AUTO_YES=1 ;;
50
42
  --help|-h) usage; exit 0 ;;
@@ -54,6 +46,42 @@ parse_args() {
54
46
  done
55
47
  }
56
48
 
49
+ # ─── Helper: kill processes matching our private profile ──────────────────────
50
+ # Usage: _kill_jishu_procs "colima" "jishushell"
51
+ _kill_jishu_procs() {
52
+ local pattern="$1"
53
+ local profile_hint="${2:-${_COLIMA_PROFILE}}"
54
+ local pids
55
+ pids="$(pgrep -f "${pattern}" 2>/dev/null || true)"
56
+ [[ -z "$pids" ]] && return 0
57
+ local killed=0
58
+ local pid
59
+ for pid in $pids; do
60
+ # Only kill processes related to our profile — not system-wide colima/docker
61
+ local cmdline
62
+ cmdline="$(ps -p "$pid" -o args= 2>/dev/null || true)"
63
+ if [[ "$cmdline" == *"${profile_hint}"* || "$cmdline" == *"${_COLIMA_HOME}"* ]]; then
64
+ kill "$pid" 2>/dev/null || true
65
+ ((killed++)) || true
66
+ fi
67
+ done
68
+ if [[ $killed -gt 0 ]]; then
69
+ ui_info "Sent SIGTERM to ${killed} ${pattern} process(es)"
70
+ # Wait briefly for graceful shutdown
71
+ sleep 2
72
+ # Force-kill any survivors
73
+ for pid in $pids; do
74
+ if kill -0 "$pid" 2>/dev/null; then
75
+ local cmdline
76
+ cmdline="$(ps -p "$pid" -o args= 2>/dev/null || true)"
77
+ if [[ "$cmdline" == *"${profile_hint}"* || "$cmdline" == *"${_COLIMA_HOME}"* ]]; then
78
+ kill -9 "$pid" 2>/dev/null || true
79
+ fi
80
+ fi
81
+ done
82
+ fi
83
+ }
84
+
57
85
  # ─── Stop & deregister auto-start services ───────────────────────────────────
58
86
  stop_services() {
59
87
  ui_section "Stopping services and removing auto-start"
@@ -61,6 +89,12 @@ stop_services() {
61
89
  if [[ "$DRY_RUN" == "1" ]]; then
62
90
  ui_info "[dry-run] Would stop and deregister: com.jishushell.panel, com.jishushell.nomad"
63
91
  ui_info "[dry-run] Would: npm uninstall -g jishushell"
92
+ if [[ "$OS" == "macos" ]]; then
93
+ ui_info "[dry-run] Would: kill stale colima/limactl/ssh processes for profile ${_COLIMA_PROFILE}"
94
+ ui_info "[dry-run] Would: COLIMA_HOME=${_COLIMA_HOME} colima stop ${_COLIMA_PROFILE}"
95
+ ui_info "[dry-run] Would: COLIMA_HOME=${_COLIMA_HOME} colima delete ${_COLIMA_PROFILE} --force"
96
+ ui_info "[dry-run] Would: docker context rm colima-${_COLIMA_PROFILE}"
97
+ fi
64
98
  return 0
65
99
  fi
66
100
 
@@ -117,187 +151,193 @@ stop_services() {
117
151
  ui_success "jishushell npm package removed"
118
152
  fi
119
153
 
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
154
+ # Kill any nomad agent process started by jishushell (match our config path)
155
+ local _nomad_pids
156
+ _nomad_pids="$(pgrep -f "nomad agent" 2>/dev/null || true)"
157
+ if [[ -n "$_nomad_pids" ]]; then
158
+ local _killed_nomad=0
159
+ for _pid in $_nomad_pids; do
160
+ local _cmd
161
+ _cmd="$(ps -p "$_pid" -o args= 2>/dev/null || true)"
162
+ # Only kill nomad agents that reference our config directory
163
+ if [[ "$_cmd" == *"${JISHUSHELL_HOME:-${HOME}/.jishushell}"* ]]; then
164
+ kill "$_pid" 2>/dev/null || true
165
+ ((_killed_nomad++)) || true
166
+ fi
128
167
  done
129
- if pgrep -f "nomad agent" &>/dev/null 2>&1; then
130
- pkill -KILL -f "nomad agent" 2>/dev/null || true
168
+ if [[ $_killed_nomad -gt 0 ]]; then
169
+ ui_info "Stopped ${_killed_nomad} JishuShell Nomad agent process(es)"
170
+ sleep 2
171
+ # Force-kill survivors
172
+ for _pid in $_nomad_pids; do
173
+ if kill -0 "$_pid" 2>/dev/null; then
174
+ local _cmd
175
+ _cmd="$(ps -p "$_pid" -o args= 2>/dev/null || true)"
176
+ if [[ "$_cmd" == *"${JISHUSHELL_HOME:-${HOME}/.jishushell}"* ]]; then
177
+ kill -9 "$_pid" 2>/dev/null || true
178
+ fi
179
+ fi
180
+ done
131
181
  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
182
  fi
140
- }
141
183
 
142
- # ─── Node.js via nvm ──────────────────────────────────────────────────────────
143
- uninstall_node() {
144
- ui_section "Removing Node.js / nvm"
184
+ # ── macOS: Tear down private Colima VM ────────────────────────────────────
185
+ if [[ "$OS" == "macos" ]]; then
186
+ ui_info "Checking for JishuShell Colima VM (profile: ${_COLIMA_PROFILE})..."
145
187
 
146
- local nvm_dir="${NVM_DIR:-$HOME/.nvm}"
188
+ # Kill stale colima/limactl/ssh processes for our profile
189
+ _kill_jishu_procs "colima" "${_COLIMA_PROFILE}"
190
+ _kill_jishu_procs "limactl" "colima-${_COLIMA_PROFILE}"
191
+ _kill_jishu_procs "ssh.*colima-${_COLIMA_PROFILE}"
147
192
 
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
193
+ # Graceful stop + delete via colima CLI
194
+ if command -v colima &>/dev/null; then
195
+ if _colima list 2>/dev/null | grep -q "${_COLIMA_PROFILE}"; then
196
+ ui_info "Stopping Colima VM (profile: ${_COLIMA_PROFILE})..."
197
+ _colima stop "${_COLIMA_PROFILE}" 2>/dev/null || true
198
+ ui_info "Deleting Colima VM..."
199
+ _colima delete "${_COLIMA_PROFILE}" --force 2>/dev/null || true
200
+ ui_success "Colima instance '${_COLIMA_PROFILE}' stopped and deleted"
201
+ else
202
+ ui_info "Colima VM '${_COLIMA_PROFILE}' not found"
167
203
  fi
168
204
  else
169
- ui_info "No Node.js versions found managed by nvm"
205
+ ui_info "Colima CLI not found skipping VM teardown"
170
206
  fi
171
207
 
172
- if confirm "Delete nvm installation directory ($nvm_dir)?"; then
173
- run_cmd rm -rf "$nvm_dir"
174
- ui_success "nvm directory removed"
208
+ # Safety net: remove docker context
209
+ if command -v docker &>/dev/null; then
210
+ docker context rm "colima-${_COLIMA_PROFILE}" 2>/dev/null || true
175
211
  fi
176
212
 
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)"
213
+ # Clean leaked ~/.colima directory (Colima stat-guard artifact)
214
+ local default_colima_home="${HOME}/.colima"
215
+ if [[ -d "$default_colima_home" ]]; then
216
+ local real_files
217
+ real_files="$(find "$default_colima_home" -type f 2>/dev/null | head -1 || true)"
218
+ if [[ -z "$real_files" ]]; then
219
+ rm -rf "$default_colima_home" 2>/dev/null || true
220
+ if [[ ! -d "$default_colima_home" ]]; then
221
+ ui_success "Removed leaked ~/.colima (empty)"
187
222
  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"
223
+ else
224
+ ui_info "~/.colima contains files from other profiles — kept"
212
225
  fi
213
226
  fi
214
227
  fi
215
228
 
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)"
229
+ local wrapper="${HOME}/.jishushell/bin/jishushell-panel-start"
230
+ if [[ -f "$wrapper" ]]; then
231
+ rm -f "$wrapper"
232
+ ui_success "Removed wrapper: ${wrapper}"
220
233
  fi
221
- }
222
234
 
223
- # ─── Docker containers / images / volumes cleanup ────────────────────────────
224
- clean_docker_data() {
225
- ui_section "Removing Docker containers, images and volumes"
235
+ # Clean JishuShell PATH entries from shell RC files.
236
+ local marker="# jishushell-bin-path"
237
+ local shell_configs=("$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.profile" "$HOME/.zshrc")
238
+ for cfg in "${shell_configs[@]}"; do
239
+ if [[ -f "$cfg" ]] && grep -qF "$marker" "$cfg" 2>/dev/null; then
240
+ ui_info "Cleaning JishuShell PATH from ${cfg}..."
241
+ if [[ "$DRY_RUN" == "1" ]]; then
242
+ ui_info "[dry-run] Would remove jishushell-bin-path lines from ${cfg}"
243
+ else
244
+ cp "$cfg" "${cfg}.bak-jishu-uninstall"
245
+ if [[ "$(uname -s)" == "Darwin" ]]; then
246
+ sed -i '' "/${marker//\//\\/}/d; /jishushell.*bin.*PATH/d; /\.jishushell\/bin/d" "$cfg"
247
+ else
248
+ sed -i "/${marker//\//\\/}/d; /jishushell.*bin.*PATH/d; /\.jishushell\/bin/d" "$cfg"
249
+ fi
250
+ ui_success "Cleaned ${cfg} (backup: ${cfg}.bak-jishu-uninstall)"
251
+ fi
252
+ fi
253
+ done
254
+ }
226
255
 
227
- if ! command -v docker &>/dev/null; then
228
- ui_info "Docker is not installed, skipping cleanup"
256
+ # ─── Delete ~/.jishushell data directory ──────────────────────────────────────
257
+ delete_data_dir() {
258
+ local jishu_home="${JISHUSHELL_HOME:-${HOME}/.jishushell}"
259
+ if [[ ! -d "$jishu_home" ]]; then
260
+ ui_info "Data directory does not exist: ${jishu_home}"
229
261
  return 0
230
262
  fi
231
263
 
264
+ local size
265
+ size="$(du -sh "$jishu_home" 2>/dev/null | cut -f1 || echo "?")"
266
+ echo ""
267
+ ui_info "Data directory: ${jishu_home} (${size})"
268
+ ui_info "This contains your instances, config, Nomad data, and Colima data."
269
+
232
270
  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"
271
+ ui_info "[dry-run] Would: ${SUDO} rm -rf ${jishu_home}"
238
272
  return 0
239
273
  fi
240
274
 
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"
275
+ if ! confirm "Delete data directory (~/.jishushell)?"; then
276
+ ui_info "Data directory kept: ${jishu_home}"
244
277
  return 0
245
278
  fi
246
279
 
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"
280
+ # On macOS, Docker Desktop keeps VirtioFS shares open for containers that are
281
+ # stopped but not removed (docker rm). Force-remove any such containers first.
282
+ if command -v docker &>/dev/null; then
283
+ local _containers_to_rm
284
+ _containers_to_rm="$(docker ps -a --format '{{.ID}}' 2>/dev/null | xargs -I{} sh -c \
285
+ 'docker inspect {} --format "{{.ID}} {{range .Mounts}}{{.Source}} {{end}}" 2>/dev/null' \
286
+ | grep -F "$jishu_home" | awk '{print $1}' || true)"
287
+ if [[ -n "$_containers_to_rm" ]]; then
288
+ ui_info "Removing Docker containers with bind-mounts from ${jishu_home}..."
289
+ echo "$_containers_to_rm" | xargs docker rm -f 2>/dev/null || true
290
+ fi
291
+ fi
292
+ if [[ "$(uname -s)" == "Darwin" ]]; then
293
+ ${SUDO} chflags -R nouchg,noschg "$jishu_home" 2>/dev/null || true
294
+ fi
295
+ ${SUDO} rm -rf "$jishu_home" || true
296
+ if [[ ! -d "$jishu_home" ]]; then
297
+ ui_success "Data directory removed"
255
298
  else
256
- ui_info "No running containers"
299
+ ui_warn "Could not remove ${jishu_home}"
300
+ return 1
257
301
  fi
302
+ }
258
303
 
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"
304
+ # ─── Uninstall Colima system packages (macOS, --docker flag) ──────────────────
305
+ uninstall_colima() {
306
+ ui_section "Uninstalling Colima / Docker / Lima system packages"
307
+
308
+ if [[ "$OS" != "macos" ]]; then
309
+ return 0
269
310
  fi
270
311
 
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"
312
+ if [[ "$DRY_RUN" == "1" ]]; then
313
+ ui_info "[dry-run] Would: brew uninstall colima docker lima"
314
+ return 0
281
315
  fi
282
316
 
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"
317
+ if ! command -v brew &>/dev/null; then
318
+ ui_info "Homebrew not found — skipping"
319
+ return 0
293
320
  fi
294
321
 
295
- # Prune custom networks
296
- docker network prune -f 2>/dev/null || true
297
- ui_success "Docker data cleanup complete"
322
+ local brew_pkgs_to_remove=()
323
+ for pkg in colima docker lima; do
324
+ if brew list "$pkg" &>/dev/null 2>&1; then
325
+ brew_pkgs_to_remove+=("$pkg")
326
+ fi
327
+ done
328
+ if [[ ${#brew_pkgs_to_remove[@]} -gt 0 ]]; then
329
+ if confirm "Uninstall Homebrew packages: ${brew_pkgs_to_remove[*]}?"; then
330
+ brew uninstall "${brew_pkgs_to_remove[@]}" 2>/dev/null || true
331
+ ui_success "Homebrew packages removed: ${brew_pkgs_to_remove[*]}"
332
+ else
333
+ ui_info "Homebrew packages kept"
334
+ fi
335
+ else
336
+ ui_info "No JishuShell-related Homebrew packages found"
337
+ fi
298
338
  }
299
339
 
300
- # ─── Docker ───────────────────────────────────────────────────────────────────
340
+ # ─── Docker (Linux, --docker flag) ───────────────────────────────────────────
301
341
  uninstall_docker() {
302
342
  ui_section "Removing Docker"
303
343
 
@@ -469,43 +509,36 @@ uninstall_docker() {
469
509
  ui_success "Docker removed successfully"
470
510
  }
471
511
 
472
- # ─── Nomad ────────────────────────────────────────────────────────────────────
512
+ # ─── Nomad system package (--nomad flag) ──────────────────────────────────────
473
513
  uninstall_nomad() {
474
- ui_section "Removing Nomad"
514
+ ui_section "Uninstalling Nomad system package"
475
515
 
476
- local local_bin="${HOME}/.jishushell/bin/nomad"
477
516
  local system_nomad
478
517
  system_nomad="$(command -v nomad 2>/dev/null || true)"
479
- # Ignore if system PATH resolves to our local bin
518
+ local local_bin="${JISHUSHELL_HOME:-${HOME}/.jishushell}/bin/nomad"
519
+ # Ignore if system PATH resolves to our local bin (that gets cleaned with ~/.jishushell)
480
520
  [[ "$system_nomad" == "$local_bin" ]] && system_nomad=""
481
521
 
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"
522
+ if [[ -z "$system_nomad" ]]; then
523
+ ui_info "No system Nomad installation found, skipping"
489
524
  return 0
490
525
  fi
491
526
 
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}"
527
+ local sys_ver
528
+ sys_ver="$(nomad version 2>/dev/null | head -n1 || echo 'unknown')"
529
+ ui_info "System Nomad: ${sys_ver} ${system_nomad}"
530
+
531
+ if [[ "$DRY_RUN" == "1" ]]; then
532
+ ui_info "[dry-run] Would remove system Nomad via package manager"
533
+ return 0
501
534
  fi
502
535
 
503
- if ! confirm "Confirm removal of Nomad?"; then
536
+ if ! confirm "Uninstall system Nomad (${system_nomad})?"; then
504
537
  ui_info "Cancelled"
505
538
  return 0
506
539
  fi
507
540
 
508
- # Stop systemd service if running
541
+ # Stop systemd service if running (Linux)
509
542
  if command -v systemctl &>/dev/null; then
510
543
  if systemctl is-active --quiet nomad 2>/dev/null; then
511
544
  ui_info "Stopping Nomad service..."
@@ -517,91 +550,61 @@ uninstall_nomad() {
517
550
  fi
518
551
  fi
519
552
 
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)"
553
+ local removed_via_pkg=0
554
+ case "$PKG_MANAGER" in
555
+ brew)
556
+ if brew list nomad &>/dev/null 2>&1; then
557
+ ui_info "Removing Nomad via Homebrew..."
558
+ brew uninstall nomad 2>/dev/null || true
559
+ removed_via_pkg=1
539
560
  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
561
+ ;;
562
+ apt)
563
+ if dpkg -l nomad 2>/dev/null | grep -q '^ii'; then
564
+ ui_info "Removing Nomad via apt..."
565
+ run_sudo apt-get remove -y nomad 2>/dev/null || true
566
+ run_sudo apt-get autoremove -y 2>/dev/null || true
567
+ removed_via_pkg=1
568
+ fi
569
+ if [[ $removed_via_pkg -eq 1 ]]; then
570
+ local hashi_sources=(/etc/apt/sources.list.d/hashicorp.list)
571
+ for src in "${hashi_sources[@]}"; do
572
+ if [[ -f "$src" ]]; then
573
+ if confirm "Delete HashiCorp APT repository config ($src)?"; then
574
+ run_sudo rm -f "$src" \
575
+ /usr/share/keyrings/hashicorp-archive-keyring.gpg 2>/dev/null || true
562
576
  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
577
  fi
578
+ done
579
+ fi
580
+ ;;
581
+ dnf|yum)
582
+ if rpm -q nomad &>/dev/null 2>&1; then
583
+ ui_info "Removing Nomad via $PKG_MANAGER..."
584
+ run_sudo "$PKG_MANAGER" remove -y nomad 2>/dev/null || true
585
+ removed_via_pkg=1
586
+ fi
587
+ if [[ $removed_via_pkg -eq 1 ]] && [[ -f /etc/yum.repos.d/hashicorp.repo ]]; then
588
+ if confirm "Delete HashiCorp YUM repository config (/etc/yum.repos.d/hashicorp.repo)?"; then
589
+ run_sudo rm -f /etc/yum.repos.d/hashicorp.repo 2>/dev/null || true
576
590
  fi
577
- ;;
578
- esac
591
+ fi
592
+ ;;
593
+ esac
579
594
 
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
595
+ # Remove binary directly if still present and package manager didn't handle it
596
+ local remaining
597
+ remaining="$(command -v nomad 2>/dev/null || true)"
598
+ if [[ -n "$remaining" && "$remaining" != "$local_bin" ]]; then
599
+ ui_info "Removing remaining system binary: ${remaining}"
600
+ run_sudo rm -f "$remaining" 2>/dev/null || true
587
601
  fi
588
602
 
589
603
  # Remove systemd service files
590
604
  run_sudo rm -f /etc/systemd/system/nomad.service \
591
605
  /usr/lib/systemd/system/nomad.service 2>/dev/null || true
592
606
 
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)
607
+ # Nomad system data dirs
605
608
  if confirm "Delete Nomad system data directories (/etc/nomad.d /var/lib/nomad /var/log/nomad)?"; then
606
609
  run_sudo rm -rf /etc/nomad.d /var/lib/nomad /var/log/nomad 2>/dev/null || true
607
610
  ui_success "Nomad system data directories removed"
@@ -612,84 +615,13 @@ uninstall_nomad() {
612
615
  fi
613
616
 
614
617
  # 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
618
  local nomad_remaining
621
619
  nomad_remaining="$(command -v nomad 2>/dev/null || true)"
622
- if [[ -n "$nomad_remaining" ]]; then
620
+ if [[ -n "$nomad_remaining" && "$nomad_remaining" != "$local_bin" ]]; then
623
621
  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
622
  return 1
631
623
  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
624
+ ui_success "Nomad removed successfully"
693
625
  }
694
626
 
695
627
  # ─── Summary ──────────────────────────────────────────────────────────────────
@@ -697,19 +629,13 @@ show_plan() {
697
629
  echo ""
698
630
  echo -e "${ACCENT}${BOLD}Uninstall Plan${NC}"
699
631
  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
632
+ echo -e " ${WARN}·${NC} Stop all running services and remove from auto-start"
633
+ echo -e " ${WARN}·${NC} Stop and delete JishuShell Colima VM (macOS)"
634
+ echo -e " ${WARN}·${NC} Kill JishuShell-related processes"
635
+ echo -e " ${WARN}·${NC} Remove docker context, npm package, PATH entries"
636
+ echo -e " ${WARN}·${NC} Data directory (~/.jishushell) will ask"
637
+ [[ $DO_DOCKER -eq 1 ]] && echo -e " ${WARN}·${NC} Uninstall Docker/Colima system packages (brew/apt/dnf)"
638
+ [[ $DO_NOMAD -eq 1 ]] && echo -e " ${WARN}·${NC} Uninstall Nomad system package (brew/apt/dnf)"
713
639
  if [[ "$DRY_RUN" == "1" ]]; then
714
640
  echo ""
715
641
  echo -e "${WARN} Dry-run mode: no changes will be made${NC}"
@@ -734,7 +660,8 @@ main() {
734
660
 
735
661
  show_plan
736
662
 
737
- if ! confirm "This will stop all JishuShell services and remove them from auto-start. Proceed?"; then
663
+ # ── Phase 1: Stop services & clean runtime artifacts ──────────────────────
664
+ if ! confirm "Stop all JishuShell services and clean up runtime artifacts?"; then
738
665
  ui_info "Cancelled"
739
666
  exit 0
740
667
  fi
@@ -743,62 +670,20 @@ main() {
743
670
 
744
671
  stop_services || uninstall_errors=1
745
672
 
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; }
673
+ # ── Phase 2: Delete data directory ────────────────────────────────────────
674
+ delete_data_dir || uninstall_errors=1
751
675
 
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
676
+ # ── Phase 3: System package removal (only with explicit flags) ────────────
677
+ if [[ $DO_DOCKER -eq 1 ]]; then
678
+ if [[ "$OS" == "macos" ]]; then
679
+ uninstall_colima || uninstall_errors=1
797
680
  else
798
- ui_info "Data directory kept: ${jishu_home}"
681
+ uninstall_docker || uninstall_errors=1
799
682
  fi
800
683
  fi
801
684
 
685
+ [[ $DO_NOMAD -eq 1 ]] && { uninstall_nomad || uninstall_errors=1; }
686
+
802
687
  echo ""
803
688
  if [[ $uninstall_errors -eq 0 ]]; then
804
689
  echo -e "${SUCCESS}${BOLD}Done.${NC}"