@@ -1416,14 +1416,72 @@ private static CommandResolution ResolveCommand(ExtensionCommand command)
14161416 "python" => new CommandResolution ( isWindows ? "python.exe" : "python3" ,
14171417 PrependExecutable ( executable , argumentList ) ) ,
14181418 "dotnet" => new CommandResolution ( "dotnet" , PrependExecutable ( executable , argumentList ) ) ,
1419- "npx" => new CommandResolution ( isWindows ? "npx.cmd" : "npx" ,
1420- PrependExecutable ( executable , argumentList ) ) ,
1419+ "npx" => ResolveNpxCommand ( executable , argumentList ) ,
14211420 "pipx" => new CommandResolution ( isWindows ? "pipx.exe" : "pipx" ,
14221421 PrependRun ( executable , argumentList ) ) ,
14231422 _ => new CommandResolution ( executable , argumentList )
14241423 } ;
14251424 }
14261425
1426+ /// <summary>
1427+ /// Resolves npx command by directly executing npx-cli.js with node to avoid
1428+ /// shell script path resolution issues when executed via Process.Start.
1429+ /// Adds --yes flag to auto-confirm package installation since extensions
1430+ /// run non-interactively and cannot respond to prompts.
1431+ /// </summary>
1432+ /// <param name="packageName">The npm package name to execute.</param>
1433+ /// <param name="arguments">Additional arguments for the package.</param>
1434+ /// <returns>A <see cref="CommandResolution" /> for npx execution.</returns>
1435+ private static CommandResolution ResolveNpxCommand ( string packageName , List < string > arguments )
1436+ {
1437+ var npxArgs = new List < string > ( arguments . Count + 2 ) { "--yes" , packageName } ;
1438+ npxArgs . AddRange ( arguments ) ;
1439+
1440+ var isWindows = OperatingSystem . IsWindows ( ) ;
1441+ var npxCliPath = FindNpxCliPath ( isWindows ) ;
1442+
1443+ if ( npxCliPath != null )
1444+ {
1445+ var args = new List < string > ( npxArgs . Count + 1 ) { npxCliPath } ;
1446+ args . AddRange ( npxArgs ) ;
1447+ return new CommandResolution ( isWindows ? "node.exe" : "node" , args ) ;
1448+ }
1449+
1450+ return new CommandResolution ( isWindows ? "npx.cmd" : "npx" , npxArgs ) ;
1451+ }
1452+
1453+ /// <summary>
1454+ /// Finds the path to npx-cli.js by searching PATH for node installation.
1455+ /// </summary>
1456+ /// <param name="isWindows">Whether the current platform is Windows.</param>
1457+ /// <returns>The full path to npx-cli.js, or null if not found.</returns>
1458+ private static string ? FindNpxCliPath ( bool isWindows )
1459+ {
1460+ var pathEnv = Environment . GetEnvironmentVariable ( "PATH" ) ;
1461+ if ( string . IsNullOrEmpty ( pathEnv ) )
1462+ return null ;
1463+
1464+ var nodeExeName = isWindows ? "node.exe" : "node" ;
1465+ var paths = pathEnv . Split ( Path . PathSeparator , StringSplitOptions . RemoveEmptyEntries ) ;
1466+
1467+ foreach ( var path in paths )
1468+ try
1469+ {
1470+ var nodePath = Path . Combine ( path , nodeExeName ) ;
1471+ if ( ! File . Exists ( nodePath ) )
1472+ continue ;
1473+
1474+ var npxCliPath = Path . Combine ( path , "node_modules" , "npm" , "bin" , "npx-cli.js" ) ;
1475+ if ( File . Exists ( npxCliPath ) )
1476+ return npxCliPath ;
1477+ }
1478+ catch
1479+ {
1480+ }
1481+
1482+ return null ;
1483+ }
1484+
14271485 /// <summary>
14281486 /// Prepends the executable path to the argument list.
14291487 /// </summary>
0 commit comments