@@ -220,7 +220,7 @@ const buildWeb = (): Promise<void> =>
220220{
221221 return new Promise < void > ((resolve, reject): void =>
222222 {
223- const stream = cp . spawn ( "npx" , [
223+ const stream = $ spawn( "npx" , [
224224 "@next2d/vite-plugin-next2d-auto-loader"
225225 ] , { "stdio" : "inherit" } ) ;
226226
@@ -230,7 +230,7 @@ const buildWeb = (): Promise<void> =>
230230 reject ( "vite plugin command failed." ) ;
231231 }
232232
233- const stream = cp . spawn ( "npx" , [
233+ const stream = $ spawn( "npx" , [
234234 "vite" ,
235235 "--outDir" ,
236236 $buildDir ,
@@ -267,7 +267,7 @@ const installElectron = (): Promise<void> =>
267267 return resolve ( ) ;
268268 }
269269
270- const stream = cp. spawn("npm", [
270+ const stream = $ spawn("npm", [
271271 "--prefix",
272272 `${ process . cwd ( ) } /electron`,
273273 "install",
@@ -363,7 +363,7 @@ const buildSteam = async (): Promise<void> =>
363363
364364 if ( preview ) {
365365
366- cp . spawn ( "npx" , [
366+ $ spawn( "npx" , [
367367 "electron" ,
368368 `${ process . cwd ( ) } /electron/index.js`
369369 ] , { "stdio" : "inherit" } ) ;
@@ -437,7 +437,7 @@ const generateNativeProject = (): Promise<void> =>
437437 return resolve ( ) ;
438438 }
439439
440- const stream = cp . spawn ( "npx" , [
440+ const stream = $ spawn( "npx" , [
441441 "cap" ,
442442 "add" ,
443443 platform
@@ -484,7 +484,7 @@ const runNative = async (): Promise<void> =>
484484 JSON . stringify ( config , null , 2 )
485485 ) ;
486486
487- cp . spawn ( "npx" , [
487+ $ spawn( "npx" , [
488488 "cap" ,
489489 "run" ,
490490 platform
@@ -518,7 +518,7 @@ const openNative = async (): Promise<void> =>
518518 JSON . stringify ( config , null , 2 )
519519 ) ;
520520
521- const stream = cp . spawn ( "npx" , [
521+ const stream = $ spawn( "npx" , [
522522 "cap" ,
523523 "sync" ,
524524 platform
@@ -531,7 +531,7 @@ const openNative = async (): Promise<void> =>
531531 return ;
532532 }
533533
534- cp . spawn ( "npx" , [
534+ $ spawn( "npx" , [
535535 "cap" ,
536536 "open" ,
537537 platform
@@ -566,7 +566,7 @@ const buildNative = async (): Promise<void> =>
566566 JSON . stringify ( config , null , 2 )
567567 ) ;
568568
569- const stream = cp . spawn ( "npx" , [
569+ const stream = $ spawn( "npx" , [
570570 "cap" ,
571571 "sync" ,
572572 platform
@@ -579,7 +579,7 @@ const buildNative = async (): Promise<void> =>
579579 return ;
580580 }
581581
582- cp . spawn ( "npx" , [
582+ $ spawn( "npx" , [
583583 "cap" ,
584584 "build" ,
585585 platform
@@ -615,6 +615,30 @@ const getTemplateDir = (name: string): string =>
615615 */
616616const XBOX_CONFIG_NAME: string = "MicrosoftGame.config";
617617
618+ /**
619+ * @description npx / npm を子プロセスとして起動する (クロスプラットフォーム)。
620+ * Windows では npx/npm が .cmd (バッチファイル) のため、shell 経由で
621+ * ないと起動できない (spawn ENOENT / Node の CVE-2024-27980 対応により
622+ * .cmd の直接 spawn も不可)。スペースを含む引数は二重引用符で保護する。
623+ * Spawn npx/npm cross-platform. On Windows they are .cmd batch files,
624+ * which require a shell to spawn.
625+ *
626+ * @param { string } command
627+ * @param { array } args
628+ * @param { object } options
629+ * @return { object }
630+ * @method
631+ * @public
632+ */
633+ const $spawn = (command: string, args: string[], options: object = { } ): cp.ChildProcess =>
634+ {
635+ if ( process . platform === "win32" && ( command === "npx" || command === "npm" ) ) {
636+ const quoted : string [ ] = args . map ( ( a : string ) : string => / \s / . test ( a ) ? `"${ a } "` : a ) ;
637+ return cp . spawn ( command , quoted , { ...options , "shell" : true } ) ;
638+ }
639+ return cp.spawn(command, args, options);
640+ } ;
641+
618642/**
619643 * @description 自動ダウンロードする prebuilt V8 のバージョン。
620644 * `.github/workflows/build-v8.yml` で発行した Releases のタグと、
0 commit comments