@@ -381,21 +381,9 @@ export class LanguageClientManager {
381381 ? 'powershell.exe -command "Get-CimInstance -ClassName Win32_Process | ForEach-Object { [PSCustomObject]@{ ProcessId = $_.ProcessId; ParentProcessId = $_.ParentProcessId; CommandLine = $_.CommandLine } } | Format-Table -HideTableHeaders"'
382382 : 'ps -e -o pid,ppid,command' ;
383383
384- const stdout = execSync ( cmd ) . toString ( ) ;
385- return stdout
386- . trim ( )
387- . split ( / \r ? \n / g)
388- . map ( ( line : string ) => {
389- const [ pidStr , ppidStr , ...commandParts ] = line . trim ( ) . split ( / \s + / ) ;
390- const pid = parseInt ( pidStr , 10 ) ;
391- const ppid = parseInt ( ppidStr , 10 ) ;
392- const command = commandParts . join ( ' ' ) ;
393- return { pid, ppid, command, orphaned : false } ;
394- } )
395- . filter (
396- ( processInfo : ProcessDetail ) => ! [ 'ps' , 'grep' , 'Get-CimInstance' ] . some ( c => processInfo . command . includes ( c ) )
397- )
398- . filter ( ( processInfo : ProcessDetail ) => processInfo . command . includes ( 'apex-jorje-lsp.jar' ) )
384+ const entries = this . parseApexLspPsOutput ( execSync ( cmd ) . toString ( ) ) ;
385+ return entries
386+ . map ( p => ( { ...p , orphaned : false } ) )
399387 . map ( processInfo => {
400388 const checkOrphanedCmd = isWindows
401389 ? `powershell.exe -command "Get-CimInstance -ClassName Win32_Process -Filter 'ProcessId = ${ processInfo . ppid } '"`
@@ -422,6 +410,30 @@ export class LanguageClientManager {
422410 process . kill ( pid , 'SIGKILL' ) ;
423411 }
424412
413+ /**
414+ * Parse ps/PowerShell stdout into Apex LS process entries.
415+ * Expects "pid ppid command" format (Unix ps -e -o pid,ppid,command).
416+ * Also handles Win32_Process output with ProcessId, ParentProcessId, CommandLine.
417+ */
418+ private parseApexLspPsOutput ( stdout : string ) : { pid : number ; ppid : number ; command : string } [ ] {
419+ const skipCommands = [ 'ps' , 'grep' , 'Get-CimInstance' ] ;
420+ const apexJar = 'apex-jorje-lsp.jar' ;
421+ return stdout
422+ . trim ( )
423+ . split ( / \r ? \n / g)
424+ . map ( line => {
425+ const parts = line . trim ( ) . split ( / \s + / ) ;
426+ if ( parts . length < 3 ) return null ;
427+ const pid = parseInt ( parts [ 0 ] , 10 ) ;
428+ const ppid = parseInt ( parts [ 1 ] , 10 ) ;
429+ const command = parts . slice ( 2 ) . join ( ' ' ) ;
430+ if ( Number . isNaN ( pid ) || Number . isNaN ( ppid ) ) return null ;
431+ return { pid, ppid, command } ;
432+ } )
433+ . filter ( ( p ) : p is NonNullable < typeof p > => p !== null )
434+ . filter ( p => ! skipCommands . some ( c => p . command . includes ( c ) ) && p . command . includes ( apexJar ) ) ;
435+ }
436+
425437 /**
426438 * Find and SIGKILL Apex LS processes that are direct children of the current process.
427439 * Used when LSP shutdown times out so the extension host can exit (child's stdio pipes close).
@@ -432,24 +444,34 @@ export class LanguageClientManager {
432444 return ;
433445 }
434446 const parentPid = process . pid ;
435- const cmd = isWindows
436- ? `powershell.exe -command "Get-CimInstance -ClassName Win32_Process | Where-Object { $_.ParentProcessId -eq ${ parentPid } } | ForEach-Object { [PSCustomObject]@{ ProcessId = $_.ProcessId; CommandLine = $_.CommandLine } } | Format-Table -HideTableHeaders"`
437- : 'ps -e -o pid,ppid,command' ;
438447 try {
439- const stdout = execSync ( cmd ) . toString ( ) ;
440- const lines = stdout . trim ( ) . split ( / \r ? \n / g) ;
441- for ( const line of lines ) {
442- const parts = line . trim ( ) . split ( / \s + / ) ;
443- if ( parts . length < 3 ) continue ;
444- const pid = parseInt ( parts [ 0 ] , 10 ) ;
445- const ppid = parseInt ( parts [ 1 ] , 10 ) ;
446- const command = parts . slice ( 2 ) . join ( ' ' ) ;
447- if ( Number . isNaN ( pid ) || Number . isNaN ( ppid ) ) continue ;
448- if ( ppid === parentPid && command . includes ( 'apex-jorje-lsp.jar' ) ) {
449- try {
450- this . terminateProcess ( pid ) ;
451- } catch {
452- // Process may already be gone
448+ if ( isWindows ) {
449+ const cmd = `powershell.exe -command "Get-CimInstance -ClassName Win32_Process | Where-Object { $_.ParentProcessId -eq ${ parentPid } } | ForEach-Object { [PSCustomObject]@{ ProcessId = $_.ProcessId; CommandLine = $_.CommandLine } } | Format-Table -HideTableHeaders"` ;
450+ const stdout = execSync ( cmd ) . toString ( ) ;
451+ const lines = stdout . trim ( ) . split ( / \r ? \n / g) ;
452+ for ( const line of lines ) {
453+ const parts = line . trim ( ) . split ( / \s + / ) ;
454+ if ( parts . length < 2 ) continue ;
455+ const pid = parseInt ( parts [ 0 ] , 10 ) ;
456+ const command = parts . slice ( 1 ) . join ( ' ' ) ;
457+ if ( Number . isNaN ( pid ) ) continue ;
458+ if ( command . includes ( 'apex-jorje-lsp.jar' ) ) {
459+ try {
460+ this . terminateProcess ( pid ) ;
461+ } catch {
462+ // Process may already be gone
463+ }
464+ }
465+ }
466+ } else {
467+ const stdout = execSync ( 'ps -e -o pid,ppid,command' ) . toString ( ) ;
468+ for ( const p of this . parseApexLspPsOutput ( stdout ) ) {
469+ if ( p . ppid === parentPid ) {
470+ try {
471+ this . terminateProcess ( p . pid ) ;
472+ } catch {
473+ // Process may already be gone
474+ }
453475 }
454476 }
455477 }
0 commit comments