diff --git a/apps/cli/lib/run-wp-cli-command.ts b/apps/cli/lib/run-wp-cli-command.ts index 54bcdd8ab7..cc37a57624 100644 --- a/apps/cli/lib/run-wp-cli-command.ts +++ b/apps/cli/lib/run-wp-cli-command.ts @@ -1,3 +1,4 @@ +import { spawn } from 'node:child_process'; import { rootCertificates } from 'node:tls'; import { loadNodeRuntime, createNodeFsMountHandler } from '@php-wasm/node'; import { @@ -6,8 +7,8 @@ import { PHP, setPhpIniEntries, ProcessIdAllocator, + type SpawnHandler, } from '@php-wasm/universal'; -import { createSpawnHandler } from '@php-wasm/util'; import { IS_JSPI_AVAILABLE } from '@studio/common/lib/jspi'; import { cleanupLegacyMuPlugins, getMuPlugins } from '@studio/common/lib/mu-plugins'; import { LatestSupportedPHPVersion } from '@studio/common/types/php-versions'; @@ -18,22 +19,8 @@ import { getSqliteCommandPath, getWpCliPharPath } from 'cli/lib/server-files'; const processIdAllocator = new ProcessIdAllocator(); const PLAYGROUND_INTERNAL_SHARED_FOLDER = '/internal/shared'; -/** - * Creates a no-op spawn handler that immediately exits with code 1. - * This allows process spawning functions (proc_open, exec, etc.) to be called - * without crashing, but they will fail gracefully. WP-CLI detects these failures - * and falls back to single-threaded mode. - * - * The timeout before exit is required by the createSpawnHandler API — PHP needs - * an event loop tick to set up its stream listeners after proc_open() returns. - * Without it, the process exits before PHP registers its handlers and - * createSpawnHandler throws a "exited synchronously" error. - */ -function createNoopSpawnHandler() { - return createSpawnHandler( async ( args, processApi ) => { - await new Promise( ( resolve ) => setTimeout( resolve, 1 ) ); - processApi.exit( 1 ); - } ); +function createNativeSpawnHandler(): SpawnHandler { + return spawn as unknown as SpawnHandler; } export interface RunWpCliCommandOptions { @@ -77,7 +64,7 @@ export async function runWpCliCommand( allow_url_fopen: 1, } ); - await php.setSpawnHandler( createNoopSpawnHandler() ); + await php.setSpawnHandler( createNativeSpawnHandler() ); await cleanupLegacyMuPlugins( siteFolder ); @@ -137,7 +124,7 @@ export async function runGlobalWpCliCommand( args: string[] ): Promise< Disposab allow_url_fopen: 1, } ); - await php.setSpawnHandler( createNoopSpawnHandler() ); + await php.setSpawnHandler( createNativeSpawnHandler() ); await php.mount( '/tmp/wp-cli.phar', createNodeFsMountHandler( getWpCliPharPath() ) ); diff --git a/apps/cli/wordpress-server-child.ts b/apps/cli/wordpress-server-child.ts index 881a9574de..f391892a53 100644 --- a/apps/cli/wordpress-server-child.ts +++ b/apps/cli/wordpress-server-child.ts @@ -247,6 +247,7 @@ async function getBaseRunCLIArgs( wordpressInstallMode, redis: IS_JSPI_AVAILABLE, memcached: IS_JSPI_AVAILABLE, + nativeSpawn: true, }; if ( config.wpVersion ) {