@@ -288,16 +288,23 @@ function envlite_pcntl_exec_available(): bool {
288288}
289289
290290/**
291- * Launches the dev server. On Unix with pcntl available, replaces the current
292- * process via pcntl_exec — same PID, no parent-child relay. On Windows (or
293- * any environment without pcntl_exec), falls back to envlite_proc_stream
294- * which inherits stdio so SIGINT still reaches the child. Returns only on
295- * error or when the fallback child exits.
291+ * Launches the dev server. On Unix, requires pcntl (enforced by Phase 0 at
292+ * init time and re-checked here for safety) and replaces the current process
293+ * via pcntl_exec — same PID, no parent-child relay. On Windows, falls back
294+ * to envlite_proc_stream which inherits stdio so SIGINT still reaches the
295+ * child. Returns only on error or when the Windows- fallback child exits.
296296 */
297297function envlite_run_dev_server (string $ repoRoot , int $ port ): int {
298298 $ argv = envlite_dev_server_argv ($ repoRoot , $ port );
299299
300- if (envlite_pcntl_exec_available ()) {
300+ if (PHP_OS_FAMILY !== 'Windows ' ) {
301+ if (!function_exists ('pcntl_exec ' )) {
302+ // Phase 0 enforces pcntl on Unix, but `serve` skips Phase 0 — so a
303+ // checkout cached from a different system could land here. The spec
304+ // says Unix uses pcntl_exec; do not silently degrade to proc_open.
305+ envlite_log (null , 'pcntl extension is required on Unix; reinstall PHP with pcntl ' );
306+ return 1 ;
307+ }
301308 // pcntl_exec uses the *current* working directory; chdir first so
302309 // `-t src` resolves relative to the repo root, matching the proc_open
303310 // path's $cwd argument.
0 commit comments