@@ -25,6 +25,7 @@ import { DevNullStream } from './dev-null-stream';
2525import { signame } from './utils' ;
2626import { PseudoPty } from './pseudo-pty' ;
2727import { Writable } from 'stream' ;
28+ import * as fs from 'fs' ;
2829
2930export const TerminalProcessOptions = Symbol ( 'TerminalProcessOptions' ) ;
3031export interface TerminalProcessOptions extends ProcessOptions {
@@ -144,13 +145,26 @@ export class TerminalProcess extends Process {
144145 * @returns the terminal PTY and a stream by which it may be sent input
145146 */
146147 private createPseudoTerminal ( command : string , options : TerminalProcessOptions , ringBuffer : MultiRingBuffer ) : { terminal : IPty | undefined , inputStream : Writable } {
148+ // Only test the command file on non-Windows platforms.
149+ // On Windows, calling `spawn` on an invalid file throws an error. On Linux/macOS, it does not.
150+ if ( ! isWindows ) {
151+ try {
152+ const stat = fs . statSync ( command ) ;
153+ if ( stat . isDirectory ( ) ) {
154+ throw new Error ( 'Permission denied' ) ;
155+ }
156+ } catch ( error ) {
157+ throw new Error ( 'File not found: ' + command ) ;
158+ }
159+ }
160+
147161 const terminal = spawn (
148162 command ,
149163 ( isWindows && options . commandLine ) || options . args || [ ] ,
150164 options . options || { }
151165 ) ;
152166
153- process . nextTick ( ( ) => this . emitOnStarted ( ) ) ;
167+ setImmediate ( ( ) => this . emitOnStarted ( { pid : terminal . pid } ) ) ;
154168
155169 // node-pty actually wait for the underlying streams to be closed before emitting exit.
156170 // We should emulate the `exit` and `close` sequence.
0 commit comments