From 6613db72b94a7e0e992f3f59094f5f16e807926c Mon Sep 17 00:00:00 2001 From: jarves Date: Thu, 4 Jun 2026 05:50:29 +0000 Subject: [PATCH] refactor: relocate node tools to node-win and implement centralized server backend in serve.cjs --- scripts/serve.cjs | 78 ++++++++++++++++++++++++++++++++++++----------- scripts/setup.ps1 | 10 +++--- start.bat | 10 +++--- 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/scripts/serve.cjs b/scripts/serve.cjs index f0aa1e9..91769c2 100644 --- a/scripts/serve.cjs +++ b/scripts/serve.cjs @@ -310,15 +310,36 @@ function checkPort(port) { function getSetupPaths() { const appDir = path.join(ROOT, "app"); - return { - node: path.join(appDir, "tools", "node", "node.exe"), - npm: path.join(appDir, "tools", "node", "npm.cmd"), - distIndex: path.join(DIST, "index.html"), - cudaBackend: BACKEND_PATHS.cuda, - vulkanBackend: BACKEND_PATHS.vulkan, - models: MODELS, - outputs: OUTPUTS, - }; + if (osPlatform === "win32") { + return { + node: path.join(appDir, "tools", "node-win", "node.exe"), + npm: path.join(appDir, "tools", "node-win", "npm.cmd"), + distIndex: path.join(DIST, "index.html"), + cudaBackend: BACKEND_PATHS.cuda, + vulkanBackend: BACKEND_PATHS.vulkan, + models: MODELS, + outputs: OUTPUTS, + }; + } else if (osPlatform === "darwin") { + return { + node: path.join(appDir, "tools", "node-mac", "bin", "node"), + npm: path.join(appDir, "tools", "node-mac", "bin", "npm"), + distIndex: path.join(DIST, "index.html"), + macBackend: BACKEND_PATHS.mac, + models: MODELS, + outputs: OUTPUTS, + }; + } else { + // Linux / WSL + return { + node: path.join(appDir, "tools", "node-linux", "bin", "node"), + npm: path.join(appDir, "tools", "node-linux", "bin", "npm"), + distIndex: path.join(DIST, "index.html"), + linuxBackend: BACKEND_PATHS.linux, + models: MODELS, + outputs: OUTPUTS, + }; + } } async function getHealth() { @@ -327,16 +348,31 @@ async function getHealth() { getPathInfo("Portable Node.js", paths.node), getPathInfo("Portable npm", paths.npm), getPathInfo("Frontend build", paths.distIndex), - getPathInfo("CUDA backend", paths.cudaBackend), - getPathInfo("Vulkan backend", paths.vulkanBackend), getDirInfo("Models folder", paths.models), getDirInfo("Outputs folder", paths.outputs), ]; - const backendInstalled = checks.find((check) => check.label === "CUDA backend")?.exists || - checks.find((check) => check.label === "Vulkan backend")?.exists; + if (osPlatform === "win32") { + checks.push(getPathInfo("CUDA backend", paths.cudaBackend)); + checks.push(getPathInfo("Vulkan backend", paths.vulkanBackend)); + } else if (osPlatform === "darwin") { + checks.push(getPathInfo("Mac backend", paths.macBackend)); + } else { + checks.push(getPathInfo("Linux backend", paths.linuxBackend)); + } + + let backendInstalled = false; + if (osPlatform === "win32") { + backendInstalled = checks.find((check) => check.label === "CUDA backend")?.exists || + checks.find((check) => check.label === "Vulkan backend")?.exists; + } else if (osPlatform === "darwin") { + backendInstalled = checks.find((check) => check.label === "Mac backend")?.exists; + } else { + backendInstalled = checks.find((check) => check.label === "Linux backend")?.exists; + } + const criticalOk = checks - .filter((check) => !["CUDA backend", "Vulkan backend"].includes(check.label)) + .filter((check) => !["CUDA backend", "Vulkan backend", "Linux backend", "Mac backend"].includes(check.label)) .every((check) => check.ok) && backendInstalled; const ports = { @@ -347,9 +383,11 @@ async function getHealth() { ports.backend.ok = backendProc !== null ? !ports.backend.available : ports.backend.available; const issues = checks - .filter((check) => !check.ok && !["CUDA backend", "Vulkan backend"].includes(check.label)) + .filter((check) => !check.ok && !["CUDA backend", "Vulkan backend", "Linux backend", "Mac backend"].includes(check.label)) .map((check) => `${check.label} is missing or not writable.`); - if (!backendInstalled) issues.push("No Windows backend binary is installed."); + if (!backendInstalled) { + issues.push(`No ${osPlatform === "win32" ? "Windows" : osPlatform === "darwin" ? "macOS" : "Linux"} backend binary is installed.`); + } if (!ports.backend.ok) issues.push(`Port ${PORT_BACKEND} is already in use by another process.`); return { @@ -457,8 +495,12 @@ function getBackendOptions() { const cudaAvailable = osPlatform === "win32" && hasNvidiaGpu() && backendAccepts(BACKEND_PATHS.cuda, "cuda"); const cudaInstalled = osPlatform === "win32" && fs.existsSync(BACKEND_PATHS.cuda); - const vulkanInstalled = osPlatform === "win32" && fs.existsSync(BACKEND_PATHS.vulkan); - const vulkanAvailable = osPlatform === "win32" && backendAccepts(BACKEND_PATHS.vulkan, "vulkan"); + const vulkanInstalled = (osPlatform === "win32" && fs.existsSync(BACKEND_PATHS.vulkan)) || + (osPlatform === "linux" && fs.existsSync(BACKEND_PATHS.linux)); + const vulkanAvailable = vulkanInstalled && backendAccepts( + osPlatform === "win32" ? BACKEND_PATHS.vulkan : BACKEND_PATHS.linux, + "vulkan" + ); const options = [{ id: "cpu", label: "CPU", available: true }]; if (vulkanAvailable) options.push({ id: "vulkan", label: "Vulkan GPU", available: true }); if (cudaAvailable) options.push({ id: "cuda", label: "CUDA GPU", available: true }); diff --git a/scripts/setup.ps1 b/scripts/setup.ps1 index 17559c0..67b24a7 100644 --- a/scripts/setup.ps1 +++ b/scripts/setup.ps1 @@ -6,7 +6,7 @@ $rootDir = Split-Path -Parent $scriptDir $appDir = Join-Path $rootDir "app" $frontendDir = Join-Path $appDir "frontend" $toolsDir = Join-Path $appDir "tools" -$nodeDir = Join-Path $toolsDir "node" +$nodeDir = Join-Path $toolsDir "node-win" $nodeExe = Join-Path $nodeDir "node.exe" $npmCmd = Join-Path $nodeDir "npm.cmd" $distDir = Join-Path $appDir "dist" @@ -150,7 +150,7 @@ Print-Header $steps = 4 # ── Step 1: Portable Node.js ────────────────────────────────────────────────── -Print-Step 1 $steps "Setting up portable Node.js (app/tools/node/)" +Print-Step 1 $steps "Setting up portable Node.js (app/tools/node-win/)" if ((Test-Path $nodeExe) -and (Test-Path $npmCmd)) { $v = & $nodeExe --version @@ -172,11 +172,11 @@ if ((Test-Path $nodeExe) -and (Test-Path $npmCmd)) { $extracted = Get-ChildItem $toolsDir -Directory | Where-Object { $_.Name -like "node-v*" } | Select-Object -First 1 if ($extracted) { if (Test-Path $nodeDir) { Remove-Item $nodeDir -Recurse -Force } - Rename-Item $extracted.FullName "node" + Rename-Item $extracted.FullName "node-win" } if (-not ((Test-Path $nodeExe) -and (Test-Path $npmCmd))) { - Print-Fail "Portable Node.js install is incomplete. Close any running Local AI Image Generator windows, delete app/tools/node, then run setup again." + Print-Fail "Portable Node.js install is incomplete. Close any running Local AI Image Generator windows, delete app/tools/node-win, then run setup again." Read-Host; exit 1 } @@ -363,7 +363,7 @@ Write-Host "" if (-not (Test-Path $npmCmd)) { Print-Fail "npm.cmd was not found at $npmCmd" - Print-Fail "Close any running Local AI Image Generator windows, delete app/tools/node, then run setup again." + Print-Fail "Close any running Local AI Image Generator windows, delete app/tools/node-win, then run setup again." Read-Host; exit 1 } diff --git a/start.bat b/start.bat index 205b706..dad78e9 100644 --- a/start.bat +++ b/start.bat @@ -3,8 +3,8 @@ title Local AI Image Generator cd /d "%~dp0" set APP=%~dp0app -set NODE=%APP%\tools\node\node.exe -set NPM=%APP%\tools\node\npm.cmd +set NODE=%APP%\tools\node-win\node.exe +set NPM=%APP%\tools\node-win\npm.cmd set DIST=%APP%\dist\index.html set SETUP=%~dp0scripts\setup.ps1 set CUDA_BACKEND=%APP%\backend\win\cuda\sd-cuda.exe @@ -14,7 +14,7 @@ set SETUP_REASON= set SETUP_MODE=Repair :: ── First-time setup check ──────────────────────────────────────────────────── -if not exist "%APP%\tools\node" set SETUP_MODE=First-Time Setup +if not exist "%APP%\tools\node-win" set SETUP_MODE=First-Time Setup if not exist "%NODE%" ( set SETUP_REASON=Portable Node.js is missing. goto :run_setup @@ -49,7 +49,7 @@ echo. echo Press any key to continue, or Ctrl+C to cancel. pause >nul -:: Clear old local server processes before setup so app/tools/node can be replaced +:: Clear old local server processes before setup so app/tools/node-win can be replaced for /f "tokens=5" %%a in ('netstat -aon 2^>nul ^| findstr ":8080 "') do taskkill /f /pid %%a >nul 2>nul for /f "tokens=5" %%a in ('netstat -aon 2^>nul ^| findstr ":1420 "') do taskkill /f /pid %%a >nul 2>nul @@ -103,4 +103,4 @@ pause >nul :: Cleanup on exit echo Shutting down... taskkill /fi "WINDOWTITLE eq SD-Server*" /f >nul 2>nul -echo Done. Goodbye! +echo Done. Goodbye! \ No newline at end of file