jishushell 0.4.24 → 0.5.15

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 (281) hide show
  1. package/INSTALL-NOTICE +11 -0
  2. package/apps/anythingllm-container.yaml +287 -0
  3. package/apps/browserless-chromium-container.yaml +90 -0
  4. package/apps/filebrowser-container.yaml +163 -0
  5. package/apps/hermes-container.yaml +36 -2
  6. package/apps/ollama-binary.yaml +91 -90
  7. package/apps/ollama-cpu-container.yaml +8 -1
  8. package/apps/ollama-with-hollama-binary.yaml +91 -90
  9. package/apps/openclaw-binary.yaml +38 -1
  10. package/apps/openclaw-container.yaml +45 -2
  11. package/apps/openclaw-with-ollama-container.yaml +11 -2
  12. package/apps/openclaw-with-searxng-container.yaml +26 -2
  13. package/apps/openwebui-container.yaml +45 -1
  14. package/apps/playwright-container.yaml +7 -1
  15. package/apps/searxng-container.yaml +58 -7
  16. package/apps/weknora-container.yaml +471 -0
  17. package/dist/cli/app.js +79 -9
  18. package/dist/cli/app.js.map +1 -1
  19. package/dist/cli/doctor.d.ts +12 -12
  20. package/dist/cli/doctor.js +242 -55
  21. package/dist/cli/doctor.js.map +1 -1
  22. package/dist/cli/llm.d.ts +4 -3
  23. package/dist/cli/llm.js +4 -3
  24. package/dist/cli/llm.js.map +1 -1
  25. package/dist/cli/panel.d.ts +6 -5
  26. package/dist/cli/panel.js +10 -9
  27. package/dist/cli/panel.js.map +1 -1
  28. package/dist/config.d.ts +19 -0
  29. package/dist/config.js +99 -1
  30. package/dist/config.js.map +1 -1
  31. package/dist/control.d.ts +7 -6
  32. package/dist/control.js +7 -6
  33. package/dist/control.js.map +1 -1
  34. package/dist/install.js +3 -3
  35. package/dist/install.js.map +1 -1
  36. package/dist/routes/agent-apps.d.ts +1 -1
  37. package/dist/routes/agent-apps.js +1 -1
  38. package/dist/routes/apps.js +44 -11
  39. package/dist/routes/apps.js.map +1 -1
  40. package/dist/routes/auth.js +5 -2
  41. package/dist/routes/auth.js.map +1 -1
  42. package/dist/routes/backup.js +64 -11
  43. package/dist/routes/backup.js.map +1 -1
  44. package/dist/routes/external-mounts.d.ts +17 -0
  45. package/dist/routes/external-mounts.js +73 -0
  46. package/dist/routes/external-mounts.js.map +1 -0
  47. package/dist/routes/file-mounts.d.ts +13 -0
  48. package/dist/routes/file-mounts.js +90 -0
  49. package/dist/routes/file-mounts.js.map +1 -0
  50. package/dist/routes/files-organize.d.ts +28 -0
  51. package/dist/routes/files-organize.js +167 -0
  52. package/dist/routes/files-organize.js.map +1 -0
  53. package/dist/routes/files.d.ts +31 -0
  54. package/dist/routes/files.js +321 -0
  55. package/dist/routes/files.js.map +1 -0
  56. package/dist/routes/instances.js +826 -17
  57. package/dist/routes/instances.js.map +1 -1
  58. package/dist/routes/internal.d.ts +2 -0
  59. package/dist/routes/internal.js +59 -0
  60. package/dist/routes/internal.js.map +1 -0
  61. package/dist/routes/llm.js +24 -35
  62. package/dist/routes/llm.js.map +1 -1
  63. package/dist/routes/setup.js +10 -10
  64. package/dist/routes/setup.js.map +1 -1
  65. package/dist/routes/system.js +1 -1
  66. package/dist/routes/system.js.map +1 -1
  67. package/dist/routes/webdav.d.ts +17 -0
  68. package/dist/routes/webdav.js +114 -0
  69. package/dist/routes/webdav.js.map +1 -0
  70. package/dist/server.d.ts +9 -0
  71. package/dist/server.js +751 -20
  72. package/dist/server.js.map +1 -1
  73. package/dist/services/agent-apps/catalog.js +4 -3
  74. package/dist/services/agent-apps/catalog.js.map +1 -1
  75. package/dist/services/agent-apps/index.d.ts +1 -1
  76. package/dist/services/agent-apps/index.js +1 -1
  77. package/dist/services/agent-apps/installers/adapter.d.ts +1 -1
  78. package/dist/services/agent-apps/installers/adapter.js +1 -1
  79. package/dist/services/agent-apps/installers/shell-script.d.ts +1 -1
  80. package/dist/services/agent-apps/installers/shell-script.js +3 -3
  81. package/dist/services/agent-apps/installers/shell-script.js.map +1 -1
  82. package/dist/services/agent-apps/types.d.ts +2 -2
  83. package/dist/services/agent-apps/types.js +1 -1
  84. package/dist/services/app/app-compiler.d.ts +1 -1
  85. package/dist/services/app/app-compiler.js +5 -5
  86. package/dist/services/app/app-compiler.js.map +1 -1
  87. package/dist/services/app/app-manager.d.ts +25 -1
  88. package/dist/services/app/app-manager.js +829 -150
  89. package/dist/services/app/app-manager.js.map +1 -1
  90. package/dist/services/app/custom-manager.js.map +1 -1
  91. package/dist/services/app/hermes-agent-manager.js +7 -4
  92. package/dist/services/app/hermes-agent-manager.js.map +1 -1
  93. package/dist/services/app/ollama-manager.js +1 -1
  94. package/dist/services/app/ollama-manager.js.map +1 -1
  95. package/dist/services/app/openclaw-manager.js +20 -3
  96. package/dist/services/app/openclaw-manager.js.map +1 -1
  97. package/dist/services/app/platform-transform.d.ts +32 -0
  98. package/dist/services/app/platform-transform.js +65 -0
  99. package/dist/services/app/platform-transform.js.map +1 -0
  100. package/dist/services/app/provide-resolver.d.ts +29 -0
  101. package/dist/services/app/provide-resolver.js +112 -0
  102. package/dist/services/app/provide-resolver.js.map +1 -0
  103. package/dist/services/app-passwords.d.ts +61 -0
  104. package/dist/services/app-passwords.js +173 -0
  105. package/dist/services/app-passwords.js.map +1 -0
  106. package/dist/services/backup-manager.d.ts +11 -0
  107. package/dist/services/backup-manager.js +177 -4
  108. package/dist/services/backup-manager.js.map +1 -1
  109. package/dist/services/capability-endpoint-validator.d.ts +41 -0
  110. package/dist/services/capability-endpoint-validator.js +104 -0
  111. package/dist/services/capability-endpoint-validator.js.map +1 -0
  112. package/dist/services/capability-health.d.ts +16 -0
  113. package/dist/services/capability-health.js +121 -0
  114. package/dist/services/capability-health.js.map +1 -0
  115. package/dist/services/capability-registry.d.ts +106 -0
  116. package/dist/services/capability-registry.js +313 -0
  117. package/dist/services/capability-registry.js.map +1 -0
  118. package/dist/services/connection-apply.d.ts +91 -0
  119. package/dist/services/connection-apply.js +475 -0
  120. package/dist/services/connection-apply.js.map +1 -0
  121. package/dist/services/connection-resolver.d.ts +65 -0
  122. package/dist/services/connection-resolver.js +281 -0
  123. package/dist/services/connection-resolver.js.map +1 -0
  124. package/dist/services/connection-transactor.d.ts +39 -0
  125. package/dist/services/connection-transactor.js +351 -0
  126. package/dist/services/connection-transactor.js.map +1 -0
  127. package/dist/services/external-mounts.d.ts +40 -0
  128. package/dist/services/external-mounts.js +187 -0
  129. package/dist/services/external-mounts.js.map +1 -0
  130. package/dist/services/files-manager.d.ts +252 -0
  131. package/dist/services/files-manager.js +1075 -0
  132. package/dist/services/files-manager.js.map +1 -0
  133. package/dist/services/files-mounts.d.ts +42 -0
  134. package/dist/services/files-mounts.js +207 -0
  135. package/dist/services/files-mounts.js.map +1 -0
  136. package/dist/services/instance-manager.d.ts +13 -0
  137. package/dist/services/instance-manager.js +138 -46
  138. package/dist/services/instance-manager.js.map +1 -1
  139. package/dist/services/llm-proxy/index.d.ts +16 -2
  140. package/dist/services/llm-proxy/index.js +48 -44
  141. package/dist/services/llm-proxy/index.js.map +1 -1
  142. package/dist/services/llm-proxy/probe.d.ts +6 -0
  143. package/dist/services/llm-proxy/probe.js +85 -0
  144. package/dist/services/llm-proxy/probe.js.map +1 -0
  145. package/dist/services/llm-proxy/ssrf.d.ts +1 -0
  146. package/dist/services/llm-proxy/ssrf.js +24 -9
  147. package/dist/services/llm-proxy/ssrf.js.map +1 -1
  148. package/dist/services/nomad-manager.d.ts +4 -0
  149. package/dist/services/nomad-manager.js +428 -35
  150. package/dist/services/nomad-manager.js.map +1 -1
  151. package/dist/services/organize/applier.d.ts +46 -0
  152. package/dist/services/organize/applier.js +218 -0
  153. package/dist/services/organize/applier.js.map +1 -0
  154. package/dist/services/organize/rules.d.ts +57 -0
  155. package/dist/services/organize/rules.js +286 -0
  156. package/dist/services/organize/rules.js.map +1 -0
  157. package/dist/services/organize/scanner.d.ts +50 -0
  158. package/dist/services/organize/scanner.js +366 -0
  159. package/dist/services/organize/scanner.js.map +1 -0
  160. package/dist/services/organize/store.d.ts +14 -0
  161. package/dist/services/organize/store.js +82 -0
  162. package/dist/services/organize/store.js.map +1 -0
  163. package/dist/services/panel-manager.js +20 -1
  164. package/dist/services/panel-manager.js.map +1 -1
  165. package/dist/services/process-manager.js +4 -3
  166. package/dist/services/process-manager.js.map +1 -1
  167. package/dist/services/runtime/adapters/hermes.d.ts +30 -1
  168. package/dist/services/runtime/adapters/hermes.js +219 -6
  169. package/dist/services/runtime/adapters/hermes.js.map +1 -1
  170. package/dist/services/runtime/adapters/openclaw-mcporter.d.ts +45 -0
  171. package/dist/services/runtime/adapters/openclaw-mcporter.js +108 -0
  172. package/dist/services/runtime/adapters/openclaw-mcporter.js.map +1 -0
  173. package/dist/services/runtime/adapters/openclaw-routes.d.ts +8 -2
  174. package/dist/services/runtime/adapters/openclaw-routes.js +68 -0
  175. package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -1
  176. package/dist/services/runtime/adapters/openclaw.d.ts +177 -0
  177. package/dist/services/runtime/adapters/openclaw.js +1171 -11
  178. package/dist/services/runtime/adapters/openclaw.js.map +1 -1
  179. package/dist/services/runtime/instance.d.ts +1 -1
  180. package/dist/services/runtime/instance.js +1 -1
  181. package/dist/services/runtime/instance.js.map +1 -1
  182. package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +46 -0
  183. package/dist/services/runtime/mcp-shims/anythingllm-shim.js +281 -0
  184. package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +1 -0
  185. package/dist/services/runtime/mcp-shims/drive-shim.d.ts +54 -0
  186. package/dist/services/runtime/mcp-shims/drive-shim.js +489 -0
  187. package/dist/services/runtime/mcp-shims/drive-shim.js.map +1 -0
  188. package/dist/services/runtime/mcp-shims/firewall.d.ts +26 -0
  189. package/dist/services/runtime/mcp-shims/firewall.js +129 -0
  190. package/dist/services/runtime/mcp-shims/firewall.js.map +1 -0
  191. package/dist/services/runtime/mcp-shims/searxng-shim.d.ts +27 -0
  192. package/dist/services/runtime/mcp-shims/searxng-shim.js +125 -0
  193. package/dist/services/runtime/mcp-shims/searxng-shim.js.map +1 -0
  194. package/dist/services/runtime/mcp-shims/write-mcp-entry.d.ts +83 -0
  195. package/dist/services/runtime/mcp-shims/write-mcp-entry.js +127 -0
  196. package/dist/services/runtime/mcp-shims/write-mcp-entry.js.map +1 -0
  197. package/dist/services/runtime/migrations.d.ts +8 -0
  198. package/dist/services/runtime/migrations.js +100 -0
  199. package/dist/services/runtime/migrations.js.map +1 -1
  200. package/dist/services/runtime/types.d.ts +46 -0
  201. package/dist/services/setup-manager.js +99 -24
  202. package/dist/services/setup-manager.js.map +1 -1
  203. package/dist/services/suggestions.d.ts +27 -0
  204. package/dist/services/suggestions.js +133 -0
  205. package/dist/services/suggestions.js.map +1 -0
  206. package/dist/services/task-registry.js +4 -2
  207. package/dist/services/task-registry.js.map +1 -1
  208. package/dist/services/telemetry/device-fingerprint.d.ts +1 -1
  209. package/dist/services/telemetry/device-fingerprint.js +1 -1
  210. package/dist/services/types-shim.d.ts +16 -0
  211. package/dist/services/types-shim.js +2 -0
  212. package/dist/services/types-shim.js.map +1 -0
  213. package/dist/services/webdav/server.d.ts +24 -0
  214. package/dist/services/webdav/server.js +420 -0
  215. package/dist/services/webdav/server.js.map +1 -0
  216. package/dist/services/webdav/xml-builder.d.ts +73 -0
  217. package/dist/services/webdav/xml-builder.js +156 -0
  218. package/dist/services/webdav/xml-builder.js.map +1 -0
  219. package/dist/services/workspace-builder.d.ts +29 -0
  220. package/dist/services/workspace-builder.js +188 -0
  221. package/dist/services/workspace-builder.js.map +1 -0
  222. package/dist/types.d.ts +231 -1
  223. package/dist/utils/instance-lock.d.ts +22 -0
  224. package/dist/utils/instance-lock.js +48 -0
  225. package/dist/utils/instance-lock.js.map +1 -0
  226. package/dist/utils/path-locks.d.ts +30 -0
  227. package/dist/utils/path-locks.js +63 -0
  228. package/dist/utils/path-locks.js.map +1 -0
  229. package/dist/utils/path-safety.d.ts +41 -0
  230. package/dist/utils/path-safety.js +119 -0
  231. package/dist/utils/path-safety.js.map +1 -0
  232. package/dist/utils/safe-json.js +55 -22
  233. package/dist/utils/safe-json.js.map +1 -1
  234. package/dist/utils/safe-write.d.ts +24 -0
  235. package/dist/utils/safe-write.js +82 -0
  236. package/dist/utils/safe-write.js.map +1 -0
  237. package/install/jishu-install.sh +323 -27
  238. package/install/jishu-uninstall.sh +353 -20
  239. package/package.json +18 -1
  240. package/public/assets/Dashboard-BdWPtroF.js +1 -0
  241. package/public/assets/{HermesChatPanel-mFSureyc.js → HermesChatPanel-B_2HlVBQ.js} +1 -1
  242. package/public/assets/HermesConfigForm-DVlhg3WV.js +4 -0
  243. package/public/assets/{InitPassword-CVA8wQA6.js → InitPassword-D7glTExX.js} +1 -1
  244. package/public/assets/InstanceDetail-CxSy2cpe.js +92 -0
  245. package/public/assets/{Login-BWsZH2mu.js → Login-Cfr5c2sv.js} +1 -1
  246. package/public/assets/NewInstance-BIYDmJis.js +1 -0
  247. package/public/assets/ProviderRecommendations-BuRnvRcI.js +1 -0
  248. package/public/assets/Settings-Cc-tYBil.js +1 -0
  249. package/public/assets/Setup-lGZEk5jq.js +1 -0
  250. package/public/assets/{WeixinLoginPanel-CnjR8xMu.js → WeixinLoginPanel-CoGqzxeV.js} +2 -2
  251. package/public/assets/index-87IJXG-w.css +1 -0
  252. package/public/assets/index-BZc5zH7u.js +19 -0
  253. package/public/assets/providers-DtNXh9JD.js +1 -0
  254. package/public/assets/registry-BWnkJgZ1.js +2 -0
  255. package/public/assets/{usePolling-Do5Erqm_.js → usePolling-CwwT9KrC.js} +1 -1
  256. package/public/assets/{vendor-i18n-ucpM0OR0.js → vendor-i18n-y9V7Sfuu.js} +1 -1
  257. package/public/assets/{vendor-react-Bk1hRGiY.js → vendor-react-BWrEVJVb.js} +6 -6
  258. package/public/index.html +4 -4
  259. package/scripts/check-app-spec.mjs +457 -0
  260. package/scripts/check-i18n.mjs +154 -0
  261. package/scripts/check-new-file-tests.mjs +230 -0
  262. package/scripts/check-quarantine-expiry.mjs +105 -0
  263. package/scripts/perf/README.md +49 -0
  264. package/scripts/perf/auth.js +99 -0
  265. package/scripts/perf/config.js +63 -0
  266. package/scripts/perf/instances.js +143 -0
  267. package/scripts/perf/proxy.js +96 -0
  268. package/scripts/run.sh +4 -4
  269. package/scripts/smoke/files-w1.sh +142 -0
  270. package/scripts/smoke-backend.mjs +122 -0
  271. package/scripts/smoke-post-publish.mjs +346 -0
  272. package/public/assets/Dashboard-B-JoOjBQ.js +0 -1
  273. package/public/assets/HermesConfigForm-DvR05LK1.js +0 -4
  274. package/public/assets/InstanceDetail-DcZW2QGO.js +0 -91
  275. package/public/assets/NewInstance-BCIrAd86.js +0 -1
  276. package/public/assets/Settings-xkDcduFz.js +0 -1
  277. package/public/assets/Setup-Cfuwj4gV.js +0 -1
  278. package/public/assets/index-CPhVFEsx.css +0 -1
  279. package/public/assets/index-DQsM6Joa.js +0 -19
  280. package/public/assets/providers-V-vwrExZ.js +0 -1
  281. package/public/assets/registry-B4UFJdpA.js +0 -2
@@ -1,16 +1,16 @@
1
1
  /**
2
- * JishuShell Doctor — 环境诊断与自动修复
2
+ * JishuShell Doctor — environment diagnostics and auto-fix.
3
3
  *
4
- * 用法:
5
- * jishushell doctor 检查所有组件状态
6
- * jishushell doctor --fix 检查并尝试自动修复
4
+ * Usage:
5
+ * jishushell doctor inspect all components
6
+ * jishushell doctor --fix inspect and attempt to auto-repair
7
7
  *
8
- * Nomad 检查依据 install/jishu-install.sh src/services/setup-manager.ts
9
- * - 二进制路径: ~/.jishushell/bin/nomad (v1.6.5)
10
- * - 配置文件: ~/.jishushell/nomad/nomad.hcl
11
- * - 数据目录: ~/.jishushell/nomad/data/
12
- * - Alloc 目录: ~/.jishushell/nomad/data/alloc/
13
- * - 日志文件: ~/.jishushell/nomad/nomad.log
8
+ * Nomad checks follow install/jishu-install.sh and src/services/setup-manager.ts:
9
+ * - binary: ~/.jishushell/bin/nomad (v1.6.5)
10
+ * - config: ~/.jishushell/nomad/nomad.hcl
11
+ * - data dir: ~/.jishushell/nomad/data/
12
+ * - alloc dir: ~/.jishushell/nomad/data/alloc/
13
+ * - log file: ~/.jishushell/nomad/nomad.log
14
14
  * - HTTP API: localhost:4646 (ACL enabled)
15
15
  * - systemd: /etc/systemd/system/nomad.service
16
16
  * - macOS: ~/Library/LaunchAgents/com.jishushell.nomad.plist
@@ -26,7 +26,7 @@ import { buildDockerClientEnv, managedColimaDockerHost } from "../utils/docker-h
26
26
  import { loadNomadToken } from "../services/setup-manager.js";
27
27
  import { ensureDirContainer, writeConfigFile, writeSecretFile } from "../utils/fs.js";
28
28
  import { LOG_FILE as PANEL_LOG_FILE } from "../services/panel-manager.js";
29
- // ── ANSI 颜色(非 TTY 时自动禁用)──────────────────────────────────────────
29
+ // ── ANSI colours (auto-disabled when stdout is not a TTY) ───────────────────
30
30
  const isTTY = process.stdout.isTTY ?? false;
31
31
  const c = {
32
32
  bold: (s) => isTTY ? `\x1b[1m${s}\x1b[0m` : s,
@@ -60,7 +60,7 @@ function detectNomadExternalInterface(loopbackIface) {
60
60
  return "";
61
61
  }
62
62
  }
63
- // ── 内部工具函数 ──────────────────────────────────────────────────────────────
63
+ // ── Internal helpers ────────────────────────────────────────────────────────
64
64
  function httpGet(url, timeoutMs = 3000) {
65
65
  return new Promise((resolve, reject) => {
66
66
  const req = http.get(url, { timeout: timeoutMs }, (res) => {
@@ -119,7 +119,7 @@ function isPortListening(port) {
119
119
  return false;
120
120
  }
121
121
  }
122
- // ── Nomad 路径常量(与 setup-manager.ts 保持一致)────────────────────────────
122
+ // ── Nomad path constants (kept in sync with setup-manager.ts) ───────────────
123
123
  const NOMAD_BIN_DIR = join(JISHUSHELL_HOME, "bin");
124
124
  const NOMAD_LOCAL_BIN = join(NOMAD_BIN_DIR, "nomad");
125
125
  const NOMAD_DIR = join(JISHUSHELL_HOME, "nomad");
@@ -133,7 +133,7 @@ function nomadEnabled() {
133
133
  return getPanelConfig().service_manager === "nomad";
134
134
  }
135
135
  // ════════════════════════════════════════════════════════════════════════════
136
- // 类别: 系统环境
136
+ // Category: system environment
137
137
  // ════════════════════════════════════════════════════════════════════════════
138
138
  const checkNode = {
139
139
  id: "node", label: "Node.js 版本", category: "系统环境", severity: "error",
@@ -183,10 +183,24 @@ const checkDockerDaemon = {
183
183
  const colimaEnv = { ...process.env, COLIMA_HOME: colimaDir };
184
184
  const dockerEnv = { ...process.env, DOCKER_HOST: managedColimaDockerHost(JISHUSHELL_HOME) };
185
185
  execFileSync("mkdir", ["-p", colimaDir], { timeout: 5000 });
186
+ // `--network-host-addresses` (added upstream as b8e7dd5) is the
187
+ // load-bearing flag on macOS: without it Colima won't expose Mac
188
+ // host IPs (e.g. en0) into the VM, so Nomad's docker driver — which
189
+ // requests port publishing on `host_network = "external"` (en0) —
190
+ // can't bind that address inside the VM and silently produces
191
+ // containers with empty `Ports: {}`. The result on the host is
192
+ // ECONNREFUSED on every gateway port and the panel proxy returns
193
+ // 502 forever. Do NOT replace this with `--network-address`; that
194
+ // is a different flag (assigns a static IP to the VM) and does not
195
+ // fix the host-port-publishing path.
196
+ // `--arch aarch64` is explicit so we don't fall back to qemu on
197
+ // Apple Silicon when colima can't auto-detect (5-10x slower).
186
198
  execFileSync("colima", ["start", "jishushell",
187
- "--vm-type", "vz", "--mount-type", "virtiofs", "--network-address",
188
- "--activate=false", "--cpu", "2", "--memory", "4", "--disk", "60",
189
- ], { stdio: "ignore", timeout: 120000, env: colimaEnv });
199
+ "--vm-type", "vz", "--mount-type", "virtiofs",
200
+ "--network-host-addresses",
201
+ "--arch", "aarch64",
202
+ "--cpu", "2", "--memory", "4", "--disk", "60",
203
+ ], { stdio: "ignore", timeout: 180000, env: colimaEnv });
190
204
  await new Promise((r) => setTimeout(r, 3000));
191
205
  try {
192
206
  execFileSync("docker", ["info"], { stdio: "ignore", timeout: 6000, env: dockerEnv });
@@ -286,7 +300,7 @@ const checkMemory = {
286
300
  },
287
301
  };
288
302
  // ════════════════════════════════════════════════════════════════════════════
289
- // 类别: 配置
303
+ // Category: configuration
290
304
  // ════════════════════════════════════════════════════════════════════════════
291
305
  const checkConfigDir = {
292
306
  id: "config-dir", label: "配置目录", category: "配置", severity: "error",
@@ -436,7 +450,7 @@ const checkFilePermissions = {
436
450
  },
437
451
  };
438
452
  // ════════════════════════════════════════════════════════════════════════════
439
- // 类别: 服务状态
453
+ // Category: service status
440
454
  // ════════════════════════════════════════════════════════════════════════════
441
455
  const checkPanel = {
442
456
  id: "panel", label: "面板服务", category: "服务状态", severity: "warning",
@@ -503,20 +517,20 @@ const checkSystemdEnabled = {
503
517
  },
504
518
  };
505
519
  // ════════════════════════════════════════════════════════════════════════════
506
- // 类别: Nomad
520
+ // Category: Nomad
507
521
  // ════════════════════════════════════════════════════════════════════════════
508
522
  /**
509
- * 检查 Nomad 二进制(~/.jishushell/bin/nomad
510
- * 依据: install/jishu-install.sh _install_nomad_binary()
511
- * 安装路径: JISHUSHELL_BIN_DIR=${JISHUSHELL_HOME}/bin/nomad
512
- * 要求版本: NOMAD_VERSION=1.6.5
523
+ * Check the Nomad binary (~/.jishushell/bin/nomad).
524
+ * Source of truth: install/jishu-install.sh _install_nomad_binary().
525
+ * Install path: JISHUSHELL_BIN_DIR=${JISHUSHELL_HOME}/bin/nomad
526
+ * Required version: NOMAD_VERSION=1.6.5
513
527
  */
514
528
  const checkNomadBin = {
515
529
  id: "nomad-bin", label: "Nomad 二进制", category: "Nomad", severity: "error",
516
530
  async check() {
517
531
  if (!nomadEnabled())
518
532
  return { ok: true, detail: "未使用 Nomad(已跳过)" };
519
- // 优先检查本地安装路径
533
+ // Prefer the local install path.
520
534
  const binPath = existsSync(NOMAD_LOCAL_BIN) ? NOMAD_LOCAL_BIN : "nomad";
521
535
  try {
522
536
  const versionOut = execFileSync(binPath, ["version"], { encoding: "utf-8", timeout: 5000 }).trim();
@@ -528,7 +542,7 @@ const checkNomadBin = {
528
542
  c.dim(` ├─ 路径: ${binPath === "nomad" ? "(系统 PATH)" : NOMAD_LOCAL_BIN}`),
529
543
  c.dim(` └─ ${NOMAD_BIN_DIR} → `) + pathMark,
530
544
  ];
531
- // 版本检查
545
+ // Version check.
532
546
  const [maj, min, pat] = version.split(".").map(Number);
533
547
  const [rMaj, rMin, rPat] = NOMAD_MIN_VER.split(".").map(Number);
534
548
  const vOk = maj > rMaj || (maj === rMaj && (min > rMin || (min === rMin && pat >= rPat)));
@@ -557,9 +571,9 @@ const checkNomadBin = {
557
571
  },
558
572
  };
559
573
  /**
560
- * 检查 Nomad 配置文件与数据目录
561
- * 依据: install/jishu-install.sh _ensure_nomad_hcl()
562
- * nomad.hcl 关键字段: data_dir, bind_addr, server, client, acl { enabled = true }
574
+ * Check the Nomad config file and data directory.
575
+ * Source of truth: install/jishu-install.sh _ensure_nomad_hcl().
576
+ * Key nomad.hcl fields: data_dir, bind_addr, server, client, acl { enabled = true }.
563
577
  */
564
578
  const checkNomadConfig = {
565
579
  id: "nomad-config", label: "Nomad 配置", category: "Nomad", severity: "error",
@@ -579,7 +593,7 @@ const checkNomadConfig = {
579
593
  if (!existsSync(NOMAD_DATA_DIR) || !existsSync(NOMAD_ALLOC_DIR)) {
580
594
  return { ok: false, detail: "数据目录不完整", fixable: true, extras };
581
595
  }
582
- // 校验 ACL 配置
596
+ // Validate the ACL config.
583
597
  try {
584
598
  const content = readFileSync(NOMAD_CONFIG, "utf-8");
585
599
  if (!content.includes("acl") || !content.includes("enabled = true")) {
@@ -594,7 +608,7 @@ const checkNomadConfig = {
594
608
  ensureDirContainer(NOMAD_DATA_DIR);
595
609
  ensureDirContainer(NOMAD_ALLOC_DIR);
596
610
  if (!existsSync(NOMAD_CONFIG)) {
597
- // 模板与 install/jishu-install.sh _ensure_nomad_hcl() 保持一致
611
+ // Template is kept in sync with install/jishu-install.sh _ensure_nomad_hcl().
598
612
  const loopbackIface = process.platform === "darwin" ? "lo0" : "lo";
599
613
  const externalIface = detectNomadExternalInterface(loopbackIface);
600
614
  const externalHostNetworkBlock = externalIface
@@ -659,9 +673,9 @@ acl {
659
673
  },
660
674
  };
661
675
  /**
662
- * 检查 Nomad Agent 运行状态(端口 4646 + HTTP API + ACL Token)
663
- * 依据: install/jishu-install.sh start_nomad() / install_nomad_systemd()
664
- * 启动命令: sudo nohup nomad agent -config=~/.jishushell/nomad/nomad.hcl > nomad.log 2>&1 &
676
+ * Check the Nomad agent runtime state (port 4646 + HTTP API + ACL token).
677
+ * Source of truth: install/jishu-install.sh start_nomad() / install_nomad_systemd().
678
+ * Start command: sudo nohup nomad agent -config=~/.jishushell/nomad/nomad.hcl > nomad.log 2>&1 &
665
679
  */
666
680
  const checkNomadAgent = {
667
681
  id: "nomad-agent", label: "Nomad Agent", category: "Nomad", severity: "error",
@@ -703,7 +717,7 @@ const checkNomadAgent = {
703
717
  }
704
718
  },
705
719
  async fix() {
706
- // 1. 尝试 systemctl
720
+ // 1. Try systemctl.
707
721
  try {
708
722
  execSync("sudo systemctl start nomad", { stdio: "ignore", timeout: 15000 });
709
723
  await new Promise((r) => setTimeout(r, 3000));
@@ -711,7 +725,7 @@ const checkNomadAgent = {
711
725
  return { ok: true, message: "Nomad Agent 已通过 systemctl 启动" };
712
726
  }
713
727
  catch { }
714
- // 2. 直接 nohup(与 install/jishu-install.sh start_nomad() 保持一致)
728
+ // 2. Fall back to nohup (matches install/jishu-install.sh start_nomad()).
715
729
  if (existsSync(NOMAD_LOCAL_BIN) && existsSync(NOMAD_CONFIG)) {
716
730
  try {
717
731
  execSync(`sudo nohup "${NOMAD_LOCAL_BIN}" agent -config="${NOMAD_CONFIG}" > "${NOMAD_LOG}" 2>&1 &`, { stdio: "ignore", timeout: 5000 });
@@ -728,9 +742,104 @@ const checkNomadAgent = {
728
742
  },
729
743
  };
730
744
  /**
731
- * 检查 nomad.service 是否注册并设为开机自启
732
- * 依据: install/jishu-install.sh install_nomad_systemd() / _install_nomad_launchd()
733
- * Linux 服务文件: /etc/systemd/system/nomad.service
745
+ * Verify Nomad's docker driver fingerprint is healthy.
746
+ *
747
+ * Boot ordering on macOS: launchd fires every LaunchAgent in parallel, so
748
+ * Nomad often starts before Colima finishes booting the VM. When Nomad
749
+ * polls the docker daemon at startup and gets a connection error, it
750
+ * caches `Drivers.docker.Healthy=False` indefinitely — every subsequent
751
+ * job submission then bounces with `missing drivers: 1`, even after
752
+ * Colima is fully up. The only thing that clears the cache is restarting
753
+ * Nomad. This check detects that exact stuck state and offers a one-click
754
+ * `launchctl kickstart` (or `systemctl restart nomad` on Linux) fix.
755
+ */
756
+ const checkNomadDockerDriver = {
757
+ id: "nomad-docker-driver", label: "Nomad docker 驱动健康", category: "Nomad", severity: "error",
758
+ async check() {
759
+ if (!nomadEnabled())
760
+ return { ok: true, detail: "未使用 Nomad(已跳过)" };
761
+ if (!isPortListening(4646))
762
+ return { ok: true, detail: "Nomad 未运行(已跳过,先看 Nomad Agent 检查)" };
763
+ loadNomadToken();
764
+ const nomadAddr = process.env.NOMAD_ADDR || "http://127.0.0.1:4646";
765
+ const token = getNomadToken();
766
+ try {
767
+ const nodesResp = token
768
+ ? await httpGetWithHeaders(`${nomadAddr}/v1/nodes`, { "X-Nomad-Token": token }, 3000)
769
+ : await httpGet(`${nomadAddr}/v1/nodes`, 3000);
770
+ if (nodesResp.status !== 200)
771
+ return { ok: true, detail: `无法读取 nodes 列表(HTTP ${nodesResp.status}),已跳过` };
772
+ const nodes = JSON.parse(nodesResp.body);
773
+ if (!nodes.length)
774
+ return { ok: true, detail: "没有 Nomad 节点(已跳过)" };
775
+ const nodeId = nodes[0].ID;
776
+ const detailResp = token
777
+ ? await httpGetWithHeaders(`${nomadAddr}/v1/node/${nodeId}`, { "X-Nomad-Token": token }, 3000)
778
+ : await httpGet(`${nomadAddr}/v1/node/${nodeId}`, 3000);
779
+ if (detailResp.status !== 200)
780
+ return { ok: true, detail: `无法读取 node 详情(HTTP ${detailResp.status}),已跳过` };
781
+ const node = JSON.parse(detailResp.body);
782
+ const docker = node?.Drivers?.docker ?? {};
783
+ // Healthy → all good. Not detected → docker isn't installed at all,
784
+ // covered by the earlier checkDockerDaemon. Only flag the bad-cache
785
+ // case: Nomad sees docker as detected-but-unhealthy AND we can
786
+ // actually reach docker daemon ourselves.
787
+ if (docker.Healthy === true)
788
+ return { ok: true, detail: "docker 驱动正常" };
789
+ if (docker.Detected !== true)
790
+ return { ok: true, detail: "docker 驱动未启用(已跳过)" };
791
+ const dockerEnv = process.platform === "darwin"
792
+ ? { ...process.env, DOCKER_HOST: managedColimaDockerHost(JISHUSHELL_HOME) }
793
+ : process.env;
794
+ let dockerReachable = false;
795
+ try {
796
+ execFileSync("docker", ["info"], { stdio: "ignore", timeout: 6000, env: dockerEnv });
797
+ dockerReachable = true;
798
+ }
799
+ catch { /* leave false */ }
800
+ if (!dockerReachable) {
801
+ return { ok: false, detail: "docker 驱动 unhealthy 且本地 docker 也不通(先修 Docker 守护进程)", fixable: false };
802
+ }
803
+ const desc = docker.HealthDescription?.slice(0, 80) ?? "";
804
+ return {
805
+ ok: false,
806
+ detail: `docker 驱动 unhealthy 但 docker 实际可达(${desc || "Nomad fingerprint 缓存过期"})`,
807
+ hint: "重启 Nomad 让其重新探测 docker 驱动",
808
+ fixable: true,
809
+ };
810
+ }
811
+ catch (e) {
812
+ return { ok: true, detail: `查询失败(已跳过): ${e.message?.slice?.(0, 60) || e}` };
813
+ }
814
+ },
815
+ async fix() {
816
+ if (process.platform === "darwin") {
817
+ try {
818
+ const uid = process.getuid ? process.getuid() : 0;
819
+ execFileSync("launchctl", ["kickstart", "-k", `gui/${uid}/com.jishushell.nomad`], {
820
+ stdio: "ignore", timeout: 10000,
821
+ });
822
+ await new Promise((r) => setTimeout(r, 5000));
823
+ return { ok: true, message: "已 kickstart Nomad,等数秒后再次运行 doctor 验证" };
824
+ }
825
+ catch (e) {
826
+ return { ok: false, message: `launchctl kickstart 失败: ${e.message}` };
827
+ }
828
+ }
829
+ try {
830
+ execSync("sudo systemctl restart nomad", { stdio: "ignore", timeout: 15000 });
831
+ await new Promise((r) => setTimeout(r, 5000));
832
+ return { ok: true, message: "已通过 systemctl 重启 Nomad" };
833
+ }
834
+ catch (e) {
835
+ return { ok: false, message: `systemctl restart 失败: ${e.message}` };
836
+ }
837
+ },
838
+ };
839
+ /**
840
+ * Check whether nomad.service is registered and enabled for boot.
841
+ * Source of truth: install/jishu-install.sh install_nomad_systemd() / _install_nomad_launchd().
842
+ * Linux service file: /etc/systemd/system/nomad.service
734
843
  * macOS plist: ~/Library/LaunchAgents/com.jishushell.nomad.plist
735
844
  */
736
845
  const checkNomadSystemd = {
@@ -768,8 +877,8 @@ const checkNomadSystemd = {
768
877
  },
769
878
  };
770
879
  /**
771
- * 列出 Nomad 集群中的 Jobs 及其运行状态
772
- * API: GET /v1/jobs ( X-Nomad-Token)
880
+ * List jobs in the Nomad cluster and their runtime status.
881
+ * API: GET /v1/jobs (requires X-Nomad-Token).
773
882
  */
774
883
  const checkNomadJobs = {
775
884
  id: "nomad-jobs", label: "Nomad Jobs", category: "Nomad", severity: "warning",
@@ -808,7 +917,7 @@ const checkNomadJobs = {
808
917
  },
809
918
  };
810
919
  // ════════════════════════════════════════════════════════════════════════════
811
- // 类别: AI 组件
920
+ // Category: AI components
812
921
  // ════════════════════════════════════════════════════════════════════════════
813
922
  const checkOpenclawPkg = {
814
923
  id: "openclaw-pkg", label: "OpenClaw 运行时", category: "AI 组件", severity: "warning",
@@ -816,7 +925,7 @@ const checkOpenclawPkg = {
816
925
  const oclawBin = join(JISHUSHELL_HOME, "packages/openclaw/bin/openclaw");
817
926
  const oclawPkgJson = join(JISHUSHELL_HOME, "packages/openclaw/lib/node_modules/openclaw/package.json");
818
927
  const localBinOk = existsSync(oclawBin);
819
- // Docker 镜像也是合法的运行时(与 setup-manager 逻辑一致)
928
+ // A Docker image is also a valid runtime (matches setup-manager logic).
820
929
  const imageTag = getPanelConfig().openclaw_image || DEFAULT_OPENCLAW_DOCKER_IMAGE;
821
930
  let dockerImageOk = false;
822
931
  try {
@@ -878,7 +987,83 @@ const checkOpenclawImage = {
878
987
  },
879
988
  };
880
989
  // ════════════════════════════════════════════════════════════════════════════
881
- // 类别: 网络
990
+ // Category: connections (capability registry health)
991
+ // ════════════════════════════════════════════════════════════════════════════
992
+ /**
993
+ * Reads `capability-registry.json` and reports the count of providers by
994
+ * status, plus any obvious data-residue (duplicate `(instanceId,
995
+ * capability)` rows, orphan entries pointing at instances that no longer
996
+ * exist, etc.). Aimed at catching the kind of registry drift that would
997
+ * surface in the Connections UI as ghost candidates.
998
+ */
999
+ const checkConnectionsRegistry = {
1000
+ id: "connections-registry", label: "连接 APP 注册表", category: "AI 组件", severity: "warning",
1001
+ async check() {
1002
+ const registryPath = join(JISHUSHELL_HOME, "apps", "capability-registry.json");
1003
+ if (!existsSync(registryPath)) {
1004
+ return { ok: true, detail: "尚无注册表(第一次启动应用前为正常状态)" };
1005
+ }
1006
+ let raw;
1007
+ try {
1008
+ raw = JSON.parse(readFileSync(registryPath, "utf-8"));
1009
+ }
1010
+ catch (e) {
1011
+ return {
1012
+ ok: false,
1013
+ detail: `capability-registry.json 解析失败:${e.message}`,
1014
+ hint: "备份后删除 ~/.jishushell/apps/capability-registry.json,下次启动会重建",
1015
+ fixable: false,
1016
+ };
1017
+ }
1018
+ const providers = raw?.providersByCapability ?? {};
1019
+ let running = 0;
1020
+ let stopped = 0;
1021
+ let unknown = 0;
1022
+ const dupKeys = new Set();
1023
+ const dupHits = [];
1024
+ for (const [cap, list] of Object.entries(providers)) {
1025
+ if (!Array.isArray(list))
1026
+ continue;
1027
+ const seen = new Set();
1028
+ for (const e of list) {
1029
+ const status = String(e?.status ?? "unknown");
1030
+ if (status === "running")
1031
+ running += 1;
1032
+ else if (status === "stopped")
1033
+ stopped += 1;
1034
+ else
1035
+ unknown += 1;
1036
+ const key = `${e?.instanceId}::${cap}`;
1037
+ if (seen.has(key) && !dupKeys.has(key)) {
1038
+ dupKeys.add(key);
1039
+ dupHits.push(key);
1040
+ }
1041
+ seen.add(key);
1042
+ }
1043
+ }
1044
+ const summary = `running=${running}, stopped=${stopped}${unknown ? `, unknown=${unknown}` : ""}`;
1045
+ if (dupHits.length > 0) {
1046
+ const sample = dupHits.slice(0, 3).join(", ");
1047
+ return {
1048
+ ok: false,
1049
+ detail: `${summary};检测到 ${dupHits.length} 条重复注册(${sample}${dupHits.length > 3 ? ", …" : ""})`,
1050
+ hint: "通常无害(dedupe 在读取时进行),如需清理可在面板中重启相关实例触发重新注册",
1051
+ fixable: false,
1052
+ };
1053
+ }
1054
+ if (unknown > 0) {
1055
+ return {
1056
+ ok: false,
1057
+ detail: `${summary};存在 ${unknown} 条 unknown 状态条目`,
1058
+ hint: "重启 jishushell 会让启动重建把它们标记为 stopped/running",
1059
+ fixable: false,
1060
+ };
1061
+ }
1062
+ return { ok: true, detail: summary };
1063
+ },
1064
+ };
1065
+ // ════════════════════════════════════════════════════════════════════════════
1066
+ // Category: network
882
1067
  // ════════════════════════════════════════════════════════════════════════════
883
1068
  const checkNetwork = {
884
1069
  id: "network", label: "网络连通性", category: "网络", severity: "warning",
@@ -899,39 +1084,41 @@ const checkNetwork = {
899
1084
  },
900
1085
  };
901
1086
  // ════════════════════════════════════════════════════════════════════════════
902
- // 所有检查项(按执行顺序)
1087
+ // All check items (in execution order).
903
1088
  // ════════════════════════════════════════════════════════════════════════════
904
1089
  export const ALL_CHECKS = [
905
- // 系统环境
1090
+ // System environment
906
1091
  checkNode,
907
1092
  checkDockerBin,
908
1093
  checkDockerDaemon,
909
1094
  checkDockerGroup,
910
1095
  checkDiskSpace,
911
1096
  checkMemory,
912
- // 配置
1097
+ // Configuration
913
1098
  checkConfigDir,
914
1099
  checkPanelConfig,
915
1100
  checkJwtSecret,
916
1101
  checkAuth,
917
1102
  checkFilePermissions,
918
- // 服务状态
1103
+ // Service status
919
1104
  checkPanel,
920
1105
  checkSystemdEnabled,
921
1106
  // Nomad
922
1107
  checkNomadBin,
923
1108
  checkNomadConfig,
924
1109
  checkNomadAgent,
1110
+ checkNomadDockerDriver,
925
1111
  checkNomadSystemd,
926
1112
  checkNomadJobs,
927
- // AI 组件
1113
+ // AI components
928
1114
  checkOpenclawPkg,
929
1115
  checkOpenclawImage,
930
- // 网络
1116
+ checkConnectionsRegistry,
1117
+ // Network
931
1118
  checkNetwork,
932
1119
  ];
933
1120
  // ════════════════════════════════════════════════════════════════════════════
934
- // 输出格式化
1121
+ // Output formatting
935
1122
  // ════════════════════════════════════════════════════════════════════════════
936
1123
  function formatRow(check, result) {
937
1124
  const isWarn = !result.ok && check.severity === "warning";
@@ -941,10 +1128,10 @@ function formatRow(check, result) {
941
1128
  return ` ${icon} ${label}${tag} ${c.dim(result.detail)}`;
942
1129
  }
943
1130
  // ════════════════════════════════════════════════════════════════════════════
944
- // 主入口
1131
+ // Main entry
945
1132
  // ════════════════════════════════════════════════════════════════════════════
946
1133
  /**
947
- * 运行所有诊断检查,返回是否全部 error 级别检查通过。
1134
+ * Run every diagnostic check and return whether all error-level checks pass.
948
1135
  */
949
1136
  export async function runDoctorChecks(opts = {}) {
950
1137
  const { fix = false } = opts;
@@ -997,7 +1184,7 @@ export async function runDoctorChecks(opts = {}) {
997
1184
  }
998
1185
  log("");
999
1186
  }
1000
- // 汇总
1187
+ // Summary
1001
1188
  const errors = ALL_CHECKS.filter((ch) => !results.get(ch.id).ok && ch.severity === "error");
1002
1189
  const warnings = ALL_CHECKS.filter((ch) => !results.get(ch.id).ok && ch.severity === "warning");
1003
1190
  log(c.dim(" ────────────────────────────────────────────────"));
@@ -1031,7 +1218,7 @@ Options:
1031
1218
  `);
1032
1219
  }
1033
1220
  // ════════════════════════════════════════════════════════════════════════════
1034
- // AI 诊断
1221
+ // AI diagnostics
1035
1222
  // ════════════════════════════════════════════════════════════════════════════
1036
1223
  /** Strip ANSI escape codes from a string. */
1037
1224
  function stripAnsi(s) {