jishushell 0.5.15 → 0.5.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile.hermes-slim +2 -5
- package/apps/filebrowser-container.yaml +1 -0
- package/apps/ollama-binary.yaml +44 -0
- package/apps/ollama-with-hollama-binary.yaml +45 -1
- package/dist/cli/doctor.js +144 -16
- package/dist/cli/doctor.js.map +1 -1
- package/dist/install.js +1 -1
- package/dist/install.js.map +1 -1
- package/dist/routes/instances.js +42 -5
- package/dist/routes/instances.js.map +1 -1
- package/dist/routes/llm.js +29 -0
- package/dist/routes/llm.js.map +1 -1
- package/dist/server.js +18 -4
- package/dist/server.js.map +1 -1
- package/dist/services/agent-apps/catalog.d.ts +3 -0
- package/dist/services/agent-apps/catalog.js +40 -13
- package/dist/services/agent-apps/catalog.js.map +1 -1
- package/dist/services/agent-apps/installers/shell-script.d.ts +1 -1
- package/dist/services/agent-apps/installers/shell-script.js +19 -2
- package/dist/services/agent-apps/installers/shell-script.js.map +1 -1
- package/dist/services/agent-apps/types.d.ts +3 -0
- package/dist/services/app/app-manager.d.ts +8 -0
- package/dist/services/app/app-manager.js +77 -3
- package/dist/services/app/app-manager.js.map +1 -1
- package/dist/services/app/openclaw-manager.js +17 -2
- package/dist/services/app/openclaw-manager.js.map +1 -1
- package/dist/services/backup-manager.js +43 -4
- package/dist/services/backup-manager.js.map +1 -1
- package/dist/services/capability-endpoint-validator.js +26 -7
- package/dist/services/capability-endpoint-validator.js.map +1 -1
- package/dist/services/instance-manager.js +89 -9
- package/dist/services/instance-manager.js.map +1 -1
- package/dist/services/llm-proxy/index.d.ts +28 -0
- package/dist/services/llm-proxy/index.js +76 -3
- package/dist/services/llm-proxy/index.js.map +1 -1
- package/dist/services/llm-proxy/validate-key.d.ts +41 -0
- package/dist/services/llm-proxy/validate-key.js +672 -0
- package/dist/services/llm-proxy/validate-key.js.map +1 -0
- package/dist/services/macos-launchd.d.ts +89 -0
- package/dist/services/macos-launchd.js +273 -0
- package/dist/services/macos-launchd.js.map +1 -0
- package/dist/services/nomad-manager.d.ts +7 -0
- package/dist/services/nomad-manager.js +290 -79
- package/dist/services/nomad-manager.js.map +1 -1
- package/dist/services/panel-manager.js +20 -10
- package/dist/services/panel-manager.js.map +1 -1
- package/dist/services/runtime/adapters/custom.js +56 -0
- package/dist/services/runtime/adapters/custom.js.map +1 -1
- package/dist/services/runtime/adapters/hermes.d.ts +4 -3
- package/dist/services/runtime/adapters/hermes.js +165 -63
- package/dist/services/runtime/adapters/hermes.js.map +1 -1
- package/dist/services/runtime/adapters/openclaw.d.ts +28 -0
- package/dist/services/runtime/adapters/openclaw.js +502 -4
- package/dist/services/runtime/adapters/openclaw.js.map +1 -1
- package/dist/services/setup-manager.js +97 -50
- package/dist/services/setup-manager.js.map +1 -1
- package/dist/services/update-manager.js +32 -14
- package/dist/services/update-manager.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/install/jishu-install.sh +247 -35
- package/install/jishu-uninstall.sh +45 -5
- package/package.json +5 -2
- package/public/assets/ApiKeyField-CvyAOcJS.js +1 -0
- package/public/assets/Dashboard-AuJESBlJ.js +1 -0
- package/public/assets/{HermesChatPanel-B_2HlVBQ.js → HermesChatPanel-CByPREwb.js} +1 -1
- package/public/assets/HermesConfigForm-DRda8FKX.js +4 -0
- package/public/assets/InitPassword-ka4wNpM5.js +1 -0
- package/public/assets/InstanceDetail-Cg1nS8HX.js +92 -0
- package/public/assets/Login-aPajuQzf.js +1 -0
- package/public/assets/NewInstance-Dd1ebNIx.js +1 -0
- package/public/assets/ProviderRecommendations-DFmADQ7V.js +1 -0
- package/public/assets/Settings-BYQnbLYL.js +1 -0
- package/public/assets/Setup-D05lwDOV.js +1 -0
- package/public/assets/WeixinLoginPanel-D89kdhP4.js +9 -0
- package/public/assets/index-HSXCsceK.css +1 -0
- package/public/assets/{index-BZc5zH7u.js → index-bnBu0nlQ.js} +7 -7
- package/public/assets/registry-C_qeFTkZ.js +2 -0
- package/public/assets/usePolling-Bn93fe7M.js +1 -0
- package/public/assets/{vendor-i18n-y9V7Sfuu.js → vendor-i18n-flxcMVeP.js} +2 -2
- package/public/assets/{vendor-react-BWrEVJVb.js → vendor-react-ZC5T_huj.js} +1 -1
- package/public/index.html +4 -4
- package/scripts/check-colima-launchd.mjs +230 -0
- package/public/assets/Dashboard-BdWPtroF.js +0 -1
- package/public/assets/HermesConfigForm-DVlhg3WV.js +0 -4
- package/public/assets/InitPassword-D7glTExX.js +0 -1
- package/public/assets/InstanceDetail-CxSy2cpe.js +0 -92
- package/public/assets/Login-Cfr5c2sv.js +0 -1
- package/public/assets/NewInstance-BIYDmJis.js +0 -1
- package/public/assets/ProviderRecommendations-BuRnvRcI.js +0 -1
- package/public/assets/Settings-Cc-tYBil.js +0 -1
- package/public/assets/Setup-lGZEk5jq.js +0 -1
- package/public/assets/WeixinLoginPanel-CoGqzxeV.js +0 -9
- package/public/assets/index-87IJXG-w.css +0 -1
- package/public/assets/input-paste-CrNVAyOy.js +0 -1
- package/public/assets/providers-DtNXh9JD.js +0 -1
- package/public/assets/registry-BWnkJgZ1.js +0 -2
- package/public/assets/usePolling-CwwT9KrC.js +0 -1
package/Dockerfile.hermes-slim
CHANGED
|
@@ -178,11 +178,8 @@ RUN mkdir -p /opt/data && \
|
|
|
178
178
|
COPY templates/hermes-entrypoint.sh /usr/local/bin/jishushell-hermes-entry.sh
|
|
179
179
|
RUN chmod 0755 /usr/local/bin/jishushell-hermes-entry.sh
|
|
180
180
|
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
# that only knows protocol version N refuses to start an image that
|
|
184
|
-
# declares N+1, which is how we gate rolling upgrades without silent
|
|
185
|
-
# behavioral drift.
|
|
181
|
+
# Retained as build metadata for operators and registry inspection. Runtime
|
|
182
|
+
# readiness is determined from the official ghcr.io RepoDigest, not this label.
|
|
186
183
|
LABEL runtime.protocol.version="1"
|
|
187
184
|
|
|
188
185
|
# Zombie reaping is handled by Nomad's `init: true` flag (docker-init
|
package/apps/ollama-binary.yaml
CHANGED
|
@@ -106,6 +106,28 @@ lifecycle:
|
|
|
106
106
|
owner_marker="$HOME/.jishushell/.ollama-installed-by-jishushell-${app_id}";
|
|
107
107
|
legacy_owner_marker="$HOME/.jishushell/apps/${app_id}/.ollama-installed-by-jishushell";
|
|
108
108
|
system_install_marker="$HOME/.jishushell/.ollama-system-install-${app_id}";
|
|
109
|
+
if [ "$(uname -s)" = "Linux" ] && ! command -v zstd >/dev/null 2>&1; then
|
|
110
|
+
echo "未检测到 zstd;Ollama v0.24+ 安装包仅提供 .tar.zst,需先安装 zstd..." >&2;
|
|
111
|
+
pm_rc=1;
|
|
112
|
+
if command -v apt-get >/dev/null 2>&1; then
|
|
113
|
+
DEBIAN_FRONTEND=noninteractive apt-get update -qq || true;
|
|
114
|
+
DEBIAN_FRONTEND=noninteractive apt-get install -y zstd && pm_rc=0;
|
|
115
|
+
elif command -v dnf >/dev/null 2>&1; then
|
|
116
|
+
dnf install -y zstd && pm_rc=0;
|
|
117
|
+
elif command -v yum >/dev/null 2>&1; then
|
|
118
|
+
yum install -y zstd && pm_rc=0;
|
|
119
|
+
elif command -v apk >/dev/null 2>&1; then
|
|
120
|
+
apk add --no-cache zstd && pm_rc=0;
|
|
121
|
+
elif command -v pacman >/dev/null 2>&1; then
|
|
122
|
+
pacman -Sy --noconfirm zstd && pm_rc=0;
|
|
123
|
+
else
|
|
124
|
+
echo "ERROR: 未找到受支持的包管理器(apt/dnf/yum/apk/pacman)来安装 zstd" >&2;
|
|
125
|
+
fi;
|
|
126
|
+
if [ "$pm_rc" != "0" ] || ! command -v zstd >/dev/null 2>&1; then
|
|
127
|
+
echo "ERROR: 自动安装 zstd 失败;请手动安装后重试。" >&2;
|
|
128
|
+
exit 1;
|
|
129
|
+
fi;
|
|
130
|
+
fi;
|
|
109
131
|
for BINDIR in /usr/local/bin /usr/bin /bin; do
|
|
110
132
|
echo "$PATH" | grep -q "$BINDIR" && break || continue;
|
|
111
133
|
done;
|
|
@@ -117,6 +139,10 @@ lifecycle:
|
|
|
117
139
|
( rm -rf "$old_dir" >/dev/null 2>&1 || true ) &
|
|
118
140
|
fi;
|
|
119
141
|
curl -fsSL https://ollama.com/install.sh | sh;
|
|
142
|
+
if ! command -v ollama >/dev/null 2>&1; then
|
|
143
|
+
echo "ERROR: 安装脚本结束后仍未找到 ollama 命令;请检查网络、磁盘空间或 zstd 是否可用。" >&2;
|
|
144
|
+
exit 1;
|
|
145
|
+
fi;
|
|
120
146
|
rm -f "$install_marker";
|
|
121
147
|
rm -f "$legacy_owner_marker";
|
|
122
148
|
rm -f "$system_install_marker";
|
|
@@ -138,6 +164,18 @@ lifecycle:
|
|
|
138
164
|
: > "$owner_marker";
|
|
139
165
|
fi
|
|
140
166
|
ifFileExists: "~/.jishushell/apps/${app_id}/.ollama-install-needed"
|
|
167
|
+
- run: >-
|
|
168
|
+
if [ -e /usr/local/bin/ollama ]; then
|
|
169
|
+
exit 0;
|
|
170
|
+
fi;
|
|
171
|
+
if ! command -v ollama >/dev/null 2>&1; then
|
|
172
|
+
exit 0;
|
|
173
|
+
fi;
|
|
174
|
+
real_ollama="$(command -v ollama)";
|
|
175
|
+
echo "检测到 ollama 位于 $real_ollama 但 /usr/local/bin/ollama 不存在;建立兼容符号链接(用于 Apple Silicon brew 等场景)..." >&2;
|
|
176
|
+
mkdir -p /usr/local/bin;
|
|
177
|
+
ln -sf "$real_ollama" /usr/local/bin/ollama
|
|
178
|
+
sudo: true
|
|
141
179
|
- run: >-
|
|
142
180
|
service_active_marker="$HOME/.jishushell/apps/${app_id}/.ollama-service-active";
|
|
143
181
|
rm -f "$service_active_marker";
|
|
@@ -198,4 +236,10 @@ lifecycle:
|
|
|
198
236
|
rm -f "$owner_marker" "$legacy_owner_marker" "$system_install_marker" "$uninstall_marker"
|
|
199
237
|
sudo: true
|
|
200
238
|
ifFileExists: "~/.jishushell/.ollama-uninstall-needed-${app_id}"
|
|
239
|
+
- run: >-
|
|
240
|
+
if [ -L /usr/local/bin/ollama ]; then
|
|
241
|
+
echo "清理由 JishuShell 建立的兼容性符号链接 /usr/local/bin/ollama" >&2;
|
|
242
|
+
rm -f /usr/local/bin/ollama;
|
|
243
|
+
fi
|
|
244
|
+
sudo: true
|
|
201
245
|
|
|
@@ -102,6 +102,28 @@ lifecycle:
|
|
|
102
102
|
owner_marker="$HOME/.jishushell/.ollama-installed-by-jishushell-${app_id}";
|
|
103
103
|
legacy_owner_marker="$HOME/.jishushell/apps/${app_id}/.ollama-installed-by-jishushell";
|
|
104
104
|
system_install_marker="$HOME/.jishushell/.ollama-system-install-${app_id}";
|
|
105
|
+
if [ "$(uname -s)" = "Linux" ] && ! command -v zstd >/dev/null 2>&1; then
|
|
106
|
+
echo "未检测到 zstd;Ollama v0.24+ 安装包仅提供 .tar.zst,需先安装 zstd..." >&2;
|
|
107
|
+
pm_rc=1;
|
|
108
|
+
if command -v apt-get >/dev/null 2>&1; then
|
|
109
|
+
DEBIAN_FRONTEND=noninteractive apt-get update -qq || true;
|
|
110
|
+
DEBIAN_FRONTEND=noninteractive apt-get install -y zstd && pm_rc=0;
|
|
111
|
+
elif command -v dnf >/dev/null 2>&1; then
|
|
112
|
+
dnf install -y zstd && pm_rc=0;
|
|
113
|
+
elif command -v yum >/dev/null 2>&1; then
|
|
114
|
+
yum install -y zstd && pm_rc=0;
|
|
115
|
+
elif command -v apk >/dev/null 2>&1; then
|
|
116
|
+
apk add --no-cache zstd && pm_rc=0;
|
|
117
|
+
elif command -v pacman >/dev/null 2>&1; then
|
|
118
|
+
pacman -Sy --noconfirm zstd && pm_rc=0;
|
|
119
|
+
else
|
|
120
|
+
echo "ERROR: 未找到受支持的包管理器(apt/dnf/yum/apk/pacman)来安装 zstd" >&2;
|
|
121
|
+
fi;
|
|
122
|
+
if [ "$pm_rc" != "0" ] || ! command -v zstd >/dev/null 2>&1; then
|
|
123
|
+
echo "ERROR: 自动安装 zstd 失败;请手动安装后重试。" >&2;
|
|
124
|
+
exit 1;
|
|
125
|
+
fi;
|
|
126
|
+
fi;
|
|
105
127
|
for BINDIR in /usr/local/bin /usr/bin /bin; do
|
|
106
128
|
echo "$PATH" | grep -q "$BINDIR" && break || continue;
|
|
107
129
|
done;
|
|
@@ -113,6 +135,10 @@ lifecycle:
|
|
|
113
135
|
( rm -rf "$old_dir" >/dev/null 2>&1 || true ) &
|
|
114
136
|
fi;
|
|
115
137
|
curl -fsSL https://ollama.com/install.sh | sh;
|
|
138
|
+
if ! command -v ollama >/dev/null 2>&1; then
|
|
139
|
+
echo "ERROR: 安装脚本结束后仍未找到 ollama 命令;请检查网络、磁盘空间或 zstd 是否可用。" >&2;
|
|
140
|
+
exit 1;
|
|
141
|
+
fi;
|
|
116
142
|
rm -f "$install_marker";
|
|
117
143
|
rm -f "$legacy_owner_marker";
|
|
118
144
|
rm -f "$system_install_marker";
|
|
@@ -134,6 +160,18 @@ lifecycle:
|
|
|
134
160
|
: > "$owner_marker";
|
|
135
161
|
fi
|
|
136
162
|
ifFileExists: "~/.jishushell/apps/${app_id}/.ollama-install-needed"
|
|
163
|
+
- run: >-
|
|
164
|
+
if [ -e /usr/local/bin/ollama ]; then
|
|
165
|
+
exit 0;
|
|
166
|
+
fi;
|
|
167
|
+
if ! command -v ollama >/dev/null 2>&1; then
|
|
168
|
+
exit 0;
|
|
169
|
+
fi;
|
|
170
|
+
real_ollama="$(command -v ollama)";
|
|
171
|
+
echo "检测到 ollama 位于 $real_ollama 但 /usr/local/bin/ollama 不存在;建立兼容符号链接(用于 Apple Silicon brew 等场景)..." >&2;
|
|
172
|
+
mkdir -p /usr/local/bin;
|
|
173
|
+
ln -sf "$real_ollama" /usr/local/bin/ollama
|
|
174
|
+
sudo: true
|
|
137
175
|
- run: >-
|
|
138
176
|
service_active_marker="$HOME/.jishushell/apps/${app_id}/.ollama-service-active";
|
|
139
177
|
rm -f "$service_active_marker";
|
|
@@ -193,4 +231,10 @@ lifecycle:
|
|
|
193
231
|
rm -rf /Applications/Ollama.app "$HOME/Applications/Ollama.app" 2>/dev/null || true;
|
|
194
232
|
rm -f "$owner_marker" "$legacy_owner_marker" "$system_install_marker" "$uninstall_marker"
|
|
195
233
|
sudo: true
|
|
196
|
-
ifFileExists: "~/.jishushell/.ollama-uninstall-needed-${app_id}"
|
|
234
|
+
ifFileExists: "~/.jishushell/.ollama-uninstall-needed-${app_id}"
|
|
235
|
+
- run: >-
|
|
236
|
+
if [ -L /usr/local/bin/ollama ]; then
|
|
237
|
+
echo "清理由 JishuShell 建立的兼容性符号链接 /usr/local/bin/ollama" >&2;
|
|
238
|
+
rm -f /usr/local/bin/ollama;
|
|
239
|
+
fi
|
|
240
|
+
sudo: true
|
package/dist/cli/doctor.js
CHANGED
|
@@ -20,7 +20,7 @@ import { randomBytes } from "crypto";
|
|
|
20
20
|
import { existsSync, readFileSync, unlinkSync, } from "fs";
|
|
21
21
|
import * as http from "http";
|
|
22
22
|
import { homedir } from "os";
|
|
23
|
-
import { join } from "path";
|
|
23
|
+
import { dirname, join } from "path";
|
|
24
24
|
import { AUTH_FILE, DEFAULT_OPENCLAW_DOCKER_IMAGE, INSTANCES_DIR, JISHUSHELL_HOME, PANEL_CONFIG_FILE, ensureDirs, getNomadToken, getPanelConfig, } from "../config.js";
|
|
25
25
|
import { buildDockerClientEnv, managedColimaDockerHost } from "../utils/docker-host.js";
|
|
26
26
|
import { loadNomadToken } from "../services/setup-manager.js";
|
|
@@ -61,6 +61,37 @@ function detectNomadExternalInterface(loopbackIface) {
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
// ── Internal helpers ────────────────────────────────────────────────────────
|
|
64
|
+
const MACOS_EXEC_PATH_ENTRIES = [
|
|
65
|
+
"/opt/homebrew/bin",
|
|
66
|
+
"/opt/homebrew/sbin",
|
|
67
|
+
"/usr/local/bin",
|
|
68
|
+
"/usr/local/sbin",
|
|
69
|
+
"/usr/bin",
|
|
70
|
+
"/bin",
|
|
71
|
+
"/usr/sbin",
|
|
72
|
+
"/sbin",
|
|
73
|
+
];
|
|
74
|
+
function buildDeterministicPath(basePath, extraEntries = []) {
|
|
75
|
+
return [...extraEntries, basePath ?? "", ...MACOS_EXEC_PATH_ENTRIES]
|
|
76
|
+
.flatMap((entry) => entry.split(":"))
|
|
77
|
+
.map((entry) => entry.trim())
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
.filter((entry, index, entries) => entries.indexOf(entry) === index)
|
|
80
|
+
.join(":");
|
|
81
|
+
}
|
|
82
|
+
function buildMacosColimaEnv(colimaHome) {
|
|
83
|
+
return {
|
|
84
|
+
...process.env,
|
|
85
|
+
COLIMA_HOME: colimaHome,
|
|
86
|
+
PATH: buildDeterministicPath(process.env.PATH, [dirname(process.execPath)]),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function buildMacosDockerEnv() {
|
|
90
|
+
return {
|
|
91
|
+
...process.env,
|
|
92
|
+
PATH: buildDeterministicPath(process.env.PATH, [dirname(process.execPath)]),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
64
95
|
function httpGet(url, timeoutMs = 3000) {
|
|
65
96
|
return new Promise((resolve, reject) => {
|
|
66
97
|
const req = http.get(url, { timeout: timeoutMs }, (res) => {
|
|
@@ -93,15 +124,25 @@ function httpGetWithHeaders(url, headers, timeoutMs = 3000) {
|
|
|
93
124
|
req.end();
|
|
94
125
|
});
|
|
95
126
|
}
|
|
96
|
-
function commandExists(cmd) {
|
|
127
|
+
function commandExists(cmd, env = process.env) {
|
|
97
128
|
try {
|
|
98
|
-
execFileSync("which", [cmd], { stdio: "ignore", timeout: 2000 });
|
|
129
|
+
execFileSync("which", [cmd], { stdio: "ignore", timeout: 2000, env });
|
|
99
130
|
return true;
|
|
100
131
|
}
|
|
101
132
|
catch {
|
|
102
133
|
return false;
|
|
103
134
|
}
|
|
104
135
|
}
|
|
136
|
+
function buildDoctorDockerEnv() {
|
|
137
|
+
const dockerEnv = buildDockerClientEnv({ jishuHome: JISHUSHELL_HOME });
|
|
138
|
+
if (process.platform !== "darwin")
|
|
139
|
+
return dockerEnv;
|
|
140
|
+
return {
|
|
141
|
+
...buildMacosDockerEnv(),
|
|
142
|
+
...dockerEnv,
|
|
143
|
+
PATH: buildDeterministicPath(process.env.PATH, [dirname(process.execPath)]),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
105
146
|
function isPortListening(port) {
|
|
106
147
|
try {
|
|
107
148
|
if (process.platform === "darwin") {
|
|
@@ -150,7 +191,8 @@ const checkNode = {
|
|
|
150
191
|
const checkDockerBin = {
|
|
151
192
|
id: "docker-bin", label: "Docker 已安装", category: "系统环境", severity: "error",
|
|
152
193
|
async check() {
|
|
153
|
-
|
|
194
|
+
const env = process.platform === "darwin" ? buildMacosDockerEnv() : process.env;
|
|
195
|
+
if (commandExists("docker", env))
|
|
154
196
|
return { ok: true, detail: "docker 命令可用" };
|
|
155
197
|
return { ok: false, detail: "未找到 docker 命令", hint: "curl -fsSL https://get.docker.com | sh", fixable: false };
|
|
156
198
|
},
|
|
@@ -158,7 +200,7 @@ const checkDockerBin = {
|
|
|
158
200
|
const checkDockerDaemon = {
|
|
159
201
|
id: "docker-daemon", label: "Docker 守护进程", category: "系统环境", severity: "error",
|
|
160
202
|
async check() {
|
|
161
|
-
const env =
|
|
203
|
+
const env = buildDoctorDockerEnv();
|
|
162
204
|
try {
|
|
163
205
|
execFileSync("docker", ["info"], { stdio: "ignore", timeout: 6000, env });
|
|
164
206
|
const ver = execSync("docker --version 2>/dev/null", { encoding: "utf-8", timeout: 3000, env }).trim();
|
|
@@ -172,7 +214,13 @@ const checkDockerDaemon = {
|
|
|
172
214
|
catch { }
|
|
173
215
|
if (process.platform === "darwin") {
|
|
174
216
|
const colimaDir = join(JISHUSHELL_HOME, "colima");
|
|
175
|
-
|
|
217
|
+
const colimaPath = buildDeterministicPath(process.env.PATH, [dirname(process.execPath)]);
|
|
218
|
+
return {
|
|
219
|
+
ok: false,
|
|
220
|
+
detail: "Docker 守护进程未运行",
|
|
221
|
+
hint: `启动 Docker Desktop,或执行 PATH=${colimaPath} COLIMA_HOME=${colimaDir} colima start jishushell`,
|
|
222
|
+
fixable: true,
|
|
223
|
+
};
|
|
176
224
|
}
|
|
177
225
|
return { ok: false, detail: "Docker 守护进程未运行", hint: "sudo systemctl start docker", fixable: true };
|
|
178
226
|
},
|
|
@@ -180,8 +228,11 @@ const checkDockerDaemon = {
|
|
|
180
228
|
if (process.platform === "darwin") {
|
|
181
229
|
try {
|
|
182
230
|
const colimaDir = join(JISHUSHELL_HOME, "colima");
|
|
183
|
-
const colimaEnv =
|
|
184
|
-
const dockerEnv = {
|
|
231
|
+
const colimaEnv = buildMacosColimaEnv(colimaDir);
|
|
232
|
+
const dockerEnv = {
|
|
233
|
+
...buildMacosDockerEnv(),
|
|
234
|
+
DOCKER_HOST: managedColimaDockerHost(JISHUSHELL_HOME),
|
|
235
|
+
};
|
|
185
236
|
execFileSync("mkdir", ["-p", colimaDir], { timeout: 5000 });
|
|
186
237
|
// `--network-host-addresses` (added upstream as b8e7dd5) is the
|
|
187
238
|
// load-bearing flag on macOS: without it Colima won't expose Mac
|
|
@@ -231,10 +282,11 @@ const checkDockerDaemon = {
|
|
|
231
282
|
const checkDockerGroup = {
|
|
232
283
|
id: "docker-group", label: "Docker 用户权限", category: "系统环境", severity: "warning",
|
|
233
284
|
async check() {
|
|
234
|
-
|
|
285
|
+
const env = process.platform === "darwin" ? buildDoctorDockerEnv() : process.env;
|
|
286
|
+
if (!commandExists("docker", env))
|
|
235
287
|
return { ok: true, detail: "跳过(docker 未安装)" };
|
|
236
288
|
try {
|
|
237
|
-
execFileSync("docker", ["info"], { stdio: "ignore", timeout: 4000 });
|
|
289
|
+
execFileSync("docker", ["info"], { stdio: "ignore", timeout: 4000, env });
|
|
238
290
|
return { ok: true, detail: "无需 sudo 即可使用 Docker" };
|
|
239
291
|
}
|
|
240
292
|
catch { }
|
|
@@ -652,6 +704,9 @@ ${externalHostNetworkBlock}
|
|
|
652
704
|
plugin "docker" {
|
|
653
705
|
config {
|
|
654
706
|
disable_log_collection = true
|
|
707
|
+
gc {
|
|
708
|
+
image = false
|
|
709
|
+
}
|
|
655
710
|
volumes {
|
|
656
711
|
enabled = true
|
|
657
712
|
}
|
|
@@ -900,12 +955,34 @@ const checkNomadJobs = {
|
|
|
900
955
|
const jobs = JSON.parse(res.body);
|
|
901
956
|
if (jobs.length === 0)
|
|
902
957
|
return { ok: true, detail: "暂无 Job(集群为空)" };
|
|
903
|
-
const
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
958
|
+
const runtimeJobs = await Promise.all(jobs.map(async (job) => {
|
|
959
|
+
try {
|
|
960
|
+
const allocRes = token
|
|
961
|
+
? await httpGetWithHeaders(`${nomadAddr}/v1/job/${encodeURIComponent(job.ID)}/allocations`, { "X-Nomad-Token": token }, 5000)
|
|
962
|
+
: await httpGet(`${nomadAddr}/v1/job/${encodeURIComponent(job.ID)}/allocations`, 5000);
|
|
963
|
+
if (allocRes.status !== 200) {
|
|
964
|
+
return { ...job, runtimeStatus: job.Status, runtimeHint: `alloc HTTP ${allocRes.status}` };
|
|
965
|
+
}
|
|
966
|
+
const allocs = JSON.parse(allocRes.body);
|
|
967
|
+
const running = allocs.find((alloc) => alloc.ClientStatus === "running");
|
|
968
|
+
if (running)
|
|
969
|
+
return { ...job, runtimeStatus: "running", runtimeHint: "" };
|
|
970
|
+
const latest = [...allocs].sort((a, b) => ((b.ModifyIndex ?? b.CreateIndex ?? 0) - (a.ModifyIndex ?? a.CreateIndex ?? 0)))[0];
|
|
971
|
+
const runtimeStatus = latest?.ClientStatus || job.Status || "unknown";
|
|
972
|
+
const runtimeHint = runtimeStatus !== job.Status ? `job=${job.Status}` : "";
|
|
973
|
+
return { ...job, runtimeStatus, runtimeHint };
|
|
974
|
+
}
|
|
975
|
+
catch (e) {
|
|
976
|
+
return { ...job, runtimeStatus: job.Status || "unknown", runtimeHint: e?.message || "alloc query failed" };
|
|
977
|
+
}
|
|
978
|
+
}));
|
|
979
|
+
const unhealthy = runtimeJobs.filter((j) => j.runtimeStatus !== "running");
|
|
980
|
+
const extras = runtimeJobs.map((j, idx) => {
|
|
981
|
+
const branch = idx === runtimeJobs.length - 1 ? "└─" : "├─";
|
|
982
|
+
const icon = j.runtimeStatus === "running" ? c.green("✓") : c.yellow("!");
|
|
983
|
+
const status = j.runtimeStatus === "running" ? c.green(j.runtimeStatus) : c.yellow(j.runtimeStatus);
|
|
984
|
+
const hint = j.runtimeHint ? `, ${j.runtimeHint}` : "";
|
|
985
|
+
return c.dim(` ${branch} ${icon} ${j.ID.padEnd(26)}`) + " " + status + c.dim(` [${j.Type}${hint}]`);
|
|
909
986
|
});
|
|
910
987
|
if (unhealthy.length > 0)
|
|
911
988
|
return { ok: false, detail: `${jobs.length} 个 job,${unhealthy.length} 个非 running 状态`, extras };
|
|
@@ -1083,6 +1160,54 @@ const checkNetwork = {
|
|
|
1083
1160
|
return { ok: false, detail: "无法连通外网(ping 及 DNS 均失败)", hint: "检查网络: ip route && cat /etc/resolv.conf", fixable: false };
|
|
1084
1161
|
},
|
|
1085
1162
|
};
|
|
1163
|
+
const COLIMA_WRAPPER = join(JISHUSHELL_HOME, "bin", "colima-launchd-wrapper.sh");
|
|
1164
|
+
const COLIMA_PLIST = join(homedir(), "Library/LaunchAgents/com.jishushell.colima.plist");
|
|
1165
|
+
const checkColimaLaunchd = {
|
|
1166
|
+
id: "colima-launchd", label: "Colima 自启 Agent", category: "Nomad", severity: "warning",
|
|
1167
|
+
async check() {
|
|
1168
|
+
if (process.platform !== "darwin")
|
|
1169
|
+
return { ok: true, detail: "非 macOS(已跳过)" };
|
|
1170
|
+
if (!existsSync(COLIMA_PLIST))
|
|
1171
|
+
return { ok: false, detail: "com.jishushell.colima.plist 不存在", hint: "bash jishu-install.sh --run 3", fixable: false };
|
|
1172
|
+
const body = readFileSync(COLIMA_PLIST, "utf-8");
|
|
1173
|
+
const oldStyle = body.includes("<string>start</string>") || body.includes("--arch</string><string>aarch64");
|
|
1174
|
+
if (oldStyle)
|
|
1175
|
+
return { ok: false, detail: "旧式 plist(无 wrapper / 写死 arch)", hint: "bash jishu-install.sh --run 3 重新生成", fixable: false };
|
|
1176
|
+
return { ok: true, detail: "自重试 wrapper 形式" };
|
|
1177
|
+
},
|
|
1178
|
+
};
|
|
1179
|
+
const checkColimaWrapper = {
|
|
1180
|
+
id: "colima-wrapper", label: "Colima wrapper 脚本", category: "Nomad", severity: "warning",
|
|
1181
|
+
async check() {
|
|
1182
|
+
if (process.platform !== "darwin")
|
|
1183
|
+
return { ok: true, detail: "非 macOS(已跳过)" };
|
|
1184
|
+
if (!existsSync(COLIMA_WRAPPER))
|
|
1185
|
+
return { ok: false, detail: "colima-launchd-wrapper.sh 缺失", hint: "bash jishu-install.sh --run 3", fixable: false };
|
|
1186
|
+
return { ok: true, detail: COLIMA_WRAPPER };
|
|
1187
|
+
},
|
|
1188
|
+
};
|
|
1189
|
+
const checkMacosAutologin = {
|
|
1190
|
+
id: "macos-autologin", label: "macOS 自动登录", category: "Nomad", severity: "warning",
|
|
1191
|
+
async check() {
|
|
1192
|
+
if (process.platform !== "darwin")
|
|
1193
|
+
return { ok: true, detail: "非 macOS(已跳过)" };
|
|
1194
|
+
let fvOn = false;
|
|
1195
|
+
try {
|
|
1196
|
+
fvOn = execFileSync("fdesetup", ["status"], { encoding: "utf-8", timeout: 4000 }).includes("FileVault is On");
|
|
1197
|
+
}
|
|
1198
|
+
catch { /* treat as off */ }
|
|
1199
|
+
if (fvOn)
|
|
1200
|
+
return { ok: true, detail: "FileVault 开启(auto-login 不适用,已跳过)" };
|
|
1201
|
+
let user = "";
|
|
1202
|
+
try {
|
|
1203
|
+
user = execFileSync("defaults", ["read", "/Library/Preferences/com.apple.loginwindow", "autoLoginUser"], { encoding: "utf-8", timeout: 4000 }).trim();
|
|
1204
|
+
}
|
|
1205
|
+
catch { /* not set */ }
|
|
1206
|
+
if (!user)
|
|
1207
|
+
return { ok: false, detail: "未配置(headless 重启不会触发 LaunchAgent)", hint: "bash jishu-install.sh --run 3 --enable-autologin", fixable: false };
|
|
1208
|
+
return { ok: true, detail: `autoLoginUser=${user}` };
|
|
1209
|
+
},
|
|
1210
|
+
};
|
|
1086
1211
|
// ════════════════════════════════════════════════════════════════════════════
|
|
1087
1212
|
// All check items (in execution order).
|
|
1088
1213
|
// ════════════════════════════════════════════════════════════════════════════
|
|
@@ -1108,6 +1233,9 @@ export const ALL_CHECKS = [
|
|
|
1108
1233
|
checkNomadConfig,
|
|
1109
1234
|
checkNomadAgent,
|
|
1110
1235
|
checkNomadDockerDriver,
|
|
1236
|
+
checkColimaLaunchd,
|
|
1237
|
+
checkColimaWrapper,
|
|
1238
|
+
checkMacosAutologin,
|
|
1111
1239
|
checkNomadSystemd,
|
|
1112
1240
|
checkNomadJobs,
|
|
1113
1241
|
// AI components
|