( pid: string | number, maxDepth = 10, )
| 113 | * @returns Array of command strings for the process chain |
| 114 | */ |
| 115 | export async function getAncestorCommandsAsync( |
| 116 | pid: string | number, |
| 117 | maxDepth = 10, |
| 118 | ): Promise<string[]> { |
| 119 | if (process.platform === 'win32') { |
| 120 | // For Windows, use a PowerShell script that walks the process tree and collects commands |
| 121 | const script = ` |
| 122 | $currentPid = ${String(pid)} |
| 123 | $commands = @() |
| 124 | for ($i = 0; $i -lt ${maxDepth}; $i++) { |
| 125 | $proc = Get-CimInstance Win32_Process -Filter "ProcessId=$currentPid" -ErrorAction SilentlyContinue |
| 126 | if (-not $proc) { break } |
| 127 | if ($proc.CommandLine) { $commands += $proc.CommandLine } |
| 128 | if (-not $proc.ParentProcessId -or $proc.ParentProcessId -eq 0) { break } |
| 129 | $currentPid = $proc.ParentProcessId |
| 130 | } |
| 131 | $commands -join [char]0 |
| 132 | `.trim() |
| 133 | |
| 134 | const result = await execFileNoThrowWithCwd( |
| 135 | 'powershell.exe', |
| 136 | ['-NoProfile', '-Command', script], |
| 137 | { timeout: 3000 }, |
| 138 | ) |
| 139 | if (result.code !== 0 || !result.stdout?.trim()) { |
| 140 | return [] |
| 141 | } |
| 142 | return result.stdout.split('\0').filter(Boolean) |
| 143 | } |
| 144 | |
| 145 | // For Unix, use a shell command that walks up the process tree and collects commands |
| 146 | // Using null byte as separator to handle commands with newlines |
| 147 | const script = `currentpid=${String(pid)}; for i in $(seq 1 ${maxDepth}); do cmd=$(ps -o command= -p $currentpid 2>/dev/null); if [ -n "$cmd" ]; then printf '%s\\0' "$cmd"; fi; ppid=$(ps -o ppid= -p $currentpid 2>/dev/null | tr -d ' '); if [ -z "$ppid" ] || [ "$ppid" = "0" ] || [ "$ppid" = "1" ]; then break; fi; currentpid=$ppid; done` |
| 148 | |
| 149 | const result = await execFileNoThrowWithCwd('sh', ['-c', script], { |
| 150 | timeout: 3000, |
| 151 | }) |
| 152 | if (result.code !== 0 || !result.stdout?.trim()) { |
| 153 | return [] |
| 154 | } |
| 155 | return result.stdout.split('\0').filter(Boolean) |
| 156 | } |
| 157 | |
| 158 | /** |
| 159 | * Gets the child process IDs for a given process |
no test coverage detected