jishushell 0.4.10 → 0.4.24-beta.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.
Files changed (248) hide show
  1. package/Dockerfile.hermes-slim +193 -0
  2. package/INSTALL-NOTICE +10 -12
  3. package/apps/hermes-container.yaml +35 -0
  4. package/apps/ollama-binary.yaml +164 -0
  5. package/apps/ollama-cpu-container.yaml +37 -0
  6. package/apps/ollama-with-hollama-binary.yaml +159 -0
  7. package/apps/openclaw-binary.yaml +69 -0
  8. package/apps/openclaw-container.yaml +37 -0
  9. package/apps/openclaw-with-ollama-container.yaml +42 -0
  10. package/apps/openclaw-with-searxng-container.yaml +136 -0
  11. package/apps/openwebui-container.yaml +53 -0
  12. package/apps/playwright-container.yaml +120 -0
  13. package/apps/searxng-container.yaml +115 -0
  14. package/dist/auth.d.ts +1 -0
  15. package/dist/auth.js +15 -14
  16. package/dist/auth.js.map +1 -1
  17. package/dist/cli/app.d.ts +4 -0
  18. package/dist/cli/app.js +874 -0
  19. package/dist/cli/app.js.map +1 -0
  20. package/dist/cli/backup.d.ts +3 -0
  21. package/dist/cli/backup.js +434 -0
  22. package/dist/cli/backup.js.map +1 -0
  23. package/dist/{doctor.d.ts → cli/doctor.d.ts} +7 -1
  24. package/dist/{doctor.js → cli/doctor.js} +377 -22
  25. package/dist/cli/doctor.js.map +1 -0
  26. package/dist/cli/helpers.d.ts +4 -0
  27. package/dist/cli/helpers.js +32 -0
  28. package/dist/cli/helpers.js.map +1 -0
  29. package/dist/cli/job.d.ts +4 -0
  30. package/dist/cli/job.js +198 -0
  31. package/dist/cli/job.js.map +1 -0
  32. package/dist/cli/llm.d.ts +25 -0
  33. package/dist/cli/llm.js +599 -0
  34. package/dist/cli/llm.js.map +1 -0
  35. package/dist/cli/managed-list.d.ts +30 -0
  36. package/dist/cli/managed-list.js +129 -0
  37. package/dist/cli/managed-list.js.map +1 -0
  38. package/dist/cli/panel.d.ts +26 -0
  39. package/dist/cli/panel.js +804 -0
  40. package/dist/cli/panel.js.map +1 -0
  41. package/dist/cli/version.d.ts +1 -0
  42. package/dist/cli/version.js +12 -0
  43. package/dist/cli/version.js.map +1 -0
  44. package/dist/cli.js +48 -776
  45. package/dist/cli.js.map +1 -1
  46. package/dist/config.d.ts +69 -0
  47. package/dist/config.js +268 -7
  48. package/dist/config.js.map +1 -1
  49. package/dist/control.d.ts +17 -41
  50. package/dist/control.js +61 -1323
  51. package/dist/control.js.map +1 -1
  52. package/dist/install.d.ts +16 -0
  53. package/dist/install.js +75 -26
  54. package/dist/install.js.map +1 -1
  55. package/dist/routes/agent-apps.d.ts +15 -0
  56. package/dist/routes/agent-apps.js +78 -0
  57. package/dist/routes/agent-apps.js.map +1 -0
  58. package/dist/routes/apps.d.ts +3 -0
  59. package/dist/routes/apps.js +278 -0
  60. package/dist/routes/apps.js.map +1 -0
  61. package/dist/routes/backup.js +3 -3
  62. package/dist/routes/backup.js.map +1 -1
  63. package/dist/routes/instances.d.ts +6 -0
  64. package/dist/routes/instances.js +863 -874
  65. package/dist/routes/instances.js.map +1 -1
  66. package/dist/routes/llm.d.ts +15 -0
  67. package/dist/routes/llm.js +247 -0
  68. package/dist/routes/llm.js.map +1 -0
  69. package/dist/routes/runtime.d.ts +15 -0
  70. package/dist/routes/runtime.js +69 -0
  71. package/dist/routes/runtime.js.map +1 -0
  72. package/dist/routes/setup.js +131 -9
  73. package/dist/routes/setup.js.map +1 -1
  74. package/dist/routes/system.js +56 -9
  75. package/dist/routes/system.js.map +1 -1
  76. package/dist/server.js +107 -7
  77. package/dist/server.js.map +1 -1
  78. package/dist/services/agent-apps/catalog.d.ts +30 -0
  79. package/dist/services/agent-apps/catalog.js +60 -0
  80. package/dist/services/agent-apps/catalog.js.map +1 -0
  81. package/dist/services/agent-apps/index.d.ts +36 -0
  82. package/dist/services/agent-apps/index.js +171 -0
  83. package/dist/services/agent-apps/index.js.map +1 -0
  84. package/dist/services/agent-apps/installers/adapter-probes.d.ts +49 -0
  85. package/dist/services/agent-apps/installers/adapter-probes.js +223 -0
  86. package/dist/services/agent-apps/installers/adapter-probes.js.map +1 -0
  87. package/dist/services/agent-apps/installers/adapter.d.ts +30 -0
  88. package/dist/services/agent-apps/installers/adapter.js +171 -0
  89. package/dist/services/agent-apps/installers/adapter.js.map +1 -0
  90. package/dist/services/agent-apps/installers/registry-probe.d.ts +38 -0
  91. package/dist/services/agent-apps/installers/registry-probe.js +183 -0
  92. package/dist/services/agent-apps/installers/registry-probe.js.map +1 -0
  93. package/dist/services/agent-apps/installers/shell-script.d.ts +47 -0
  94. package/dist/services/agent-apps/installers/shell-script.js +471 -0
  95. package/dist/services/agent-apps/installers/shell-script.js.map +1 -0
  96. package/dist/services/agent-apps/types.d.ts +125 -0
  97. package/dist/services/agent-apps/types.js +17 -0
  98. package/dist/services/agent-apps/types.js.map +1 -0
  99. package/dist/services/app/app-compiler.d.ts +15 -0
  100. package/dist/services/app/app-compiler.js +172 -0
  101. package/dist/services/app/app-compiler.js.map +1 -0
  102. package/dist/services/app/app-manager.d.ts +142 -0
  103. package/dist/services/app/app-manager.js +2148 -0
  104. package/dist/services/app/app-manager.js.map +1 -0
  105. package/dist/services/app/custom-manager.d.ts +27 -0
  106. package/dist/services/app/custom-manager.js +285 -0
  107. package/dist/services/app/custom-manager.js.map +1 -0
  108. package/dist/services/app/hermes-agent-manager.d.ts +20 -0
  109. package/dist/services/app/hermes-agent-manager.js +289 -0
  110. package/dist/services/app/hermes-agent-manager.js.map +1 -0
  111. package/dist/services/app/id-normalizer.d.ts +27 -0
  112. package/dist/services/app/id-normalizer.js +77 -0
  113. package/dist/services/app/id-normalizer.js.map +1 -0
  114. package/dist/services/app/ollama-manager.d.ts +18 -0
  115. package/dist/services/app/ollama-manager.js +207 -0
  116. package/dist/services/app/ollama-manager.js.map +1 -0
  117. package/dist/services/app/openclaw-manager.d.ts +63 -0
  118. package/dist/services/app/openclaw-manager.js +1178 -0
  119. package/dist/services/app/openclaw-manager.js.map +1 -0
  120. package/dist/services/app/paths.d.ts +47 -0
  121. package/dist/services/app/paths.js +68 -0
  122. package/dist/services/app/paths.js.map +1 -0
  123. package/dist/services/app/registry.d.ts +17 -0
  124. package/dist/services/app/registry.js +31 -0
  125. package/dist/services/app/registry.js.map +1 -0
  126. package/dist/services/app/remote-spec.d.ts +14 -0
  127. package/dist/services/app/remote-spec.js +58 -0
  128. package/dist/services/app/remote-spec.js.map +1 -0
  129. package/dist/services/app/terminal-session-manager.d.ts +27 -0
  130. package/dist/services/app/terminal-session-manager.js +157 -0
  131. package/dist/services/app/terminal-session-manager.js.map +1 -0
  132. package/dist/services/app/types.d.ts +72 -0
  133. package/dist/services/app/types.js +16 -0
  134. package/dist/services/app/types.js.map +1 -0
  135. package/dist/services/backup-manager.js +60 -22
  136. package/dist/services/backup-manager.js.map +1 -1
  137. package/dist/services/instance-manager.d.ts +125 -34
  138. package/dist/services/instance-manager.js +679 -1043
  139. package/dist/services/instance-manager.js.map +1 -1
  140. package/dist/services/llm-proxy/adapters.js +5 -1
  141. package/dist/services/llm-proxy/adapters.js.map +1 -1
  142. package/dist/services/llm-proxy/circuit-breaker.js +10 -2
  143. package/dist/services/llm-proxy/circuit-breaker.js.map +1 -1
  144. package/dist/services/llm-proxy/index.d.ts +43 -0
  145. package/dist/services/llm-proxy/index.js +120 -5
  146. package/dist/services/llm-proxy/index.js.map +1 -1
  147. package/dist/services/llm-proxy/ssrf.js +1 -1
  148. package/dist/services/llm-proxy/ssrf.js.map +1 -1
  149. package/dist/services/nomad-manager.d.ts +260 -3
  150. package/dist/services/nomad-manager.js +2921 -341
  151. package/dist/services/nomad-manager.js.map +1 -1
  152. package/dist/services/panel-manager.d.ts +50 -0
  153. package/dist/services/panel-manager.js +443 -0
  154. package/dist/services/panel-manager.js.map +1 -0
  155. package/dist/services/plugin-installer.js +28 -2
  156. package/dist/services/plugin-installer.js.map +1 -1
  157. package/dist/services/process-manager.js +42 -7
  158. package/dist/services/process-manager.js.map +1 -1
  159. package/dist/services/runtime/adapters/custom.d.ts +20 -0
  160. package/dist/services/runtime/adapters/custom.js +90 -0
  161. package/dist/services/runtime/adapters/custom.js.map +1 -0
  162. package/dist/services/runtime/adapters/hermes.d.ts +174 -0
  163. package/dist/services/runtime/adapters/hermes.js +1316 -0
  164. package/dist/services/runtime/adapters/hermes.js.map +1 -0
  165. package/dist/services/runtime/adapters/openclaw-routes.d.ts +17 -0
  166. package/dist/services/runtime/adapters/openclaw-routes.js +946 -0
  167. package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -0
  168. package/dist/services/runtime/adapters/openclaw.d.ts +188 -0
  169. package/dist/services/runtime/adapters/openclaw.js +2195 -0
  170. package/dist/services/runtime/adapters/openclaw.js.map +1 -0
  171. package/dist/services/runtime/errors.d.ts +28 -0
  172. package/dist/services/runtime/errors.js +31 -0
  173. package/dist/services/runtime/errors.js.map +1 -0
  174. package/dist/services/runtime/index.d.ts +34 -0
  175. package/dist/services/runtime/index.js +51 -0
  176. package/dist/services/runtime/index.js.map +1 -0
  177. package/dist/services/runtime/instance.d.ts +24 -0
  178. package/dist/services/runtime/instance.js +143 -0
  179. package/dist/services/runtime/instance.js.map +1 -0
  180. package/dist/services/runtime/migrations.d.ts +15 -0
  181. package/dist/services/runtime/migrations.js +25 -0
  182. package/dist/services/runtime/migrations.js.map +1 -0
  183. package/dist/services/runtime/registry.d.ts +13 -0
  184. package/dist/services/runtime/registry.js +32 -0
  185. package/dist/services/runtime/registry.js.map +1 -0
  186. package/dist/services/runtime/types.d.ts +545 -0
  187. package/dist/services/runtime/types.js +14 -0
  188. package/dist/services/runtime/types.js.map +1 -0
  189. package/dist/services/setup-manager.d.ts +70 -29
  190. package/dist/services/setup-manager.js +591 -625
  191. package/dist/services/setup-manager.js.map +1 -1
  192. package/dist/services/task-registry.d.ts +44 -0
  193. package/dist/services/task-registry.js +74 -0
  194. package/dist/services/task-registry.js.map +1 -0
  195. package/dist/services/telemetry/heartbeat.d.ts +6 -6
  196. package/dist/services/telemetry/heartbeat.js +29 -30
  197. package/dist/services/telemetry/heartbeat.js.map +1 -1
  198. package/dist/services/update-manager.d.ts +47 -0
  199. package/dist/services/update-manager.js +305 -0
  200. package/dist/services/update-manager.js.map +1 -0
  201. package/dist/types.d.ts +224 -0
  202. package/dist/utils/docker-host.d.ts +15 -0
  203. package/dist/utils/docker-host.js +64 -0
  204. package/dist/utils/docker-host.js.map +1 -0
  205. package/install/jishu-install.sh +303 -38
  206. package/install/post-install.sh +64 -5
  207. package/package.json +19 -5
  208. package/public/assets/Dashboard-rh9qpYRR.js +1 -0
  209. package/public/assets/HermesChatPanel-D6JI6lLY.js +1 -0
  210. package/public/assets/HermesConfigForm-DcbSemaj.js +4 -0
  211. package/public/assets/InitPassword-CFTKsED4.js +1 -0
  212. package/public/assets/InstanceDetail-BhNIKA6Z.js +91 -0
  213. package/public/assets/{Login-CUoEZOWR.js → Login-KB9qrtM0.js} +1 -1
  214. package/public/assets/NewInstance-CxkO8Hlq.js +1 -0
  215. package/public/assets/Settings-BVWJvOkU.js +1 -0
  216. package/public/assets/Setup-X-lzuaUT.js +1 -0
  217. package/public/assets/WeixinLoginPanel-gca0QTic.js +9 -0
  218. package/public/assets/index-C8B0cFJM.js +19 -0
  219. package/public/assets/index-CPhVFEsx.css +1 -0
  220. package/public/assets/input-paste-CrNVAyOy.js +1 -0
  221. package/public/assets/{providers-lBSOjUWy.js → providers-V-vwrExZ.js} +1 -1
  222. package/public/assets/registry-fVUSujib.js +2 -0
  223. package/public/assets/{usePolling-CK0DfI4h.js → usePolling-Do5Erqm_.js} +1 -1
  224. package/public/assets/vendor-i18n-ucpM0OR0.js +9 -0
  225. package/public/assets/{vendor-react-B1-3Yrt-.js → vendor-react-Bk1hRGiY.js} +1 -1
  226. package/public/favicon.png +0 -0
  227. package/public/index.html +9 -4
  228. package/public/logos/hermes.png +0 -0
  229. package/public/logos/ollama.png +0 -0
  230. package/public/logos/openclaw.svg +60 -0
  231. package/scripts/build-hermes-image.sh +21 -0
  232. package/scripts/build-local.sh +54 -0
  233. package/scripts/check-adapter-isolation.ts +293 -0
  234. package/scripts/fixtures/instances/hermes-sample/instance.json +37 -0
  235. package/scripts/fixtures/instances/legacy-openclaw-sample/instance.json +7 -0
  236. package/scripts/smoke/hermes-bootstrap.sh +195 -0
  237. package/templates/hermes-entrypoint.sh +154 -0
  238. package/dist/doctor.js.map +0 -1
  239. package/install/jishu-install-china.sh +0 -3092
  240. package/public/assets/Dashboard-DhsrzJ4F.js +0 -1
  241. package/public/assets/InitPassword-BjubiVdd.js +0 -1
  242. package/public/assets/InstanceDetail-DMcywsof.js +0 -17
  243. package/public/assets/NewInstance-Bk0G4EiJ.js +0 -1
  244. package/public/assets/Settings-D5tHL_h5.js +0 -1
  245. package/public/assets/Setup-4t6E3Rut.js +0 -1
  246. package/public/assets/index-BJ47MWpF.css +0 -1
  247. package/public/assets/index-DbX85irc.js +0 -16
  248. package/public/assets/vendor-i18n-CfW0RvgE.js +0 -9
@@ -0,0 +1,64 @@
1
+ import { execFileSync } from "child_process";
2
+ import { existsSync } from "fs";
3
+ import { join } from "path";
4
+ export function managedColimaSocketPath(jishuHome, colimaProfile = "jishushell") {
5
+ return join(jishuHome, "colima", colimaProfile, "docker.sock");
6
+ }
7
+ export function managedColimaDockerHost(jishuHome, colimaProfile = "jishushell") {
8
+ return `unix://${managedColimaSocketPath(jishuHome, colimaProfile)}`;
9
+ }
10
+ function resolveDockerHostFromCurrentContext(env, execFileSyncImpl) {
11
+ const contextEnv = { ...env };
12
+ delete contextEnv.DOCKER_HOST;
13
+ try {
14
+ const contextName = String(execFileSyncImpl("docker", ["context", "show"], {
15
+ encoding: "utf-8",
16
+ timeout: 3000,
17
+ env: contextEnv,
18
+ })).trim();
19
+ if (!contextName)
20
+ return undefined;
21
+ const raw = String(execFileSyncImpl("docker", ["context", "inspect", contextName], {
22
+ encoding: "utf-8",
23
+ timeout: 3000,
24
+ env: contextEnv,
25
+ }));
26
+ const parsed = JSON.parse(raw);
27
+ const host = parsed[0]?.Endpoints?.docker?.Host;
28
+ return typeof host === "string" && host.trim() ? host.trim() : undefined;
29
+ }
30
+ catch {
31
+ return undefined;
32
+ }
33
+ }
34
+ export function resolveDockerHost(options) {
35
+ const { jishuHome, colimaProfile = "jishushell", env = process.env, platform = process.platform, execFileSyncImpl = execFileSync, existsSyncImpl = existsSync, } = options;
36
+ const envHost = typeof env.DOCKER_HOST === "string" ? env.DOCKER_HOST.trim() : "";
37
+ const colimaSocket = managedColimaSocketPath(jishuHome, colimaProfile);
38
+ const colimaHost = managedColimaDockerHost(jishuHome, colimaProfile);
39
+ const contextHost = platform === "darwin"
40
+ ? resolveDockerHostFromCurrentContext(env, execFileSyncImpl)
41
+ : undefined;
42
+ if (platform === "darwin" && existsSyncImpl(colimaSocket)) {
43
+ return colimaHost;
44
+ }
45
+ if (envHost) {
46
+ if (platform === "darwin" && envHost === colimaHost) {
47
+ return contextHost;
48
+ }
49
+ return envHost;
50
+ }
51
+ if (contextHost)
52
+ return contextHost;
53
+ return undefined;
54
+ }
55
+ export function buildDockerClientEnv(options) {
56
+ const env = { ...(options.env ?? process.env) };
57
+ const dockerHost = resolveDockerHost(options);
58
+ if (dockerHost)
59
+ env.DOCKER_HOST = dockerHost;
60
+ else
61
+ delete env.DOCKER_HOST;
62
+ return env;
63
+ }
64
+ //# sourceMappingURL=docker-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-host.js","sourceRoot":"","sources":["../../src/utils/docker-host.ts"],"names":[],"mappings":"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"}
@@ -118,7 +118,11 @@ is_promptable() {
118
118
  if [[ "${NO_PROMPT:-0}" == "1" ]]; then
119
119
  return 1
120
120
  fi
121
- if [[ -r /dev/tty && -w /dev/tty ]]; then
121
+ # Web-triggered upgrades never have an interactive TTY
122
+ if [[ "${JISHUSHELL_WEB_UPDATE:-0}" == "1" ]]; then
123
+ return 1
124
+ fi
125
+ if ( : <> /dev/tty ) 2>/dev/null; then
122
126
  return 0
123
127
  fi
124
128
  return 1
@@ -161,7 +165,7 @@ JISHU_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd 2>/dev/null |
161
165
  # ──── BEGIN VERSIONS ────
162
166
  NODE_VERSION="${JISHU_NODE_VERSION:-22}"
163
167
  NVM_VERSION="${JISHU_NVM_VERSION:-0.40.4}"
164
- NOMAD_VERSION="${JISHU_NOMAD_VERSION:-1.11.3}"
168
+ NOMAD_VERSION="${JISHU_NOMAD_VERSION:-1.6.5}"
165
169
  JISHUSHELL_PORT="${JISHUSHELL_PORT:-8090}"
166
170
 
167
171
  # ──── NPM Registry Configuration ────
@@ -223,6 +227,11 @@ SKIP_NOMAD="${SKIP_NOMAD:-0}"
223
227
  SKIP_OPENCLAW="${SKIP_OPENCLAW:-0}" # default=0 (install); use --skip 4 or --skip-openclaw to skip
224
228
  SKIP_JISHUSHELL="${SKIP_JISHUSHELL:-0}" # 1=skip install_jishushell
225
229
  SKIP_JISHUSHELL_SERVICE="${SKIP_JISHUSHELL_SERVICE:-0}" # 1=skip service registration
230
+ JISHUSHELL_NPM_VERSION="${JISHUSHELL_NPM_VERSION:-latest}" # jishushell npm package version
231
+ JISHUSHELL_VERSION_OVERRIDE=0
232
+ if [[ "${JISHUSHELL_NPM_VERSION}" != "latest" ]]; then
233
+ JISHUSHELL_VERSION_OVERRIDE=1
234
+ fi
226
235
  OPENCLAW_NPM_VERSION="${OPENCLAW_NPM_VERSION:-latest}" # openclaw npm package version
227
236
  OPENCLAW_DOCKER_TAG="${OPENCLAW_DOCKER_TAG:-ghcr.io/x-aijishu/openclaw-runtime:latest}" # pre-built image from registry
228
237
  OPENCLAW_IMAGE="" # set dynamically after pull/build
@@ -448,6 +457,10 @@ check_sudo() {
448
457
 
449
458
  if ! sudo -n true 2>/dev/null; then
450
459
  ui_info "Some steps require sudo — you may be prompted for your password."
460
+ if ! is_promptable; then
461
+ ui_error "Failed to obtain sudo privileges (no interactive TTY available)"
462
+ exit 1
463
+ fi
451
464
  if ! sudo -v </dev/tty; then
452
465
  ui_error "Failed to obtain sudo privileges"
453
466
  exit 1
@@ -1413,12 +1426,24 @@ install_nomad() {
1413
1426
  if [[ -z "$current_version" ]]; then
1414
1427
  ui_warn "Nomad at ${local_bin} is not functional (wrong arch or corrupt) — reinstalling..."
1415
1428
  rm -f "$local_bin"
1429
+ elif [[ "$current_version" == "$NOMAD_VERSION" ]]; then
1430
+ ui_success "Nomad already at target version: v${current_version} → ${local_bin}"
1431
+ _ensure_jishushell_bin_in_path
1432
+ return 0
1416
1433
  elif version_gte "$current_version" "$NOMAD_VERSION"; then
1417
- ui_success "Nomad already installed: v${current_version} ${local_bin}"
1434
+ # current > target (the == case was handled above). JishuShell
1435
+ # pins Nomad to a specific version on purpose (license downgrade
1436
+ # from BSL 1.1 to MPL 2.0). Raft state is not backward compatible
1437
+ # across the jump, so we auto-migrate: download + verify the new
1438
+ # binary first (safe-first), then stop services, back up the old
1439
+ # data_dir, wipe it, clean orphaned containers, and swap the
1440
+ # binary. JishuShell re-bootstraps ACL and resubmits jobs from
1441
+ # on-disk instance configs on the next start.
1442
+ _migrate_nomad_to_target "$current_version" || return 1
1418
1443
  _ensure_jishushell_bin_in_path
1419
1444
  return 0
1420
1445
  else
1421
- ui_warn "Nomad version too old: v${current_version} (need >= v${NOMAD_VERSION}) — upgrading..."
1446
+ ui_warn "Nomad version too old: v${current_version} (need v${NOMAD_VERSION}) — upgrading..."
1422
1447
  rm -f "$local_bin"
1423
1448
  fi
1424
1449
  fi
@@ -1504,6 +1529,180 @@ REPO
1504
1529
  return 1
1505
1530
  }
1506
1531
 
1532
+ # Auto-migrate from a higher Nomad version (e.g. 1.11.3 BSL) back to the
1533
+ # jishushell target (1.6.5 MPL). Called when install_nomad detects a local
1534
+ # binary whose semver is > NOMAD_VERSION. The migration is destructive to
1535
+ # Nomad's raft state (schema is not backward compatible) but preserves
1536
+ # instance configs under ~/.jishushell/instances/*, which is what jishushell
1537
+ # uses to resubmit jobs after reboot. A single tar.gz snapshot of the old
1538
+ # data_dir is kept under ~/.jishushell/nomad/backups/ for forensic inspection
1539
+ # — it is not a user-recovery mechanism (the schema can't be replayed).
1540
+ _migrate_nomad_to_target() {
1541
+ local current_version="$1"
1542
+ local local_bin="${JISHUSHELL_BIN_DIR}/nomad"
1543
+
1544
+ if [[ "$DRY_RUN" == "1" ]]; then
1545
+ ui_info "[dry-run] Would migrate Nomad v${current_version} → v${NOMAD_VERSION}:"
1546
+ ui_info "[dry-run] 1. Stage + verify new binary in /tmp"
1547
+ ui_info "[dry-run] 2. Stop jishushell + nomad services"
1548
+ ui_info "[dry-run] 3. Tar backup ${JISHUSHELL_HOME}/nomad/data → nomad/backups/data-<ts>.tar.gz"
1549
+ ui_info "[dry-run] 4. Wipe raft state + nomad.env files (schema incompatible)"
1550
+ ui_info "[dry-run] 5. Remove orphaned gateway-<alloc> containers"
1551
+ ui_info "[dry-run] 6. Swap binary into ${local_bin}"
1552
+ return 0
1553
+ fi
1554
+
1555
+ ui_warn "Nomad v${current_version} > target v${NOMAD_VERSION} — auto-migrating (BSL → MPL)..."
1556
+ ui_info " Raft state is not backward-compatible; allocation history will be reset."
1557
+ ui_info " Instance configs under ${JISHUSHELL_HOME}/instances/ are preserved."
1558
+
1559
+ # ── Stage 1: download + verify new binary before touching anything ────
1560
+ local stage_dir
1561
+ stage_dir="$(mktemp -d)" || { ui_error "mktemp failed"; return 1; }
1562
+ # shellcheck disable=SC2064
1563
+ trap "rm -rf '$stage_dir'" RETURN
1564
+
1565
+ local platform
1566
+ platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
1567
+ local download_url="https://releases.hashicorp.com/nomad/${NOMAD_VERSION}/nomad_${NOMAD_VERSION}_${platform}_${ARCH}.zip"
1568
+ local sums_url="https://releases.hashicorp.com/nomad/${NOMAD_VERSION}/nomad_${NOMAD_VERSION}_SHA256SUMS"
1569
+
1570
+ ui_info "Staging Nomad v${NOMAD_VERSION} (${platform}/${ARCH})..."
1571
+ if ! retry_net "Download Nomad binary" 3 curl -fsSL "$download_url" -o "${stage_dir}/nomad.zip"; then
1572
+ ui_error "Failed to download Nomad v${NOMAD_VERSION} — keeping existing v${current_version}"
1573
+ return 1
1574
+ fi
1575
+ if ! retry_net "Download Nomad checksums" 3 curl -fsSL "$sums_url" -o "${stage_dir}/SHA256SUMS"; then
1576
+ ui_error "Failed to download Nomad checksum file — aborting migration for security"
1577
+ return 1
1578
+ fi
1579
+
1580
+ local expected_hash actual_hash
1581
+ expected_hash="$(grep "nomad_${NOMAD_VERSION}_${platform}_${ARCH}.zip" "${stage_dir}/SHA256SUMS" | awk '{print $1}')"
1582
+ if [[ -z "$expected_hash" ]]; then
1583
+ ui_error "No checksum entry for nomad_${NOMAD_VERSION}_${platform}_${ARCH}.zip — aborting"
1584
+ return 1
1585
+ fi
1586
+ if command -v sha256sum &>/dev/null; then
1587
+ actual_hash="$(sha256sum "${stage_dir}/nomad.zip" | awk '{print $1}')"
1588
+ else
1589
+ actual_hash="$(shasum -a 256 "${stage_dir}/nomad.zip" | awk '{print $1}')"
1590
+ fi
1591
+ if [[ "$expected_hash" != "$actual_hash" ]]; then
1592
+ ui_error "Nomad checksum mismatch — download may have been tampered with!"
1593
+ ui_error " Expected: $expected_hash"
1594
+ ui_error " Got: $actual_hash"
1595
+ return 1
1596
+ fi
1597
+ ui_info "Checksum verified ✓"
1598
+
1599
+ if ! command -v unzip &>/dev/null; then
1600
+ ui_info "Installing unzip..."
1601
+ pkg_install unzip >/dev/null 2>&1
1602
+ fi
1603
+ if ! unzip -o "${stage_dir}/nomad.zip" nomad -d "${stage_dir}" >/dev/null 2>&1; then
1604
+ if ! unzip -o "${stage_dir}/nomad.zip" -d "${stage_dir}" >/dev/null 2>&1; then
1605
+ ui_error "Failed to extract staged Nomad archive"
1606
+ return 1
1607
+ fi
1608
+ fi
1609
+ chmod 755 "${stage_dir}/nomad" 2>/dev/null
1610
+
1611
+ local staged_version
1612
+ staged_version="$("${stage_dir}/nomad" version 2>/dev/null | head -n1 | extract_semver || echo "")"
1613
+ if [[ "$staged_version" != "$NOMAD_VERSION" ]]; then
1614
+ ui_error "Staged binary reports v${staged_version:-unknown}, expected v${NOMAD_VERSION} — aborting"
1615
+ return 1
1616
+ fi
1617
+ ui_success "Staged new Nomad binary v${staged_version}"
1618
+
1619
+ # ── Stage 2: destructive state changes begin ──────────────────────────
1620
+ ui_info "Stopping services..."
1621
+ ${SUDO} systemctl stop jishushell 2>/dev/null || true
1622
+ ${SUDO} systemctl stop nomad 2>/dev/null || true
1623
+ # pkill -f 'nomad agent' matches its own cmdline ("pkill -f nomad agent"
1624
+ # literally contains the pattern) and self-terminates before reaching the
1625
+ # real nomad process. Use pgrep -x nomad instead (exact proc-name match,
1626
+ # pgrep's own comm is "pgrep" not "nomad").
1627
+ local nomad_pids
1628
+ nomad_pids="$(pgrep -x nomad 2>/dev/null | tr '\n' ' ')"
1629
+ if [[ -n "$nomad_pids" ]]; then
1630
+ # shellcheck disable=SC2086
1631
+ ${SUDO} kill -TERM $nomad_pids 2>/dev/null || kill -TERM $nomad_pids 2>/dev/null || true
1632
+ sleep 2
1633
+ nomad_pids="$(pgrep -x nomad 2>/dev/null | tr '\n' ' ')"
1634
+ if [[ -n "$nomad_pids" ]]; then
1635
+ # shellcheck disable=SC2086
1636
+ ${SUDO} kill -KILL $nomad_pids 2>/dev/null || kill -KILL $nomad_pids 2>/dev/null || true
1637
+ fi
1638
+ fi
1639
+
1640
+ # ── Stage 3: tar backup (single snapshot, overwrite any previous) ─────
1641
+ local backup_file=""
1642
+ local backup_dir="${JISHUSHELL_HOME}/nomad/backups"
1643
+ if [[ -d "${JISHUSHELL_HOME}/nomad/data" ]]; then
1644
+ mkdir -p "$backup_dir"
1645
+ local ts
1646
+ ts="$(date +%Y%m%d-%H%M%S)"
1647
+ backup_file="${backup_dir}/data-${ts}.tar.gz"
1648
+ ui_info "Backing up raft state → ${backup_file}"
1649
+ if ! tar czf "$backup_file" -C "${JISHUSHELL_HOME}/nomad" data 2>/dev/null; then
1650
+ ui_warn "Backup tar failed — continuing (raft state will still be wiped)"
1651
+ backup_file=""
1652
+ else
1653
+ # Keep only the most recent snapshot to avoid unbounded disk growth
1654
+ ls -t "${backup_dir}"/data-*.tar.gz 2>/dev/null | tail -n +2 | xargs -r rm -f
1655
+ fi
1656
+ fi
1657
+
1658
+ # ── Stage 4: wipe raft state + env files ─────────────────────────────
1659
+ ${SUDO} rm -rf "${JISHUSHELL_HOME}/nomad/data"
1660
+ rm -f "${JISHUSHELL_HOME}/nomad.env"
1661
+ ${SUDO} rm -f /etc/jishushell/nomad.env
1662
+
1663
+ # ── Stage 5: orphaned gateway containers (alloc ids gone with raft) ──
1664
+ # sudo npm install -g runs postinstall as the invoking user (typically pi),
1665
+ # whose login shell may not have docker group access — the legacy install
1666
+ # only granted docker to the nomad.service via SupplementaryGroups, not to
1667
+ # the login shell. Try unprivileged first, fall back to sudo docker so this
1668
+ # step works regardless of group membership.
1669
+ if command -v docker &>/dev/null; then
1670
+ local _docker="docker"
1671
+ if ! docker ps >/dev/null 2>&1; then
1672
+ _docker="${SUDO} docker"
1673
+ fi
1674
+ local gw_containers
1675
+ gw_containers="$($_docker ps -a --format '{{.Names}}' 2>/dev/null | grep '^gateway-' || true)"
1676
+ if [[ -n "$gw_containers" ]]; then
1677
+ local gw_count
1678
+ gw_count="$(echo "$gw_containers" | wc -l)"
1679
+ echo "$gw_containers" | xargs -r $_docker rm -f >/dev/null 2>&1 || true
1680
+ ui_info "Removed ${gw_count} orphaned gateway container(s)"
1681
+ fi
1682
+ fi
1683
+
1684
+ # ── Stage 6: swap binary into place (atomic via temp name + rename) ──
1685
+ mkdir -p "${JISHUSHELL_BIN_DIR}"
1686
+ local dest_tmp="${local_bin}.tmp.$$"
1687
+ if ! cp "${stage_dir}/nomad" "$dest_tmp"; then
1688
+ ui_error "Failed to copy new Nomad binary into place"
1689
+ [[ -n "$backup_file" ]] && ui_error " Backup preserved at: ${backup_file}"
1690
+ return 1
1691
+ fi
1692
+ chmod 755 "$dest_tmp"
1693
+ if ! mv -f "$dest_tmp" "$local_bin"; then
1694
+ ui_error "Failed to swap Nomad binary"
1695
+ [[ -n "$backup_file" ]] && ui_error " Backup preserved at: ${backup_file}"
1696
+ rm -f "$dest_tmp"
1697
+ return 1
1698
+ fi
1699
+
1700
+ ui_success "Nomad migrated to v${NOMAD_VERSION}"
1701
+ [[ -n "$backup_file" ]] && ui_info " Backup (forensic, not self-recovery): ${backup_file}"
1702
+ ui_info " JishuShell will re-bootstrap ACL and resubmit jobs from instance configs on next start."
1703
+ return 0
1704
+ }
1705
+
1507
1706
  _install_nomad_binary() {
1508
1707
  local dest="${JISHUSHELL_BIN_DIR}/nomad"
1509
1708
 
@@ -1688,8 +1887,25 @@ _ensure_nomad_hcl() {
1688
1887
  # LAN IP doesn't exist inside the Lima VM, causing "cannot assign requested
1689
1888
  # address" when Docker tries to bind to it.
1690
1889
  local loopback_iface="lo"
1890
+ local external_iface=""
1891
+ local external_host_network_block=""
1691
1892
  [[ "$OS" == "macos" ]] && loopback_iface="lo0"
1692
1893
 
1894
+ if [[ "$OS" == "macos" ]]; then
1895
+ external_iface="$(route -n get default 2>/dev/null | awk '/interface:/{print $2; exit}')"
1896
+ elif command -v ip >/dev/null 2>&1; then
1897
+ external_iface="$(ip route show default 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}')"
1898
+ fi
1899
+
1900
+ if [[ -n "$external_iface" && "$external_iface" != "$loopback_iface" ]]; then
1901
+ external_host_network_block=$(cat <<EOF
1902
+ host_network "external" {
1903
+ interface = "${external_iface}"
1904
+ }
1905
+ EOF
1906
+ )
1907
+ fi
1908
+
1693
1909
  cat > "$config_file" << NOMAD_HCL
1694
1910
  data_dir = "${nomad_data_dir}"
1695
1911
 
@@ -1713,6 +1929,7 @@ client {
1713
1929
  servers = ["127.0.0.1:4647"]
1714
1930
  network_interface = "${loopback_iface}"
1715
1931
  alloc_dir = "${nomad_alloc_dir}"
1932
+ ${external_host_network_block}
1716
1933
 
1717
1934
  drain_on_shutdown {
1718
1935
  deadline = "30s"
@@ -1849,14 +2066,17 @@ install_nomad_systemd() {
1849
2066
 
1850
2067
  _ensure_nomad_hcl
1851
2068
 
2069
+ # Nomad 1.6.5's docker driver fingerprint requires euid==0 (PR #18197 lifted
2070
+ # the root requirement only in 1.7+, which is BSL). The panel stays as the
2071
+ # installing user via a separate unit; it talks to this agent over HTTP so
2072
+ # ~/.jishushell/nomad/data/ can be root-owned without breaking anything.
1852
2073
  local service_content="[Unit]
1853
2074
  Description=Nomad Agent
1854
2075
  After=network-online.target docker.service
1855
2076
  Wants=network-online.target
1856
2077
 
1857
2078
  [Service]
1858
- User=${REAL_USER}
1859
- SupplementaryGroups=docker
2079
+ User=root
1860
2080
  Type=simple
1861
2081
  EnvironmentFile=-/etc/jishushell/nomad.env
1862
2082
  ExecStart=${nomad_bin} agent -config=${config_file}
@@ -1879,8 +2099,12 @@ WantedBy=multi-user.target"
1879
2099
  need_reload=1
1880
2100
  fi
1881
2101
 
1882
- # Ensure Nomad data dirs are owned by the real user before the service starts
2102
+ # Keep the real user owning ~/.jishushell except for Nomad's own state,
2103
+ # which must be root-owned because the agent runs as root for driver fingerprinting.
1883
2104
  chown -R "${REAL_USER}:${REAL_GID:-${REAL_USER}}" "${JISHUSHELL_HOME}" 2>/dev/null || true
2105
+ if [[ -d "${nomad_config_dir}/data" ]]; then
2106
+ ${SUDO} chown -R root:root "${nomad_config_dir}/data" 2>/dev/null || true
2107
+ fi
1884
2108
 
1885
2109
  if [[ $need_reload -eq 1 ]]; then
1886
2110
  ${SUDO} systemctl daemon-reload
@@ -2211,6 +2435,14 @@ _prompt_openclaw_skip() {
2211
2435
  esac
2212
2436
  }
2213
2437
 
2438
+ jishushell_package_spec() {
2439
+ if [[ "${JISHUSHELL_VERSION_OVERRIDE}" == "1" || "${JISHUSHELL_NPM_VERSION}" != "latest" ]]; then
2440
+ printf 'jishushell@%s' "${JISHUSHELL_NPM_VERSION}"
2441
+ return 0
2442
+ fi
2443
+ printf 'jishushell'
2444
+ }
2445
+
2214
2446
  # show_install_plan [--with-jishushell]
2215
2447
  show_install_plan() {
2216
2448
  local with_jishushell=0
@@ -2226,17 +2458,19 @@ show_install_plan() {
2226
2458
  ui_kv "Node.js" "$(if [[ $SKIP_NODE -eq 1 ]]; then echo 'skip'; else echo "v${NODE_VERSION} via nvm v${NVM_VERSION}"; fi)"
2227
2459
  ui_kv "Docker" "$(if [[ $SKIP_DOCKER -eq 1 ]]; then echo 'skip'; else echo 'latest stable'; fi)"
2228
2460
  ui_kv "Nomad" "$(if [[ $SKIP_NOMAD -eq 1 ]]; then echo 'skip'; else echo "v${NOMAD_VERSION}"; fi)"
2229
- ui_kv "OpenClaw" "$(if [[ \"${SKIP_OPENCLAW}\" == \"1\" ]]; then echo 'skip'; else echo \"docker pull ${OPENCLAW_DOCKER_TAG}\"; fi)"
2461
+ ui_kv "OpenClaw" "$(if [[ "${SKIP_OPENCLAW}" == "1" ]]; then echo 'skip'; else echo "docker pull ${OPENCLAW_DOCKER_TAG}"; fi)"
2230
2462
  if [[ $with_jishushell -eq 1 ]]; then
2231
2463
  local _plan_jishu
2232
2464
  if [[ $SKIP_JISHUSHELL -eq 1 ]]; then
2233
2465
  _plan_jishu="skip"
2234
2466
  else
2235
2467
  local _plan_tgz=""
2236
- for _c in "${JISHU_SCRIPT_DIR}"/jishushell-*.tgz; do
2237
- [[ -f "$_c" ]] && { _plan_tgz="$(basename "$_c")"; break; }
2238
- done
2239
- _plan_jishu="${_plan_tgz:+npm install -g ${_plan_tgz} (local)}${_plan_tgz:-npm install -g jishushell}"
2468
+ if [[ "${JISHUSHELL_VERSION_OVERRIDE}" != "1" && "${JISHUSHELL_NPM_VERSION}" == "latest" ]]; then
2469
+ for _c in "${JISHU_SCRIPT_DIR}"/jishushell-*.tgz; do
2470
+ [[ -f "$_c" ]] && { _plan_tgz="$(basename "$_c")"; break; }
2471
+ done
2472
+ fi
2473
+ _plan_jishu="${_plan_tgz:+npm install -g ${_plan_tgz} (local)}${_plan_tgz:-npm install -g $(jishushell_package_spec)}"
2240
2474
  fi
2241
2475
  ui_kv "JishuShell" "$_plan_jishu"
2242
2476
  ui_kv "JishuShell service" "$(if [[ $SKIP_JISHUSHELL_SERVICE -eq 1 ]]; then echo 'skip'; else echo 'register autostart'; fi)"
@@ -2401,16 +2635,20 @@ install_jishushell() {
2401
2635
  fi
2402
2636
 
2403
2637
  if [[ "$DRY_RUN" == "1" ]]; then
2638
+ local jishushell_pkg_spec
2639
+ jishushell_pkg_spec="$(jishushell_package_spec)"
2404
2640
  local _dry_reg=""
2405
2641
  [[ -n "${NPM_REGISTRY:-}" ]] && _dry_reg=" --registry ${NPM_REGISTRY}"
2406
2642
  local _dry_tgz=""
2407
- for _c in "${JISHU_SCRIPT_DIR}"/jishushell-*.tgz; do
2408
- [[ -f "$_c" ]] && { _dry_tgz="$_c"; break; }
2409
- done
2643
+ if [[ "${JISHUSHELL_VERSION_OVERRIDE}" != "1" && "${JISHUSHELL_NPM_VERSION}" == "latest" ]]; then
2644
+ for _c in "${JISHU_SCRIPT_DIR}"/jishushell-*.tgz; do
2645
+ [[ -f "$_c" ]] && { _dry_tgz="$_c"; break; }
2646
+ done
2647
+ fi
2410
2648
  if [[ -n "$_dry_tgz" ]]; then
2411
2649
  ui_info "[dry-run] Would: npm install -g ${_dry_tgz} (local package)"
2412
2650
  else
2413
- ui_info "[dry-run] Would: npm install -g jishushell${_dry_reg}"
2651
+ ui_info "[dry-run] Would: npm install -g ${jishushell_pkg_spec}${_dry_reg}"
2414
2652
  fi
2415
2653
  ui_info "[dry-run] Would write wrapper: ${JISHUSHELL_BIN_DIR}/jishushell-panel-start"
2416
2654
  return 0
@@ -2441,6 +2679,8 @@ install_jishushell() {
2441
2679
  return 1
2442
2680
  fi
2443
2681
 
2682
+ local jishushell_pkg_spec
2683
+ jishushell_pkg_spec="$(jishushell_package_spec)"
2444
2684
  local npm_registry_args=()
2445
2685
  if [[ -n "${NPM_REGISTRY:-}" ]]; then
2446
2686
  if [[ ! "$NPM_REGISTRY" =~ ^https?:// ]]; then
@@ -2448,9 +2688,9 @@ install_jishushell() {
2448
2688
  return 1
2449
2689
  fi
2450
2690
  npm_registry_args=("--registry" "${NPM_REGISTRY}")
2451
- ui_info "Installing jishushell from ${NPM_REGISTRY}..."
2691
+ ui_info "Installing ${jishushell_pkg_spec} from ${NPM_REGISTRY}..."
2452
2692
  else
2453
- ui_info "Installing jishushell from public npm registry..."
2693
+ ui_info "Installing ${jishushell_pkg_spec} from public npm registry..."
2454
2694
  fi
2455
2695
 
2456
2696
  # When jishushell is already installed (e.g. running as npm postinstall hook),
@@ -2459,12 +2699,14 @@ install_jishushell() {
2459
2699
  # Prefer a local .tgz package in the same directory as this script.
2460
2700
  local tgz_path=""
2461
2701
  local _tgz_candidate
2462
- for _tgz_candidate in "${JISHU_SCRIPT_DIR}"/jishushell-*.tgz; do
2463
- if [[ -f "$_tgz_candidate" ]]; then
2464
- tgz_path="$_tgz_candidate"
2465
- break
2466
- fi
2467
- done
2702
+ if [[ "${JISHUSHELL_VERSION_OVERRIDE}" != "1" && "${JISHUSHELL_NPM_VERSION}" == "latest" ]]; then
2703
+ for _tgz_candidate in "${JISHU_SCRIPT_DIR}"/jishushell-*.tgz; do
2704
+ if [[ -f "$_tgz_candidate" ]]; then
2705
+ tgz_path="$_tgz_candidate"
2706
+ break
2707
+ fi
2708
+ done
2709
+ fi
2468
2710
 
2469
2711
  # Export a sentinel so post-install.sh (triggered by npm's postinstall
2470
2712
  # lifecycle hook) knows it was launched from inside jishu-install.sh and
@@ -2480,10 +2722,16 @@ install_jishushell() {
2480
2722
  return 1
2481
2723
  fi
2482
2724
  else
2483
- log_detail "[$(date '+%H:%M:%S')] ${npm_bin} install -g jishushell ${npm_registry_args[*]:-}"
2484
- if ! log_cmd "$npm_bin" install -g jishushell ${npm_registry_args[@]+"${npm_registry_args[@]}"}; then
2725
+ log_detail "[$(date '+%H:%M:%S')] ${npm_bin} install -g ${jishushell_pkg_spec} ${npm_registry_args[*]:-}"
2726
+ if [[ ${#npm_registry_args[@]} -gt 0 ]]; then
2727
+ if ! log_cmd "$npm_bin" install -g "${jishushell_pkg_spec}" "${npm_registry_args[@]}"; then
2728
+ unset JISHU_RUNNING_IN_INSTALLER
2729
+ ui_error "npm install -g ${jishushell_pkg_spec} failed"
2730
+ return 1
2731
+ fi
2732
+ elif ! log_cmd "$npm_bin" install -g "${jishushell_pkg_spec}"; then
2485
2733
  unset JISHU_RUNNING_IN_INSTALLER
2486
- ui_error "npm install -g jishushell failed"
2734
+ ui_error "npm install -g ${jishushell_pkg_spec} failed"
2487
2735
  return 1
2488
2736
  fi
2489
2737
  fi
@@ -2620,7 +2868,6 @@ Environment=HOME=${REAL_HOME}
2620
2868
  Environment=JISHUSHELL_HOME=${JISHUSHELL_HOME}
2621
2869
  ProtectSystem=strict
2622
2870
  PrivateTmp=true
2623
- NoNewPrivileges=true
2624
2871
  ReadWritePaths=${JISHUSHELL_HOME} /etc/jishushell
2625
2872
 
2626
2873
  [Install]
@@ -2787,8 +3034,17 @@ parse_args() {
2787
3034
  shift
2788
3035
  OPENCLAW_NPM_VERSION="${1:?--openclaw-version requires a version argument (e.g. 3.24)}"
2789
3036
  ;;
3037
+ --openclaw-docker-tag)
3038
+ shift
3039
+ OPENCLAW_DOCKER_TAG="${1:?--openclaw-docker-tag requires a tag argument (e.g. ghcr.io/x-aijishu/openclaw-runtime:2026.4.9)}"
3040
+ ;;
2790
3041
  --skip-jishushell) SKIP_JISHUSHELL=1 ;;
2791
3042
  --skip-jishushell-service) SKIP_JISHUSHELL_SERVICE=1 ;;
3043
+ --jishushell-version)
3044
+ shift
3045
+ JISHUSHELL_NPM_VERSION="${1:?--jishushell-version requires a version argument (e.g. 0.4.9)}"
3046
+ JISHUSHELL_VERSION_OVERRIDE=1
3047
+ ;;
2792
3048
  --skip)
2793
3049
  shift
2794
3050
  IFS=',' read -ra _steps <<< "${1:-}"
@@ -2854,10 +3110,16 @@ Options:
2854
3110
  --skip-docker Skip step 2: Docker installation
2855
3111
  --skip-nomad Skip step 3: Nomad installation
2856
3112
  --skip-openclaw Skip step 4: OpenClaw installation
3113
+ --openclaw-docker-tag <tag>
3114
+ Pull a specific OpenClaw image tag
3115
+ (e.g. --openclaw-docker-tag ghcr.io/x-aijishu/openclaw-runtime:2026.4.9)
2857
3116
  --skip-jishushell Skip step 5: JishuShell installation
2858
3117
  --skip-jishushell-service Skip step 6: JishuShell service registration
3118
+ --jishushell-version <ver>
3119
+ Install a specific jishushell version
3120
+ (e.g. --jishushell-version 0.4.9)
2859
3121
  --registry <url> Use a custom npm registry for all installs
2860
- (e.g. --registry http://10.188.0.22:4873/)
3122
+ (e.g. --registry http://127.0.0.1:4873/)
2861
3123
  --yes, -y Skip all confirmation prompts
2862
3124
  --help, -h Show this help message
2863
3125
 
@@ -2873,12 +3135,16 @@ Environment variables:
2873
3135
  JISHU_NODE_VERSION Specify Node.js major version (default: ${NODE_VERSION})
2874
3136
  JISHU_NVM_VERSION Specify nvm version (default: ${NVM_VERSION})
2875
3137
  JISHU_NOMAD_VERSION Specify Nomad version (default: ${NOMAD_VERSION})
3138
+ JISHUSHELL_NPM_VERSION
3139
+ Specify jishushell npm package version (default: latest)
2876
3140
  OPENCLAW_NPM_VERSION Specify openclaw npm package version (default: latest)
2877
- OPENCLAW_DOCKER_TAG Override built Docker image tag (default: jishushell-base:v1)
3141
+ OPENCLAW_DOCKER_TAG Override OpenClaw Docker image tag (default: ${OPENCLAW_DOCKER_TAG})
2878
3142
  NPM_REGISTRY Custom npm registry URL (same as --registry flag)
2879
3143
 
2880
- OpenClaw version flag (equivalent to OPENCLAW_NPM_VERSION env var):
2881
- --openclaw-version <ver> Install a specific openclaw version, e.g. --openclaw-version 3.24
3144
+ Version flags:
3145
+ --jishushell-version <ver> Install a specific jishushell version, e.g. --jishushell-version 0.4.9
3146
+ --openclaw-version <ver> Install a specific openclaw version, e.g. --openclaw-version 3.24
3147
+ --openclaw-docker-tag <tag> Pull a specific OpenClaw image tag, e.g. --openclaw-docker-tag ghcr.io/x-aijishu/openclaw-runtime:2026.4.9
2882
3148
  NO_PROMPT Set to 1 to skip interactive prompts
2883
3149
  VERBOSE Set to 1 for verbose output
2884
3150
 
@@ -2948,12 +3214,11 @@ _prompt_install_confirm() {
2948
3214
  fi
2949
3215
  if [[ $SKIP_NOMAD -eq 0 ]]; then
2950
3216
  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}"
3217
+ echo -e " ${MUTED} Nomad v${NOMAD_VERSION} (last MPL 2.0 release in the 1.6.x line)${NC}"
3218
+ echo -e " ${MUTED} URL : https://github.com/hashicorp/nomad/tree/v${NOMAD_VERSION}${NC}"
3219
+ echo -e " ${MUTED} License : Mozilla Public License 2.0${NC}"
3220
+ echo -e " ${MUTED} https://github.com/hashicorp/nomad/blob/v${NOMAD_VERSION}/LICENSE${NC}"
3221
+ echo -e " ${MUTED} Author : HashiCorp, Inc.${NC}"
2957
3222
  echo ""
2958
3223
  fi
2959
3224
  echo -e " ${ACCENT}─────────────────────────────────────────────────────────${NC}"