fix(desktop): hide Windows console children launched by GUI

This commit is contained in:
Gille
2026-06-10 03:04:54 -07:00
committed by Teknium
parent 189ffe7362
commit 4c797d0e23
4 changed files with 88 additions and 18 deletions
+22 -15
View File
@@ -107,6 +107,13 @@ const IS_WINDOWS = process.platform === 'win32'
const IS_WSL = isWslEnvironment()
const APP_ROOT = app.getAppPath()
function hiddenWindowsChildOptions(options = {}) {
if (!IS_WINDOWS || Object.prototype.hasOwnProperty.call(options, 'windowsHide')) {
return options
}
return { ...options, windowsHide: true }
}
// Remote displays (SSH X11 forwarding, VNC, RDP) make Chromium's GPU
// compositor flicker — accelerated layers can't be presented cleanly over the
// wire, so the window flashes during scroll/streaming/animation. Local
@@ -1106,7 +1113,7 @@ function findSystemPython() {
const out = execFileSync(
'reg',
['query', `${hive}\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath`, '/ve', '/reg:64'],
{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }
hiddenWindowsChildOptions({ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
)
// Output format: " (Default) REG_SZ C:\Path\To\Python\"
const match = out.match(/REG_SZ\s+(.+?)\s*$/m)
@@ -1142,10 +1149,10 @@ function findSystemPython() {
if (pyExe) {
for (const version of SUPPORTED_VERSIONS) {
try {
const out = execFileSync(pyExe, [`-${version}`, '-c', 'import sys; print(sys.executable)'], {
const out = execFileSync(pyExe, [`-${version}`, '-c', 'import sys; print(sys.executable)'], hiddenWindowsChildOptions({
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore']
})
}))
const candidate = out.trim()
if (candidate && fileExists(candidate)) return candidate
} catch {
@@ -1280,11 +1287,11 @@ function resolveUpdateRoot() {
function runGit(args, options = {}) {
return new Promise((resolve, reject) => {
const child = spawn(resolveGitBinary(), IS_WINDOWS ? ['-c', 'windows.appendAtomically=false', ...args] : args, {
const child = spawn(resolveGitBinary(), IS_WINDOWS ? ['-c', 'windows.appendAtomically=false', ...args] : args, hiddenWindowsChildOptions({
cwd: options.cwd,
env: { ...process.env, ...(options.env || {}), GIT_TERMINAL_PROMPT: '0' },
stdio: ['ignore', 'pipe', 'pipe']
})
}))
let stdout = ''
let stderr = ''
@@ -1494,7 +1501,7 @@ function forceKillProcessTree(pid) {
if (!IS_WINDOWS) return
if (!Number.isInteger(pid) || pid <= 0) return
try {
execFileSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore' })
execFileSync('taskkill', ['/PID', String(pid), '/T', '/F'], hiddenWindowsChildOptions({ stdio: 'ignore' }))
} catch {
// Already gone, or no permission — best effort; the unlock wait below is
// the real gate.
@@ -1680,11 +1687,11 @@ function runStreamedUpdate(command, args, { cwd, env, stage } = {}) {
return new Promise(resolve => {
let child
try {
child = spawn(command, args, {
child = spawn(command, args, hiddenWindowsChildOptions({
cwd,
env: { ...process.env, ...(env || {}) },
stdio: ['ignore', 'pipe', 'pipe']
})
}))
} catch (err) {
resolve({ code: 1, error: err.message })
return
@@ -2671,7 +2678,7 @@ function fetchHtmlTitleWithCurl(rawUrl) {
'--raw',
url
]
const child = spawn('curl', args, { stdio: ['ignore', 'pipe', 'ignore'] })
const child = spawn('curl', args, hiddenWindowsChildOptions({ stdio: ['ignore', 'pipe', 'ignore'] }))
const chunks = []
let bytes = 0
@@ -4491,7 +4498,7 @@ async function spawnPoolBackend(profile, entry) {
rememberLog(`Starting Hermes backend for profile "${profile}" via ${backend.label}`)
const child = spawn(backend.command, backend.args, {
const child = spawn(backend.command, backend.args, hiddenWindowsChildOptions({
cwd: hermesCwd,
env: {
...process.env,
@@ -4509,7 +4516,7 @@ async function spawnPoolBackend(profile, entry) {
},
shell: backend.shell,
stdio: ['ignore', 'pipe', 'pipe']
})
}))
entry.process = child
entry.port = port
entry.token = token
@@ -4691,7 +4698,7 @@ async function startHermes() {
await advanceBootProgress('backend.spawn', `Starting Hermes backend via ${backend.label}`, 84)
rememberLog(`Starting Hermes backend via ${backend.label}`)
hermesProcess = spawn(backend.command, backend.args, {
hermesProcess = spawn(backend.command, backend.args, hiddenWindowsChildOptions({
cwd: hermesCwd,
env: {
...process.env,
@@ -4714,7 +4721,7 @@ async function startHermes() {
},
shell: backend.shell,
stdio: ['ignore', 'pipe', 'pipe']
})
}))
hermesProcess.stdout.on('data', rememberLog)
hermesProcess.stderr.on('data', rememberLog)
@@ -5986,11 +5993,11 @@ async function getUninstallSummary() {
resolve(value)
}
try {
const child = spawn(py, ['-m', 'hermes_cli.main', 'uninstall', '--gui-summary'], {
const child = spawn(py, ['-m', 'hermes_cli.main', 'uninstall', '--gui-summary'], hiddenWindowsChildOptions({
cwd: agentRoot,
env: { ...process.env, HERMES_HOME, NO_COLOR: '1' },
stdio: ['ignore', 'pipe', 'ignore']
})
}))
child.stdout.on('data', chunk => {
stdout += chunk.toString()
})