Installer: close everything running from the app's folder before copying

Updating 1.4.35 -> 1.4.36 on the TV stopped at "Bible App cannot be closed. Please
close it manually and click Retry" with the app plainly closed. That message also
comes from the installer's copy step (and from removing the old version) when any
file in the install folder is in use — not only when Bible App.exe is running.

The app runs programs from its own folder: the local AI server (llama-server.exe),
speech (whisper-cli.exe), the upscaler. electron-builder's stock check closes only
Bible App.exe, and when it has to force-close the app, the app's own shutdown (which
stops the AI server) never runs. The orphaned llama-server.exe then holds its files
open forever, so Retry can never succeed.

- build/installer.nsh: customCheckAppRunning replaces the stock check. It asks the
  app to close, force-closes any Bible App.exe left, force-closes the helpers by name,
  then, as a backstop, every process whose executable is inside the install folder
  (via WMI, which works from the 32-bit installer on 64-bit Windows; the folder is
  passed in an environment variable and a bare drive is refused). It runs before the
  old version is removed and before any file is copied.
- main.cjs: the in-app updater stops the AI server before launching the installer.

The fix is in the INSTALLER, so the TV still on 1.4.35 gets it with this release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:37:14 -04:00
co-authored by Claude Opus 5.5
parent 5e1402118b
commit f0af453020
2 changed files with 42 additions and 0 deletions
+3
View File
@@ -355,6 +355,9 @@ async function createWindow () {
quit: () => { try { app.quit(); } catch (_) {} },
runInstaller: (installerPath) => {
// Launch the installer detached, then quit so it can replace the running app.
// Stop the local AI server FIRST: it runs from the install folder, and one left running holds
// its files open, so the installer cannot copy the new version over them ("cannot be closed").
try { stopLlamaServer(); } catch (_) {}
try {
const { spawn } = require('child_process');
const child = spawn(installerPath, [], { detached: true, stdio: 'ignore', windowsHide: false });