From e5672cd826f3a113b0fa793684d93f43e2b750b9 Mon Sep 17 00:00:00 2001 From: techjarves Date: Tue, 9 Jun 2026 17:11:53 +0530 Subject: [PATCH] feat: implement portable static file server and backend process manager in serve.cjs --- scripts/serve.cjs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/serve.cjs b/scripts/serve.cjs index 2c75f5f..b514ac2 100644 --- a/scripts/serve.cjs +++ b/scripts/serve.cjs @@ -604,7 +604,10 @@ function getBackendOptions() { const rocmAvailable = rocmInstalled && hasAmdGpu() && backendAccepts(BACKEND_PATHS.linuxRocm, "rocm"); const cpuInstalled = osPlatform === "linux" && fs.existsSync(BACKEND_PATHS.linuxCpu); const metalInstalled = osPlatform === "darwin" && fs.existsSync(BACKEND_PATHS.mac); - const metalAvailable = metalInstalled && backendAccepts(BACKEND_PATHS.mac, "metal"); + // Darwin release binaries are Metal builds. Treat an installed macOS backend + // as Metal-capable so the UI does not default to CPU if a probe flag changes + // upstream. + const metalAvailable = metalInstalled; const options = [{ id: "cpu", label: "CPU", available: true }]; if (metalAvailable) options.push({ id: "metal", label: "Metal GPU", available: true }); @@ -1053,6 +1056,11 @@ async function startBackend(settings = {}) { backendLoadState.device = deviceMatch[1].trim(); currentSettings.backendDevice = backendLoadState.device; } + const metalDeviceMatch = cleanOutput.match(/GPU name:\s*([^\r\n]+)/); + if (metalDeviceMatch) { + backendLoadState.device = metalDeviceMatch[1].trim(); + currentSettings.backendDevice = backendLoadState.device; + } if (cleanOutput.includes("ggml_cuda_init")) { backendLoadState.backendMode = "CUDA GPU"; currentSettings.backendMode = "CUDA GPU"; @@ -1065,6 +1073,10 @@ async function startBackend(settings = {}) { backendLoadState.backendMode = "ROCm GPU"; currentSettings.backendMode = "ROCm GPU"; } + if (cleanOutput.includes("ggml_metal")) { + backendLoadState.backendMode = "Metal GPU"; + currentSettings.backendMode = "Metal GPU"; + } if (cleanOutput.includes("[ERROR]")) { const nextError = describeBackendError(cleanOutput.trim(), currentSettings.model); const hasSpecificFileError = String(backendError || "").includes("incomplete or corrupted");