Start Comfy without a visible command prompt on the desktop.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,8 +2,9 @@ import http from 'node:http'
|
|||||||
import net from 'node:net'
|
import net from 'node:net'
|
||||||
import { execFile, spawn } from 'node:child_process'
|
import { execFile, spawn } from 'node:child_process'
|
||||||
import { promisify } from 'node:util'
|
import { promisify } from 'node:util'
|
||||||
import { readdirSync, existsSync, rmSync, readFileSync, openSync } from 'node:fs'
|
import { readdirSync, existsSync, rmSync, readFileSync, openSync, mkdirSync, writeFileSync, unlinkSync } from 'node:fs'
|
||||||
import { basename, join, resolve, relative, isAbsolute } from 'node:path'
|
import { basename, dirname, join, resolve, relative, isAbsolute } from 'node:path'
|
||||||
|
import { tmpdir } from 'node:os'
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile)
|
const execFileAsync = promisify(execFile)
|
||||||
const port = Number(process.env.COMFY_CONTROL_PORT || 8199)
|
const port = Number(process.env.COMFY_CONTROL_PORT || 8199)
|
||||||
@@ -235,10 +236,11 @@ function desktopShellCommand() {
|
|||||||
|
|
||||||
async function pythonMainUp() {
|
async function pythonMainUp() {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execFileAsync('wmic', [
|
const { stdout } = await execFileAsync('powershell.exe', [
|
||||||
'process', 'where', "name='python.exe'", 'get', 'commandline'
|
'-NoProfile', '-Command',
|
||||||
|
"Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'ComfyUI\\\\main.py|ComfyUI/main.py' } | Select-Object -First 1 -ExpandProperty ProcessId"
|
||||||
], { windowsHide: true, timeout: 6000 })
|
], { windowsHide: true, timeout: 6000 })
|
||||||
return /main\.py/i.test(String(stdout || ''))
|
return Boolean(String(stdout).trim())
|
||||||
} catch {
|
} catch {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -268,6 +270,70 @@ async function pickListenPort() {
|
|||||||
return preferred
|
return preferred
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function windowlessPython(pythonPath) {
|
||||||
|
if (process.platform !== 'win32') return pythonPath
|
||||||
|
if (!/python\.exe$/i.test(pythonPath)) return pythonPath
|
||||||
|
const pythonw = pythonPath.replace(/python\.exe$/i, 'pythonw.exe')
|
||||||
|
return existsSync(pythonw) ? pythonw : pythonPath
|
||||||
|
}
|
||||||
|
|
||||||
|
function vbsString(value) {
|
||||||
|
return `"${String(value).replace(/"/g, '""')}"`
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawnViaWscript(file, args, opts = {}) {
|
||||||
|
const command = [file, ...args].map((part) => {
|
||||||
|
const text = String(part)
|
||||||
|
return /\s|"/.test(text) ? `"${text.replace(/"/g, '\\"')}"` : text
|
||||||
|
}).join(' ')
|
||||||
|
const lines = ['Set sh = CreateObject("WScript.Shell")']
|
||||||
|
if (opts.cwd) lines.push(`sh.CurrentDirectory = ${vbsString(opts.cwd)}`)
|
||||||
|
lines.push(`sh.Run ${vbsString(command)}, 0, False`)
|
||||||
|
const tmp = join(tmpdir(), `aigen-launch-${process.pid}-${Date.now()}.vbs`)
|
||||||
|
writeFileSync(tmp, `${lines.join('\r\n')}\r\n`)
|
||||||
|
const child = spawn('wscript.exe', ['//B', '//Nologo', tmp], {
|
||||||
|
detached: true,
|
||||||
|
stdio: 'ignore',
|
||||||
|
windowsHide: true
|
||||||
|
})
|
||||||
|
child.unref()
|
||||||
|
const cleanup = () => {
|
||||||
|
try { unlinkSync(tmp) } catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
child.once('exit', cleanup)
|
||||||
|
setTimeout(cleanup, 15000)
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawnHidden(file, args, opts = {}) {
|
||||||
|
const exe = windowlessPython(file)
|
||||||
|
// python.exe + detached:true allocates an empty console on the active display.
|
||||||
|
// pythonw.exe is windowless. If it is missing, launch via hidden WScript.
|
||||||
|
if (process.platform === 'win32' && /python\.exe$/i.test(exe)) {
|
||||||
|
return spawnViaWscript(exe, args, opts)
|
||||||
|
}
|
||||||
|
const child = spawn(exe, args, {
|
||||||
|
detached: true,
|
||||||
|
stdio: opts.stdio || 'ignore',
|
||||||
|
windowsHide: true,
|
||||||
|
cwd: opts.cwd
|
||||||
|
})
|
||||||
|
child.unref()
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawnShellHidden(command, cwd) {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
const match = String(command).match(/start\s+""\s+"([^"]+)"/i)
|
||||||
|
|| String(command).match(/^"([^"]+\.exe)"\s*$/i)
|
||||||
|
if (match) return spawnHidden(match[1], [], { cwd })
|
||||||
|
return spawnViaWscript(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', command], { cwd })
|
||||||
|
}
|
||||||
|
const child = spawn(command, { shell: true, detached: true, stdio: 'ignore', cwd })
|
||||||
|
child.unref()
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
async function startComfy() {
|
async function startComfy() {
|
||||||
markWork()
|
markWork()
|
||||||
const launch = resolveHeadlessLaunch()
|
const launch = resolveHeadlessLaunch()
|
||||||
@@ -277,15 +343,13 @@ async function startComfy() {
|
|||||||
if (portIdx >= 0) launch.args[portIdx + 1] = String(port)
|
if (portIdx >= 0) launch.args[portIdx + 1] = String(port)
|
||||||
let stdio = 'ignore'
|
let stdio = 'ignore'
|
||||||
try {
|
try {
|
||||||
|
mkdirSync(dirname(launch.log), { recursive: true })
|
||||||
stdio = ['ignore', openSync(launch.log, 'a'), openSync(launch.log, 'a')]
|
stdio = ['ignore', openSync(launch.log, 'a'), openSync(launch.log, 'a')]
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
const child = spawn(launch.file, launch.args, {
|
const child = spawnHidden(launch.file, launch.args, {
|
||||||
detached: true,
|
|
||||||
stdio,
|
stdio,
|
||||||
windowsHide: true,
|
|
||||||
cwd: launch.cwd
|
cwd: launch.cwd
|
||||||
})
|
})
|
||||||
child.unref()
|
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({
|
||||||
src: 'comfy-host-agent',
|
src: 'comfy-host-agent',
|
||||||
event: 'start',
|
event: 'start',
|
||||||
@@ -302,14 +366,7 @@ async function startComfy() {
|
|||||||
cwd: launch?.cwd || process.env.COMFY_LAUNCH_CWD || undefined,
|
cwd: launch?.cwd || process.env.COMFY_LAUNCH_CWD || undefined,
|
||||||
mode: launch?.mode || 'desktop-shell'
|
mode: launch?.mode || 'desktop-shell'
|
||||||
}
|
}
|
||||||
const child = spawn(fallback.command, {
|
spawnShellHidden(fallback.command, fallback.cwd)
|
||||||
shell: true,
|
|
||||||
detached: true,
|
|
||||||
stdio: 'ignore',
|
|
||||||
windowsHide: true,
|
|
||||||
cwd: fallback.cwd
|
|
||||||
})
|
|
||||||
child.unref()
|
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({
|
||||||
src: 'comfy-host-agent',
|
src: 'comfy-host-agent',
|
||||||
event: 'start',
|
event: 'start',
|
||||||
|
|||||||
@@ -226,12 +226,18 @@ async function processRunning() {
|
|||||||
|
|
||||||
function spawnLaunchCommand(command: string) {
|
function spawnLaunchCommand(command: string) {
|
||||||
log('spawn', { command: command.slice(0, 180) })
|
log('spawn', { command: command.slice(0, 180) })
|
||||||
const child = spawn(command, {
|
const win = process.platform === 'win32'
|
||||||
shell: true,
|
const exe = win
|
||||||
detached: true,
|
? command.match(/start\s+""\s+"([^"]+)"/i)?.[1] || command.match(/^"([^"]+\.exe)"\s*$/i)?.[1]
|
||||||
stdio: 'ignore',
|
: ''
|
||||||
windowsHide: true
|
const child = exe
|
||||||
})
|
? spawn(exe, [], { detached: true, stdio: 'ignore', windowsHide: true })
|
||||||
|
: spawn(command, {
|
||||||
|
shell: true,
|
||||||
|
detached: !win,
|
||||||
|
stdio: 'ignore',
|
||||||
|
windowsHide: true
|
||||||
|
})
|
||||||
child.unref()
|
child.unref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user