mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 00:03:08 +00:00
The terminal daemon was fork()ed with no explicit execPath, so its process image was the install-dir Orca.exe run via ELECTRON_RUN_AS_NODE. On Windows, the NSIS installer's CHECK_APP_RUNNING sweep force-kills processes whose image lives under the install directory, so an app update killed the live daemon and every terminal it hosted (including the user's running Claude process). Relocate the daemon host image out of the install dir: stage a standalone, version-correct node.exe under %APPDATA%\orca\daemon-host\<appVersion>\ and fork the daemon from it. The daemon's image now lives in userData, outside the installer's kill zone, so it survives updates. Fail-open: if no relocated node.exe is present, fall back to the current Orca.exe + ELECTRON_RUN_AS_NODE path (zero regression). Adoption and stale-kill are unaffected — process identification matches on daemon-entry/socket/token args and the unchanged entryPath, never the host image name. Build: afterPack stages the build host's own official (OpenJS-signed) Node 24.x node.exe into resources/daemon-host/node.exe. engines.node="24" pins the build host to the ABI Electron 42 embeds (Node 24.15, NAPI 10) so the relocated host loads node-pty's NAPI conpty.node addon. Shipping the OpenJS-signed binary means it is validly signed regardless of whether SignPath re-signs nested PEs. Extract the version-keyed copy + daemon-pinned GC shared by the node-pty native relocation (#7421) into install-dir-runtime-relocation.ts and reuse it for the host relocation. CI verify step + contract/config tests guard the staging.
42 lines
2.0 KiB
JavaScript
42 lines
2.0 KiB
JavaScript
const { copyFileSync, existsSync, mkdirSync } = require('node:fs')
|
|
const { join } = require('node:path')
|
|
|
|
// Where the standalone daemon-host node.exe is staged under packaged resources.
|
|
// Mirrored at runtime by src/main/daemon/daemon-host-relocation.ts, which copies
|
|
// it into userData/daemon-host/<version>/ and forks the terminal daemon from it.
|
|
const DAEMON_HOST_DIR = 'daemon-host'
|
|
const DAEMON_HOST_NODE_EXE = 'node.exe'
|
|
|
|
/**
|
|
* Stages a standalone Windows node.exe into resources/daemon-host so the
|
|
* detached terminal daemon can be forked from a userData copy that lives
|
|
* outside the install directory the NSIS updater force-closes mid-update.
|
|
*
|
|
* Source is the build host's own node.exe (process.execPath). It is version-
|
|
* correct by construction: engines.node pins the build to Node 24.x, whose NAPI
|
|
* 10 runtime loads node-pty's Electron-42-built conpty.node. Being an official
|
|
* Node binary, it also carries the OpenJS Foundation Authenticode signature, so
|
|
* it ships validly signed regardless of whether SignPath re-signs nested PEs.
|
|
*
|
|
* Windows x64 only — the sole Windows build target. Other targets ship no
|
|
* node.exe and the runtime falls open to forking the install-dir Electron host.
|
|
*/
|
|
function ensurePackagedDaemonHostNode(resourcesDir, electronPlatformName) {
|
|
if (electronPlatformName !== 'win32') {
|
|
return
|
|
}
|
|
const nodeExePath = process.execPath
|
|
// The build must run under standalone Node (not Electron) so execPath is a
|
|
// real node.exe with a NAPI runtime; anything else would strand the daemon.
|
|
if (!/node\.exe$/i.test(nodeExePath) || !existsSync(nodeExePath)) {
|
|
throw new Error(
|
|
`[daemon-host] cannot stage node.exe: build host execPath is not a node.exe (${nodeExePath})`
|
|
)
|
|
}
|
|
const destDir = join(resourcesDir, DAEMON_HOST_DIR)
|
|
mkdirSync(destDir, { recursive: true })
|
|
copyFileSync(nodeExePath, join(destDir, DAEMON_HOST_NODE_EXE))
|
|
}
|
|
|
|
module.exports = { ensurePackagedDaemonHostNode, DAEMON_HOST_DIR, DAEMON_HOST_NODE_EXE }
|