({ reason, args, logPath })
| 420 | // Users who insist can opt back in with EVOLVER_SUICIDE_WINDOWS=true (and accept |
| 421 | // the popups). |
| 422 | function spawnReplacementProcess({ reason, args, logPath }) { |
| 423 | const isWindows = process.platform === 'win32'; |
| 424 | const allowOnWindows = parseBoolEnv(process.env.EVOLVER_SUICIDE_WINDOWS, false); |
| 425 | if (isWindows && !allowOnWindows) { |
| 426 | console.log( |
| 427 | '[Daemon] Skipping in-process respawn on Windows (' + reason + '). ' + |
| 428 | 'Native Node spawn(detached, windowsHide) opens a cmd popup on every restart (Issue #528). ' + |
| 429 | 'Set EVOLVER_SUICIDE_WINDOWS=true to opt back in. ' + |
| 430 | 'Recommended: run evolver under an external supervisor (NSSM, pm2-windows, etc.) so it restarts on exit.' |
| 431 | ); |
| 432 | return { spawned: false, reason: 'windows_default_skip' }; |
| 433 | } |
| 434 | try { |
| 435 | const logFd = fs.openSync(logPath, 'a'); |
| 436 | const spawnOpts = { |
| 437 | detached: true, |
| 438 | stdio: ['ignore', logFd, logFd], |
| 439 | env: process.env, |
| 440 | windowsHide: true, |
| 441 | }; |
| 442 | const child = spawn(process.execPath, [__filename, ...args], spawnOpts); |
| 443 | child.unref(); |
| 444 | return { spawned: true }; |
| 445 | } catch (e) { |
| 446 | console.error('[Daemon] Spawn-replacement failed (' + reason + '): ' + (e && e.message || e)); |
| 447 | return { spawned: false, reason: 'spawn_error', error: e }; |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | // Atomic write of the cycle_progress.json file. Wrapper polls this file every |
| 452 | // 60s; if updated_at goes stale beyond EVOLVE_INNER_STUCK_TIMEOUT_SEC the |
no test coverage detected