jishushell 0.4.30 → 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/anythingllm-container.yaml +287 -0
- package/apps/browserless-chromium-container.yaml +18 -6
- package/apps/filebrowser-container.yaml +164 -0
- package/apps/ollama-binary.yaml +44 -0
- package/apps/ollama-with-hollama-binary.yaml +45 -1
- package/apps/openclaw-binary.yaml +8 -0
- package/apps/openclaw-container.yaml +9 -1
- package/apps/openclaw-with-searxng-container.yaml +4 -0
- package/apps/searxng-container.yaml +5 -4
- package/apps/weknora-container.yaml +471 -0
- package/dist/cli/doctor.js +144 -16
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/panel.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.js +99 -1
- package/dist/config.js.map +1 -1
- package/dist/install.js +4 -4
- package/dist/install.js.map +1 -1
- package/dist/routes/auth.js +2 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/backup.js +64 -11
- package/dist/routes/backup.js.map +1 -1
- package/dist/routes/external-mounts.d.ts +17 -0
- package/dist/routes/external-mounts.js +73 -0
- package/dist/routes/external-mounts.js.map +1 -0
- package/dist/routes/file-mounts.d.ts +13 -0
- package/dist/routes/file-mounts.js +90 -0
- package/dist/routes/file-mounts.js.map +1 -0
- package/dist/routes/files-organize.d.ts +28 -0
- package/dist/routes/files-organize.js +167 -0
- package/dist/routes/files-organize.js.map +1 -0
- package/dist/routes/files.d.ts +31 -0
- package/dist/routes/files.js +321 -0
- package/dist/routes/files.js.map +1 -0
- package/dist/routes/instances.js +87 -12
- package/dist/routes/instances.js.map +1 -1
- package/dist/routes/internal.d.ts +2 -0
- package/dist/routes/internal.js +59 -0
- package/dist/routes/internal.js.map +1 -0
- package/dist/routes/llm.js +29 -0
- package/dist/routes/llm.js.map +1 -1
- package/dist/routes/setup.js +9 -9
- package/dist/routes/setup.js.map +1 -1
- package/dist/routes/system.js +1 -1
- package/dist/routes/system.js.map +1 -1
- package/dist/routes/webdav.d.ts +17 -0
- package/dist/routes/webdav.js +114 -0
- package/dist/routes/webdav.js.map +1 -0
- package/dist/server.js +358 -6
- 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-compiler.d.ts +1 -1
- package/dist/services/app/app-compiler.js +5 -5
- package/dist/services/app/app-compiler.js.map +1 -1
- package/dist/services/app/app-manager.d.ts +9 -0
- package/dist/services/app/app-manager.js +248 -43
- package/dist/services/app/app-manager.js.map +1 -1
- package/dist/services/app/custom-manager.js.map +1 -1
- package/dist/services/app/hermes-agent-manager.js +1 -0
- package/dist/services/app/hermes-agent-manager.js.map +1 -1
- package/dist/services/app/ollama-manager.js +1 -1
- package/dist/services/app/ollama-manager.js.map +1 -1
- package/dist/services/app/openclaw-manager.js +37 -5
- package/dist/services/app/openclaw-manager.js.map +1 -1
- package/dist/services/app/platform-transform.d.ts +32 -0
- package/dist/services/app/platform-transform.js +65 -0
- package/dist/services/app/platform-transform.js.map +1 -0
- package/dist/services/app-passwords.d.ts +61 -0
- package/dist/services/app-passwords.js +173 -0
- package/dist/services/app-passwords.js.map +1 -0
- package/dist/services/backup-manager.d.ts +11 -0
- package/dist/services/backup-manager.js +220 -8
- 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/connection-apply.d.ts +2 -0
- package/dist/services/connection-apply.js +55 -1
- package/dist/services/connection-apply.js.map +1 -1
- package/dist/services/connection-resolver.js +1 -1
- package/dist/services/connection-resolver.js.map +1 -1
- package/dist/services/connection-transactor.d.ts +2 -0
- package/dist/services/connection-transactor.js +12 -2
- package/dist/services/connection-transactor.js.map +1 -1
- package/dist/services/external-mounts.d.ts +40 -0
- package/dist/services/external-mounts.js +187 -0
- package/dist/services/external-mounts.js.map +1 -0
- package/dist/services/files-manager.d.ts +252 -0
- package/dist/services/files-manager.js +1075 -0
- package/dist/services/files-manager.js.map +1 -0
- package/dist/services/files-mounts.d.ts +42 -0
- package/dist/services/files-mounts.js +207 -0
- package/dist/services/files-mounts.js.map +1 -0
- package/dist/services/instance-manager.js +90 -32
- 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/ssrf.js +6 -2
- package/dist/services/llm-proxy/ssrf.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 +11 -0
- package/dist/services/nomad-manager.js +343 -98
- package/dist/services/nomad-manager.js.map +1 -1
- package/dist/services/organize/applier.d.ts +46 -0
- package/dist/services/organize/applier.js +218 -0
- package/dist/services/organize/applier.js.map +1 -0
- package/dist/services/organize/rules.d.ts +57 -0
- package/dist/services/organize/rules.js +286 -0
- package/dist/services/organize/rules.js.map +1 -0
- package/dist/services/organize/scanner.d.ts +50 -0
- package/dist/services/organize/scanner.js +366 -0
- package/dist/services/organize/scanner.js.map +1 -0
- package/dist/services/organize/store.d.ts +14 -0
- package/dist/services/organize/store.js +82 -0
- package/dist/services/organize/store.js.map +1 -0
- package/dist/services/panel-manager.js +40 -11
- package/dist/services/panel-manager.js.map +1 -1
- package/dist/services/process-manager.js +3 -2
- package/dist/services/process-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 +166 -64
- package/dist/services/runtime/adapters/hermes.js.map +1 -1
- package/dist/services/runtime/adapters/openclaw-routes.d.ts +8 -2
- package/dist/services/runtime/adapters/openclaw-routes.js +68 -0
- package/dist/services/runtime/adapters/openclaw-routes.js.map +1 -1
- package/dist/services/runtime/adapters/openclaw.d.ts +118 -0
- package/dist/services/runtime/adapters/openclaw.js +1459 -49
- package/dist/services/runtime/adapters/openclaw.js.map +1 -1
- package/dist/services/runtime/instance.d.ts +1 -1
- package/dist/services/runtime/instance.js +1 -1
- package/dist/services/runtime/instance.js.map +1 -1
- package/dist/services/runtime/mcp-shims/anythingllm-shim.d.ts +46 -0
- package/dist/services/runtime/mcp-shims/anythingllm-shim.js +281 -0
- package/dist/services/runtime/mcp-shims/anythingllm-shim.js.map +1 -0
- package/dist/services/runtime/mcp-shims/drive-shim.d.ts +54 -0
- package/dist/services/runtime/mcp-shims/drive-shim.js +489 -0
- package/dist/services/runtime/mcp-shims/drive-shim.js.map +1 -0
- package/dist/services/runtime/types.d.ts +31 -0
- package/dist/services/setup-manager.js +190 -68
- package/dist/services/setup-manager.js.map +1 -1
- package/dist/services/suggestions.js.map +1 -1
- package/dist/services/update-manager.js +32 -14
- package/dist/services/update-manager.js.map +1 -1
- package/dist/services/webdav/server.d.ts +24 -0
- package/dist/services/webdav/server.js +420 -0
- package/dist/services/webdav/server.js.map +1 -0
- package/dist/services/webdav/xml-builder.d.ts +73 -0
- package/dist/services/webdav/xml-builder.js +156 -0
- package/dist/services/webdav/xml-builder.js.map +1 -0
- package/dist/services/workspace-builder.d.ts +29 -0
- package/dist/services/workspace-builder.js +188 -0
- package/dist/services/workspace-builder.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/utils/path-locks.d.ts +30 -0
- package/dist/utils/path-locks.js +63 -0
- package/dist/utils/path-locks.js.map +1 -0
- package/dist/utils/path-safety.d.ts +41 -0
- package/dist/utils/path-safety.js +119 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/dist/utils/safe-write.d.ts +24 -0
- package/dist/utils/safe-write.js +82 -0
- package/dist/utils/safe-write.js.map +1 -0
- package/install/jishu-install.sh +247 -35
- package/install/jishu-uninstall.sh +45 -5
- package/package.json +20 -2
- package/public/assets/ApiKeyField-CvyAOcJS.js +1 -0
- package/public/assets/Dashboard-AuJESBlJ.js +1 -0
- package/public/assets/{HermesChatPanel-_GHoklgo.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-bnBu0nlQ.js +19 -0
- package/public/assets/registry-C_qeFTkZ.js +2 -0
- package/public/assets/usePolling-Bn93fe7M.js +1 -0
- package/public/assets/{vendor-i18n-ucpM0OR0.js → vendor-i18n-flxcMVeP.js} +2 -2
- package/public/assets/{vendor-react-Bk1hRGiY.js → vendor-react-ZC5T_huj.js} +7 -7
- package/public/index.html +4 -4
- package/scripts/check-app-spec.mjs +18 -4
- package/scripts/check-colima-launchd.mjs +230 -0
- package/scripts/check-new-file-tests.mjs +230 -0
- package/scripts/check-quarantine-expiry.mjs +105 -0
- package/scripts/perf/README.md +49 -0
- package/scripts/perf/auth.js +99 -0
- package/scripts/perf/config.js +63 -0
- package/scripts/perf/instances.js +143 -0
- package/scripts/perf/proxy.js +96 -0
- package/scripts/smoke/files-w1.sh +142 -0
- package/scripts/smoke-backend.mjs +122 -0
- package/scripts/smoke-post-publish.mjs +346 -0
- package/public/assets/Dashboard-rkWp-CXd.js +0 -1
- package/public/assets/HermesConfigForm-anDnwUp_.js +0 -4
- package/public/assets/InitPassword-ZU9_-hDr.js +0 -1
- package/public/assets/InstanceDetail-CN0FH1aw.js +0 -92
- package/public/assets/Login-BItXqYAJ.js +0 -1
- package/public/assets/NewInstance-BousE6kY.js +0 -1
- package/public/assets/ProviderRecommendations-DFYj7Fb6.js +0 -1
- package/public/assets/Settings-Bttc6QmM.js +0 -1
- package/public/assets/Setup-Bsxx1zgj.js +0 -1
- package/public/assets/WeixinLoginPanel-DPZpAKgO.js +0 -9
- package/public/assets/index-8xZy1z5k.css +0 -1
- package/public/assets/index-Dw3HhUYE.js +0 -19
- package/public/assets/input-paste-CrNVAyOy.js +0 -1
- package/public/assets/providers-DtNXh9JD.js +0 -1
- package/public/assets/registry-5s2UB6is.js +0 -2
- package/public/assets/usePolling-Do5Erqm_.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execFileSync, execSync, spawn as nodeSpawn } from "child_process";
|
|
2
2
|
import { chmodSync, copyFileSync, existsSync, mkdtempSync, readFileSync, renameSync, rmSync, symlinkSync, unlinkSync } from "fs";
|
|
3
|
-
import { userInfo, platform as osPlatform } from "node:os";
|
|
3
|
+
import { userInfo, platform as osPlatform, arch as osArch, cpus as osCpus } from "node:os";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { dirname, join } from "path";
|
|
@@ -8,7 +8,8 @@ import { StringDecoder } from "string_decoder";
|
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
import { JISHUSHELL_HOME, getPanelConfig, savePanelConfig, setOpenclawDockerImage, getOpenclawDockerImage, DEFAULT_OPENCLAW_DOCKER_IMAGE, getRuntimeCatalogEntry, OPENCLAW_MODULES, OPENCLAW_BIN_DIR, } from "../config.js";
|
|
10
10
|
import { ensureDirContainer, ensureDirHost, writeConfigFile, writeSecretFile, writeExecutableFile, writeSystemTmpFile } from "../utils/fs.js";
|
|
11
|
-
import { buildDockerClientEnv, managedColimaSocketPath, resolveDockerHost } from "../utils/docker-host.js";
|
|
11
|
+
import { buildDockerClientEnv, managedColimaSocketPath, managedColimaDockerHost, resolveDockerHost } from "../utils/docker-host.js";
|
|
12
|
+
import { appleSiliconGuard, buildColimaWrapperScript, buildColimaPlist, buildNomadWaitWrapper, buildNomadPlist, buildPanelGateWrapper, buildPanelPlist, } from "./macos-launchd.js";
|
|
12
13
|
import { getAdapter, listRegisteredAdapters } from "./runtime/index.js";
|
|
13
14
|
// Internal usage of task primitives — re-exports further down preserve the
|
|
14
15
|
// public import surface used by runtime/adapters/*, routes, and CLI.
|
|
@@ -21,9 +22,9 @@ const NOMAD_BIN = join(BIN_DIR, "nomad");
|
|
|
21
22
|
const NOMAD_CONFIG_DIR = join(JISHUSHELL_HOME, "nomad");
|
|
22
23
|
const NOMAD_DATA_DIR = join(JISHUSHELL_HOME, "nomad", "data");
|
|
23
24
|
const NOMAD_ALLOC_DIR = join(JISHUSHELL_HOME, "nomad", "data", "alloc");
|
|
24
|
-
const
|
|
25
|
+
const _COLIMA_DIR = join(JISHUSHELL_HOME, "colima");
|
|
25
26
|
const COLIMA_PROFILE = "jishushell";
|
|
26
|
-
const
|
|
27
|
+
const _COLIMA_SOCKET = managedColimaSocketPath(JISHUSHELL_HOME, COLIMA_PROFILE);
|
|
27
28
|
const NOMAD_VERSION = "1.6.5";
|
|
28
29
|
let _serverPort = 8090;
|
|
29
30
|
export function setServerPort(port) { _serverPort = port; }
|
|
@@ -192,7 +193,7 @@ function curlProgressParser(line) {
|
|
|
192
193
|
export function getDirSizeMB(dir) {
|
|
193
194
|
try {
|
|
194
195
|
const result = execFileSync("du", ["-sm", dir], { encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] });
|
|
195
|
-
return parseInt(result.split("\t")[0]) || 0;
|
|
196
|
+
return parseInt(result.split("\t")[0], 10) || 0;
|
|
196
197
|
}
|
|
197
198
|
catch {
|
|
198
199
|
return 0;
|
|
@@ -212,15 +213,6 @@ function checkCommand(cmd, versionFlag = "--version") {
|
|
|
212
213
|
return { ok: false, version: "", path: "" };
|
|
213
214
|
}
|
|
214
215
|
}
|
|
215
|
-
function isProcessRunning(name) {
|
|
216
|
-
try {
|
|
217
|
-
const result = execFileSync("pgrep", ["-f", name], { encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] });
|
|
218
|
-
return result.trim().length > 0;
|
|
219
|
-
}
|
|
220
|
-
catch {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
216
|
function isPortListening(port) {
|
|
225
217
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
226
218
|
return false;
|
|
@@ -509,7 +501,7 @@ async function buildRuntimesStatus() {
|
|
|
509
501
|
export async function upgradeNode(targetMajor = 22) {
|
|
510
502
|
try {
|
|
511
503
|
const current = process.version; // e.g. "v20.20.1"
|
|
512
|
-
const currentMajor = parseInt(current.replace("v", "").split(".")[0]);
|
|
504
|
+
const currentMajor = parseInt(current.replace("v", "").split(".")[0], 10);
|
|
513
505
|
if (currentMajor >= targetMajor) {
|
|
514
506
|
return { ok: true, message: `Node.js ${current} already meets requirement (>= ${targetMajor})` };
|
|
515
507
|
}
|
|
@@ -578,6 +570,17 @@ export async function upgradeNode(targetMajor = 22) {
|
|
|
578
570
|
async function installDockerWithTask(task) {
|
|
579
571
|
try {
|
|
580
572
|
emitTask(task, { type: "progress", message: "开始安装 Docker...", progress: 0 });
|
|
573
|
+
// macOS short-circuit: the rest of this function targets apt/get.docker.com,
|
|
574
|
+
// both of which silently no-op or hard-fail on Darwin. Docker on macOS is
|
|
575
|
+
// provided by Colima (auto-installed by the bash installer at
|
|
576
|
+
// install/jishu-install.sh) — not by this code path. Refuse early with a
|
|
577
|
+
// clear pointer so the user doesn't see a confusing apt error.
|
|
578
|
+
if (process.platform === "darwin") {
|
|
579
|
+
const msg = "macOS Docker 需要 Colima。请运行 shell 安装器 (curl -fsSL https://raw.githubusercontent.com/nicepkg/jishushell/main/install/jishu-install.sh | bash),或参阅 docs/macos-colima.md 手动安装 Colima。";
|
|
580
|
+
emitTask(task, { type: "error", message: msg });
|
|
581
|
+
task.status = "error";
|
|
582
|
+
return { ok: false, message: msg, error: "darwin-not-supported-via-this-path" };
|
|
583
|
+
}
|
|
581
584
|
const user = execSync("whoami", { encoding: "utf-8", timeout: 5000 }).trim();
|
|
582
585
|
// ── Try the get.docker.com convenience script ─────────────────
|
|
583
586
|
emitTask(task, { type: "log", message: "下载 Docker 安装脚本..." });
|
|
@@ -1152,6 +1155,42 @@ function writeNomadConfig() {
|
|
|
1152
1155
|
}
|
|
1153
1156
|
`
|
|
1154
1157
|
: "";
|
|
1158
|
+
// Detect docker0 bridge CIDR so multi-container apps (weknora etc.) can
|
|
1159
|
+
// declare `host_network: docker_bridge` on their ports and have Nomad
|
|
1160
|
+
// publish them on the docker0 IP — which is what `host.docker.internal`
|
|
1161
|
+
// resolves to inside peer containers. Hardcoding 172.17.0.0/16 would
|
|
1162
|
+
// break setups where docker daemon.json overrides `bip` /
|
|
1163
|
+
// `default-address-pools`. Fall back to the Docker default if detection
|
|
1164
|
+
// fails (e.g. docker not yet installed at panel install time; doctor
|
|
1165
|
+
// will regenerate later).
|
|
1166
|
+
const dockerBridgeCidr = detectDockerBridgeCidr() || "172.17.0.0/16";
|
|
1167
|
+
const dockerBridgeHostNetworkBlock = `
|
|
1168
|
+
host_network "docker_bridge" {
|
|
1169
|
+
cidr = "${dockerBridgeCidr}"
|
|
1170
|
+
}
|
|
1171
|
+
`;
|
|
1172
|
+
// Apple Silicon CPU fingerprint workaround. Nomad 1.6.x on darwin/arm64
|
|
1173
|
+
// reads `hw.tbfrequency` (timebase, e.g. 24 MHz on M-series) as the CPU
|
|
1174
|
+
// clock, so a 14-core M4 Max reports as 48 MHz total compute and every
|
|
1175
|
+
// job that asks for CPU>48 gets rejected with "Resources exhausted on
|
|
1176
|
+
// dimension cpu". Override with a conservative estimate (cores × 2500
|
|
1177
|
+
// MHz) — M-series base clock is at least 2.5 GHz, so this never
|
|
1178
|
+
// overcommits relative to actual silicon. Intel Macs fingerprint
|
|
1179
|
+
// correctly and don't need the override.
|
|
1180
|
+
const cpuTotalComputeBlock = platform === "darwin" && osArch() === "arm64"
|
|
1181
|
+
? ` cpu_total_compute = ${osCpus().length * 2500} # Apple Silicon workaround: Nomad mis-fingerprints CPU freq via tbfrequency\n`
|
|
1182
|
+
: "";
|
|
1183
|
+
// macOS docker driver endpoint. macOS users run Docker via Colima
|
|
1184
|
+
// (managed by this panel under `~/.jishushell/colima/jishushell/`) or
|
|
1185
|
+
// Docker Desktop (`~/.docker/run/docker.sock`); neither exposes
|
|
1186
|
+
// `/var/run/docker.sock` out of the box. Resolve the correct host once
|
|
1187
|
+
// and bake it into the HCL so Nomad doesn't fall back to the default
|
|
1188
|
+
// `unix:///var/run/docker.sock` and fail. Linux keeps the default
|
|
1189
|
+
// (empty endpoint = Docker's standard /var/run/docker.sock).
|
|
1190
|
+
const dockerHost = platform === "darwin"
|
|
1191
|
+
? resolveDockerHost({ jishuHome: JISHUSHELL_HOME, colimaProfile: COLIMA_PROFILE })
|
|
1192
|
+
: undefined;
|
|
1193
|
+
const dockerEndpointLine = dockerHost ? `\n endpoint = "${dockerHost}"` : "";
|
|
1155
1194
|
const config = `
|
|
1156
1195
|
data_dir = "${NOMAD_DATA_DIR}"
|
|
1157
1196
|
|
|
@@ -1171,11 +1210,11 @@ server {
|
|
|
1171
1210
|
}
|
|
1172
1211
|
|
|
1173
1212
|
client {
|
|
1174
|
-
enabled = true
|
|
1213
|
+
${cpuTotalComputeBlock} enabled = true
|
|
1175
1214
|
servers = ["127.0.0.1:4647"]
|
|
1176
1215
|
network_interface = "${loopbackIface}"
|
|
1177
1216
|
alloc_dir = "${NOMAD_ALLOC_DIR}"
|
|
1178
|
-
${externalHostNetworkBlock}
|
|
1217
|
+
${externalHostNetworkBlock}${dockerBridgeHostNetworkBlock}
|
|
1179
1218
|
|
|
1180
1219
|
# drain_on_shutdown intentionally omitted: on single-node Pi there is
|
|
1181
1220
|
# nowhere to drain workloads to, and draining on every systemctl restart
|
|
@@ -1185,7 +1224,10 @@ ${externalHostNetworkBlock}
|
|
|
1185
1224
|
}
|
|
1186
1225
|
|
|
1187
1226
|
plugin "docker" {
|
|
1188
|
-
config {
|
|
1227
|
+
config {${dockerEndpointLine}
|
|
1228
|
+
gc {
|
|
1229
|
+
image = false
|
|
1230
|
+
}
|
|
1189
1231
|
volumes {
|
|
1190
1232
|
enabled = true
|
|
1191
1233
|
}
|
|
@@ -1208,6 +1250,22 @@ limits {
|
|
|
1208
1250
|
`;
|
|
1209
1251
|
writeConfigFile(join(NOMAD_CONFIG_DIR, "nomad.hcl"), config);
|
|
1210
1252
|
}
|
|
1253
|
+
function detectDockerBridgeCidr() {
|
|
1254
|
+
// `docker network inspect bridge` returns the CIDR for docker0. The exact
|
|
1255
|
+
// value depends on /etc/docker/daemon.json `bip` / `default-address-pools`
|
|
1256
|
+
// — Docker's default is 172.17.0.0/16 but isn't guaranteed. We need the
|
|
1257
|
+
// real value because Nomad uses `host_network "docker_bridge" { cidr = …}`
|
|
1258
|
+
// to pick which interface to publish a port on for specs that declare
|
|
1259
|
+
// `host_network: docker_bridge`. Wrong CIDR → port silently published on
|
|
1260
|
+
// wrong interface → cross-task host.docker.internal calls get refused.
|
|
1261
|
+
try {
|
|
1262
|
+
const raw = execFileSync("docker", ["network", "inspect", "bridge", "--format", "{{(index .IPAM.Config 0).Subnet}}"], { encoding: "utf8", timeout: 3000, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
1263
|
+
return /^\d{1,3}(\.\d{1,3}){3}\/\d{1,2}$/.test(raw) ? raw : "";
|
|
1264
|
+
}
|
|
1265
|
+
catch {
|
|
1266
|
+
return "";
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1211
1269
|
function detectNomadExternalInterface(loopbackIface) {
|
|
1212
1270
|
try {
|
|
1213
1271
|
if (osPlatform() === "darwin") {
|
|
@@ -1450,8 +1508,41 @@ function enableNomadNodeEligibility() {
|
|
|
1450
1508
|
}
|
|
1451
1509
|
export async function startNomad() {
|
|
1452
1510
|
try {
|
|
1511
|
+
const configPath = join(NOMAD_CONFIG_DIR, "nomad.hcl");
|
|
1512
|
+
const readConfig = () => {
|
|
1513
|
+
try {
|
|
1514
|
+
return existsSync(configPath) ? readFileSync(configPath, "utf-8") : "";
|
|
1515
|
+
}
|
|
1516
|
+
catch {
|
|
1517
|
+
return "";
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1520
|
+
const oldConfig = readConfig();
|
|
1453
1521
|
writeNomadConfig();
|
|
1522
|
+
const newConfig = readConfig();
|
|
1523
|
+
const drifted = oldConfig.length > 0 && newConfig.length > 0 && oldConfig !== newConfig;
|
|
1454
1524
|
if (isPortListening(4646)) {
|
|
1525
|
+
// Nomad already running, but if the rewritten config differs (typically
|
|
1526
|
+
// because detectNomadExternalInterface() now resolves to a different
|
|
1527
|
+
// interface — e.g. older install missing the host_network block, or
|
|
1528
|
+
// network interface renamed across reboots), reload nomad so allocations
|
|
1529
|
+
// bind to the right host network on next placement.
|
|
1530
|
+
if (drifted) {
|
|
1531
|
+
try {
|
|
1532
|
+
execFileSync("sudo", ["-n", "systemctl", "restart", "nomad"], { stdio: "pipe", timeout: 15000 });
|
|
1533
|
+
for (let i = 0; i < 15; i++) {
|
|
1534
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
1535
|
+
if (isPortListening(4646)) {
|
|
1536
|
+
await finalizeNomadStartup();
|
|
1537
|
+
return { ok: true, message: "Nomad restarted (config reconciled)" };
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
return { ok: false, message: "Nomad restart timed out after config reconcile", error: "Port 4646 not listening after 15s" };
|
|
1541
|
+
}
|
|
1542
|
+
catch (e) {
|
|
1543
|
+
console.warn(`[nomad] config drift detected but restart failed (${e.message}); existing nomad continues with stale config`);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1455
1546
|
await finalizeNomadStartup();
|
|
1456
1547
|
return { ok: true, message: "Nomad already running" };
|
|
1457
1548
|
}
|
|
@@ -1501,7 +1592,6 @@ export async function startNomad() {
|
|
|
1501
1592
|
catch {
|
|
1502
1593
|
return { ok: false, message: "Nomad not installed", error: "Install Nomad first" };
|
|
1503
1594
|
}
|
|
1504
|
-
const configPath = join(NOMAD_CONFIG_DIR, "nomad.hcl");
|
|
1505
1595
|
const logPath = join(NOMAD_CONFIG_DIR, "nomad.log");
|
|
1506
1596
|
// Use spawn with detached to avoid execSync shell injection and ensure proper daemonization
|
|
1507
1597
|
try {
|
|
@@ -1572,45 +1662,75 @@ export function installNomadSystemd() {
|
|
|
1572
1662
|
const configPath = join(NOMAD_CONFIG_DIR, "nomad.hcl");
|
|
1573
1663
|
writeNomadConfig();
|
|
1574
1664
|
if (process.platform === "darwin") {
|
|
1575
|
-
|
|
1665
|
+
// macOS is Apple Silicon only — fail fast (mirrors the bash uname guard).
|
|
1666
|
+
const guard = appleSiliconGuard();
|
|
1667
|
+
if (!guard.ok)
|
|
1668
|
+
return { ok: false, message: guard.message };
|
|
1669
|
+
const laDir = join(process.env.HOME || dirname(JISHUSHELL_HOME), "Library/LaunchAgents");
|
|
1670
|
+
// Always use JishuShell's private Colima socket — hardcoded, not
|
|
1671
|
+
// runtime-detected. Colima may not be running yet when the plist is
|
|
1672
|
+
// written; runtime fallback would pick the wrong socket (Docker
|
|
1673
|
+
// Desktop or /var/run/docker.sock). Mirrors the bash _COLIMA_SOCKET use.
|
|
1674
|
+
const colimaSocket = managedColimaSocketPath(JISHUSHELL_HOME, COLIMA_PROFILE);
|
|
1675
|
+
const colimaDockerHost = managedColimaDockerHost(JISHUSHELL_HOME, COLIMA_PROFILE);
|
|
1676
|
+
// ── 1. Colima self-retrying launchd agent ───────────────────────
|
|
1677
|
+
// colima binary: prefer PATH, fall back to both Homebrew prefixes
|
|
1678
|
+
// (mirrors the bash COLIMA_BIN resolution).
|
|
1679
|
+
let colimaBin = "";
|
|
1680
|
+
try {
|
|
1681
|
+
colimaBin = execFileSync("which", ["colima"], { encoding: "utf-8", timeout: 5000 }).trim().split("\n")[0];
|
|
1682
|
+
}
|
|
1683
|
+
catch {
|
|
1684
|
+
colimaBin = "";
|
|
1685
|
+
}
|
|
1686
|
+
if (!colimaBin && existsSync("/opt/homebrew/bin/colima"))
|
|
1687
|
+
colimaBin = "/opt/homebrew/bin/colima";
|
|
1688
|
+
if (!colimaBin && existsSync("/usr/local/bin/colima"))
|
|
1689
|
+
colimaBin = "/usr/local/bin/colima";
|
|
1690
|
+
if (!colimaBin)
|
|
1691
|
+
colimaBin = "colima";
|
|
1692
|
+
const colimaWrapperPath = join(BIN_DIR, "colima-launchd-wrapper.sh");
|
|
1693
|
+
writeExecutableFile(colimaWrapperPath, buildColimaWrapperScript({
|
|
1694
|
+
colimaHome: _COLIMA_DIR,
|
|
1695
|
+
profile: COLIMA_PROFILE,
|
|
1696
|
+
socket: colimaSocket,
|
|
1697
|
+
colimaBin,
|
|
1698
|
+
}));
|
|
1699
|
+
const colimaPlistPath = join(laDir, "com.jishushell.colima.plist");
|
|
1700
|
+
writeConfigFile(colimaPlistPath, buildColimaPlist({
|
|
1701
|
+
wrapperPath: colimaWrapperPath,
|
|
1702
|
+
colimaHome: _COLIMA_DIR,
|
|
1703
|
+
logPath: join(_COLIMA_DIR, "colima-launchd.log"),
|
|
1704
|
+
}));
|
|
1705
|
+
try {
|
|
1706
|
+
execSync(`launchctl unload "${colimaPlistPath}" 2>/dev/null`);
|
|
1707
|
+
}
|
|
1708
|
+
catch { }
|
|
1709
|
+
try {
|
|
1710
|
+
execSync(`launchctl load -w "${colimaPlistPath}"`, { timeout: 15000 });
|
|
1711
|
+
}
|
|
1712
|
+
catch { }
|
|
1713
|
+
// ── 2. Nomad gated behind a docker-readiness wrapper ────────────
|
|
1576
1714
|
const logPath = join(NOMAD_CONFIG_DIR, "nomad.log");
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1579
|
-
|
|
1715
|
+
const nomadWrapperPath = join(BIN_DIR, "nomad-launchd-wrapper.sh");
|
|
1716
|
+
writeExecutableFile(nomadWrapperPath, buildNomadWaitWrapper({
|
|
1717
|
+
dockerHost: colimaDockerHost,
|
|
1718
|
+
nomadBin: nomadPath,
|
|
1719
|
+
configPath,
|
|
1720
|
+
}));
|
|
1721
|
+
const plistContent = buildNomadPlist({
|
|
1722
|
+
wrapperPath: nomadWrapperPath,
|
|
1723
|
+
dockerHost: colimaDockerHost,
|
|
1724
|
+
logPath,
|
|
1580
1725
|
});
|
|
1581
|
-
const
|
|
1582
|
-
? `
|
|
1583
|
-
<key>DOCKER_HOST</key><string>${dockerHost}</string>`
|
|
1584
|
-
: "";
|
|
1585
|
-
const plistContent = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1586
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1587
|
-
<plist version="1.0">
|
|
1588
|
-
<dict>
|
|
1589
|
-
<key>Label</key><string>${plistLabel}</string>
|
|
1590
|
-
<key>ProgramArguments</key>
|
|
1591
|
-
<array>
|
|
1592
|
-
<string>${nomadPath}</string>
|
|
1593
|
-
<string>agent</string>
|
|
1594
|
-
<string>-config=${configPath}</string>
|
|
1595
|
-
</array>
|
|
1596
|
-
<key>EnvironmentVariables</key>
|
|
1597
|
-
<dict>${dockerHostEntry}
|
|
1598
|
-
<key>PATH</key><string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
1599
|
-
</dict>
|
|
1600
|
-
<key>RunAtLoad</key><true/>
|
|
1601
|
-
<key>KeepAlive</key><true/>
|
|
1602
|
-
<key>StandardOutPath</key><string>${logPath}</string>
|
|
1603
|
-
<key>StandardErrorPath</key><string>${logPath}</string>
|
|
1604
|
-
</dict>
|
|
1605
|
-
</plist>`;
|
|
1606
|
-
const plistPath = join(process.env.HOME || dirname(JISHUSHELL_HOME), `Library/LaunchAgents/${plistLabel}.plist`);
|
|
1726
|
+
const plistPath = join(laDir, "com.jishushell.nomad.plist");
|
|
1607
1727
|
writeConfigFile(plistPath, plistContent);
|
|
1608
1728
|
try {
|
|
1609
1729
|
execSync(`launchctl unload "${plistPath}" 2>/dev/null`);
|
|
1610
1730
|
}
|
|
1611
1731
|
catch { }
|
|
1612
1732
|
execSync(`launchctl load -w "${plistPath}"`, { timeout: 15000 });
|
|
1613
|
-
return { ok: true, message: "Nomad launchd agent installed and started" };
|
|
1733
|
+
return { ok: true, message: "Nomad launchd agent installed and started (Colima gated)" };
|
|
1614
1734
|
}
|
|
1615
1735
|
// Nomad 1.6.5's docker driver fingerprint requires euid==0 — PR #18197 lifted
|
|
1616
1736
|
// that restriction only in 1.7+, and we intentionally stay on the 1.6 MPL line.
|
|
@@ -1664,7 +1784,10 @@ export function installJishushellSystemd(port) {
|
|
|
1664
1784
|
// The real owner home: prefer JISHUSHELL_HOME's parent so we don't rely on $HOME.
|
|
1665
1785
|
const realHome = dirname(JISHUSHELL_HOME);
|
|
1666
1786
|
if (process.platform === "darwin") {
|
|
1667
|
-
|
|
1787
|
+
// macOS is Apple Silicon only — fail fast (mirrors the bash uname guard).
|
|
1788
|
+
const guard = appleSiliconGuard();
|
|
1789
|
+
if (!guard.ok)
|
|
1790
|
+
return { ok: false, message: guard.message };
|
|
1668
1791
|
const logPath = join(JISHUSHELL_HOME, "panel.log");
|
|
1669
1792
|
const wrapperPath = join(JISHUSHELL_HOME, "bin", "jishushell-panel-start");
|
|
1670
1793
|
const nomadEnvPath = join(JISHUSHELL_HOME, "nomad.env");
|
|
@@ -1677,23 +1800,22 @@ export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/local/sbin
|
|
|
1677
1800
|
exec "${nodeBin}" "${cliBin}" serve --port ${resolvedPort}
|
|
1678
1801
|
`;
|
|
1679
1802
|
writeExecutableFile(wrapperPath, wrapperContent);
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
const plistPath = join(process.env.HOME || realHome, `Library/LaunchAgents/${plistLabel}.plist`);
|
|
1803
|
+
// 60s docker-readiness gate so the first post-reboot page load
|
|
1804
|
+
// doesn't flash "image missing"; on timeout it starts anyway
|
|
1805
|
+
// (mirrors the bash panel-launchd-wrapper.sh gate).
|
|
1806
|
+
const gateWrapperPath = join(BIN_DIR, "panel-launchd-wrapper.sh");
|
|
1807
|
+
writeExecutableFile(gateWrapperPath, buildPanelGateWrapper({
|
|
1808
|
+
socket: managedColimaSocketPath(JISHUSHELL_HOME, COLIMA_PROFILE),
|
|
1809
|
+
panelStartWrapper: wrapperPath,
|
|
1810
|
+
}));
|
|
1811
|
+
const plistContent = buildPanelPlist({
|
|
1812
|
+
gateWrapperPath,
|
|
1813
|
+
logPath,
|
|
1814
|
+
});
|
|
1815
|
+
// Symmetric with installNomadSystemd()'s laDir (realHome === dirname(JISHUSHELL_HOME),
|
|
1816
|
+
// so process.env.HOME || dirname(JISHUSHELL_HOME) is provably the same path).
|
|
1817
|
+
const laDir = join(process.env.HOME || dirname(JISHUSHELL_HOME), "Library/LaunchAgents");
|
|
1818
|
+
const plistPath = join(laDir, "com.jishushell.panel.plist");
|
|
1697
1819
|
writeConfigFile(plistPath, plistContent);
|
|
1698
1820
|
const panelAlreadyRunning = isPortListening(resolvedPort);
|
|
1699
1821
|
if (!panelAlreadyRunning) {
|