From 9a33329d14adcb54a81f2cf8db33a40651f565f9 Mon Sep 17 00:00:00 2001 From: ZA139 Date: Tue, 24 Mar 2026 19:58:28 +0800 Subject: [PATCH 1/3] Use windows-process-tree on Windows for process listing Add @vscode/windows-process-tree as a dependency and use it on Windows to enumerate processes (via promisified getAllProcesses). Fall back to the existing WMIC parser when windows-process-tree is unavailable. Update provider logic to return parsed process items from the native API on Windows and keep PS-based listing for macOS/Linux. Update unit tests to stub and exercise the new getAllProcesses flow and the WMIC fallback, and add webpack externals entry for the new native module. --- package-lock.json | 35 +++ package.json | 1 + .../debugger/attachQuickPick/provider.ts | 37 ++- .../attachQuickPick/provider.unit.test.ts | 236 ++++++++++++++++-- webpack.config.js | 1 + 5 files changed, 276 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 83c15964..0bb3dd42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@vscode/debugprotocol": "^1.65.0", "@vscode/extension-telemetry": "^0.8.4", "@vscode/python-extension": "^1.0.6", + "@vscode/windows-process-tree": "^0.7.0", "fs-extra": "^11.2.0", "iconv-lite": "^0.6.3", "jsonc-parser": "^3.0.0", @@ -1830,6 +1831,25 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@vscode/windows-process-tree": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@vscode/windows-process-tree/-/windows-process-tree-0.7.0.tgz", + "integrity": "sha512-uH58Fofu1bgiulsY2svyGOLLKAYNJ0Req4PioPd7BZzHRziuiBRw1SxyT7wvsYHvm7eKWwzwo6mZpExDfwX9iA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "7.1.0" + } + }, + "node_modules/@vscode/windows-process-tree/node_modules/node-addon-api": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", + "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==", + "license": "MIT", + "engines": { + "node": "^16 || ^18 || >= 20" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -9096,6 +9116,21 @@ "dev": true, "optional": true }, + "@vscode/windows-process-tree": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@vscode/windows-process-tree/-/windows-process-tree-0.7.0.tgz", + "integrity": "sha512-uH58Fofu1bgiulsY2svyGOLLKAYNJ0Req4PioPd7BZzHRziuiBRw1SxyT7wvsYHvm7eKWwzwo6mZpExDfwX9iA==", + "requires": { + "node-addon-api": "7.1.0" + }, + "dependencies": { + "node-addon-api": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", + "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==" + } + } + }, "@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", diff --git a/package.json b/package.json index e7c53f08..381f4564 100644 --- a/package.json +++ b/package.json @@ -682,6 +682,7 @@ "@vscode/debugprotocol": "^1.65.0", "@vscode/extension-telemetry": "^0.8.4", "@vscode/python-extension": "^1.0.6", + "@vscode/windows-process-tree": "^0.7.0", "fs-extra": "^11.2.0", "iconv-lite": "^0.6.3", "jsonc-parser": "^3.0.0", diff --git a/src/extension/debugger/attachQuickPick/provider.ts b/src/extension/debugger/attachQuickPick/provider.ts index 8699f479..3e768649 100644 --- a/src/extension/debugger/attachQuickPick/provider.ts +++ b/src/extension/debugger/attachQuickPick/provider.ts @@ -3,7 +3,9 @@ 'use strict'; +import { promisify } from 'util'; import { l10n } from 'vscode'; +import * as wpc from '@vscode/windows-process-tree'; import { getOSType, OSType } from '../../common/platform'; import { PsProcessParser } from './psProcessParser'; import { IAttachItem, IAttachProcessProvider, ProcessListCommand } from './types'; @@ -58,14 +60,38 @@ export class AttachProcessProvider implements IAttachProcessProvider { } public async _getInternalProcessEntries(): Promise { - let processCmd: ProcessListCommand; const osType = getOSType(); + + if (osType === OSType.Windows) { + try { + const getAllProcesses = promisify(wpc.getAllProcesses); + const processList = await getAllProcesses(wpc.ProcessDataFlag.CommandLine); + return processList.map((p) => ({ + label: p.name, + description: String(p.pid), + detail: p.commandLine || '', + id: String(p.pid), + processName: p.name, + commandLine: p.commandLine || '', + })); + } catch { + const customEnvVars = await getEnvironmentVariables(); + const output = await plainExec( + WmicProcessParser.wmicCommand.command, + WmicProcessParser.wmicCommand.args, + { throwOnStdErr: true }, + customEnvVars, + ); + logProcess(WmicProcessParser.wmicCommand.command, WmicProcessParser.wmicCommand.args, { throwOnStdErr: true }); + return WmicProcessParser.parseProcesses(output.stdout); + } + } + + let processCmd: ProcessListCommand; if (osType === OSType.OSX) { processCmd = PsProcessParser.psDarwinCommand; } else if (osType === OSType.Linux) { processCmd = PsProcessParser.psLinuxCommand; - } else if (osType === OSType.Windows) { - processCmd = WmicProcessParser.wmicCommand; } else { throw new Error(l10n.t("Operating system '{0}' not supported.", osType)); } @@ -73,9 +99,6 @@ export class AttachProcessProvider implements IAttachProcessProvider { const customEnvVars = await getEnvironmentVariables(); const output = await plainExec(processCmd.command, processCmd.args, { throwOnStdErr: true }, customEnvVars); logProcess(processCmd.command, processCmd.args, { throwOnStdErr: true }); - - return osType === OSType.Windows - ? WmicProcessParser.parseProcesses(output.stdout) - : PsProcessParser.parseProcesses(output.stdout); + return PsProcessParser.parseProcesses(output.stdout); } } diff --git a/src/test/unittest/attachQuickPick/provider.unit.test.ts b/src/test/unittest/attachQuickPick/provider.unit.test.ts index 259eaa07..90b5dbec 100644 --- a/src/test/unittest/attachQuickPick/provider.unit.test.ts +++ b/src/test/unittest/attachQuickPick/provider.unit.test.ts @@ -13,6 +13,7 @@ import { IAttachItem } from '../../../extension/debugger/attachQuickPick/types'; import { WmicProcessParser } from '../../../extension/debugger/attachQuickPick/wmicProcessParser'; import * as platform from '../../../extension/common/platform'; import * as rawProcessApis from '../../../extension/common/process/rawProcessApis'; +import * as wpc from '@vscode/windows-process-tree'; use(chaiAsPromised); @@ -20,11 +21,13 @@ suite('Attach to process - process provider', () => { let provider: AttachProcessProvider; let getOSTypeStub: sinon.SinonStub; let plainExecStub: sinon.SinonStub; + let getAllProcessesStub: sinon.SinonStub; setup(() => { provider = new AttachProcessProvider(); getOSTypeStub = sinon.stub(platform, 'getOSType'); plainExecStub = sinon.stub(rawProcessApis, 'plainExec'); + getAllProcessesStub = sinon.stub(wpc, 'getAllProcesses'); }); teardown(() => { @@ -128,21 +131,17 @@ suite('Attach to process - process provider', () => { assert.deepEqual(attachItems, expectedOutput); }); - test('The Windows process list command should be called if the platform is Windows', async () => { - const windowsOutput = `CommandLine=\r -Name=System\r -ProcessId=4\r -\r -\r -CommandLine=sihost.exe\r -Name=sihost.exe\r -ProcessId=5728\r -\r -\r -CommandLine=C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc\r -Name=svchost.exe\r -ProcessId=5912\r -`; + test('The Windows process list should be obtained via getAllProcesses if the platform is Windows', async () => { + const processList = [ + { pid: 4, ppid: 0, name: 'System', commandLine: '' }, + { pid: 5728, ppid: 1, name: 'sihost.exe', commandLine: 'sihost.exe' }, + { + pid: 5912, + ppid: 1, + name: 'svchost.exe', + commandLine: 'C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc', + }, + ]; const expectedOutput: IAttachItem[] = [ { label: 'System', @@ -170,19 +169,10 @@ ProcessId=5912\r }, ]; getOSTypeStub.returns(platform.OSType.Windows); - plainExecStub - .withArgs(WmicProcessParser.wmicCommand.command, sinon.match.any, sinon.match.any, sinon.match.any) - .resolves({ stdout: windowsOutput }); + getAllProcessesStub.callsFake((callback: Function) => callback(processList)); const attachItems = await provider._getInternalProcessEntries(); - sinon.assert.calledOnceWithExactly( - plainExecStub, - WmicProcessParser.wmicCommand.command, - WmicProcessParser.wmicCommand.args, - sinon.match.any, - sinon.match.any, - ); - + sinon.assert.notCalled(plainExecStub); assert.deepEqual(attachItems, expectedOutput); }); @@ -308,6 +298,195 @@ ProcessId=5912\r }); test('Items returned by getAttachItems should be sorted alphabetically', async () => { + const processList = [ + { pid: 4, ppid: 0, name: 'System', commandLine: '' }, + { pid: 5372, ppid: 1, name: 'svchost.exe', commandLine: '' }, + { pid: 5728, ppid: 1, name: 'sihost.exe', commandLine: 'sihost.exe' }, + ]; + const expectedOutput: IAttachItem[] = [ + { + label: 'sihost.exe', + description: '5728', + detail: 'sihost.exe', + id: '5728', + processName: 'sihost.exe', + commandLine: 'sihost.exe', + }, + { + label: 'svchost.exe', + description: '5372', + detail: '', + id: '5372', + processName: 'svchost.exe', + commandLine: '', + }, + { + label: 'System', + description: '4', + detail: '', + id: '4', + processName: 'System', + commandLine: '', + }, + ]; + + getAllProcessesStub.callsFake((callback: Function) => callback(processList)); + + const output = await provider.getAttachItems(); + + assert.deepEqual(output, expectedOutput); + }); + + test('Python processes should be at the top of the list returned by getAttachItems', async () => { + const processList = [ + { pid: 4, ppid: 0, name: 'System', commandLine: '' }, + { pid: 5372, ppid: 1, name: 'svchost.exe', commandLine: '' }, + { pid: 5728, ppid: 1, name: 'sihost.exe', commandLine: 'sihost.exe' }, + { + pid: 5912, + ppid: 1, + name: 'svchost.exe', + commandLine: 'C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc', + }, + { + pid: 6028, + ppid: 1, + name: 'python.exe', + commandLine: + 'C:\\Users\\Contoso\\AppData\\Local\\Programs\\Python\\Python37\\python.exe c:/Users/Contoso/Documents/hello_world.py', + }, + { + pid: 8026, + ppid: 1, + name: 'python.exe', + commandLine: + 'C:\\Users\\Contoso\\AppData\\Local\\Programs\\Python\\Python37\\python.exe c:/Users/Contoso/Documents/foo_bar.py', + }, + ]; + const expectedOutput: IAttachItem[] = [ + { + label: 'python.exe', + description: '8026', + detail: 'C:\\Users\\Contoso\\AppData\\Local\\Programs\\Python\\Python37\\python.exe c:/Users/Contoso/Documents/foo_bar.py', + id: '8026', + processName: 'python.exe', + commandLine: + 'C:\\Users\\Contoso\\AppData\\Local\\Programs\\Python\\Python37\\python.exe c:/Users/Contoso/Documents/foo_bar.py', + }, + { + label: 'python.exe', + description: '6028', + detail: 'C:\\Users\\Contoso\\AppData\\Local\\Programs\\Python\\Python37\\python.exe c:/Users/Contoso/Documents/hello_world.py', + id: '6028', + processName: 'python.exe', + commandLine: + 'C:\\Users\\Contoso\\AppData\\Local\\Programs\\Python\\Python37\\python.exe c:/Users/Contoso/Documents/hello_world.py', + }, + { + label: 'sihost.exe', + description: '5728', + detail: 'sihost.exe', + id: '5728', + processName: 'sihost.exe', + commandLine: 'sihost.exe', + }, + { + label: 'svchost.exe', + description: '5372', + detail: '', + id: '5372', + processName: 'svchost.exe', + commandLine: '', + }, + { + label: 'svchost.exe', + description: '5912', + detail: 'C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc', + id: '5912', + processName: 'svchost.exe', + commandLine: 'C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc', + }, + { + label: 'System', + description: '4', + detail: '', + id: '4', + processName: 'System', + commandLine: '', + }, + ]; + + getAllProcessesStub.callsFake((callback: Function) => callback(processList)); + + const output = await provider.getAttachItems(); + + assert.deepEqual(output, expectedOutput); + }); + }); + + suite('Windows getAttachItems - wmic fallback', () => { + setup(() => { + getOSTypeStub.returns(platform.OSType.Windows); + }); + + test('Should fall back to wmic when getAllProcesses fails', async () => { + getAllProcessesStub.callsFake((_callback: Function) => { + throw new Error('windows-process-tree unavailable'); + }); + const windowsOutput = `CommandLine=\r +Name=System\r +ProcessId=4\r +\r +\r +CommandLine=sihost.exe\r +Name=sihost.exe\r +ProcessId=5728\r +\r +\r +CommandLine=C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc\r +Name=svchost.exe\r +ProcessId=5912\r +`; + const expectedOutput: IAttachItem[] = [ + { + label: 'System', + description: '4', + detail: '', + id: '4', + processName: 'System', + commandLine: '', + }, + { + label: 'sihost.exe', + description: '5728', + detail: 'sihost.exe', + id: '5728', + processName: 'sihost.exe', + commandLine: 'sihost.exe', + }, + { + label: 'svchost.exe', + description: '5912', + detail: 'C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc', + id: '5912', + processName: 'svchost.exe', + commandLine: 'C:\\WINDOWS\\system32\\svchost.exe -k UnistackSvcGroup -s CDPUserSvc', + }, + ]; + + plainExecStub + .withArgs(WmicProcessParser.wmicCommand.command, sinon.match.any, sinon.match.any, sinon.match.any) + .resolves({ stdout: windowsOutput }); + + const attachItems = await provider._getInternalProcessEntries(); + sinon.assert.calledOnce(plainExecStub); + assert.deepEqual(attachItems, expectedOutput); + }); + + test('Items returned by getAttachItems via wmic fallback should be sorted alphabetically', async () => { + getAllProcessesStub.callsFake((_callback: Function) => { + throw new Error('windows-process-tree unavailable'); + }); const windowsOutput = `CommandLine=\r Name=System\r ProcessId=4\r @@ -358,7 +537,10 @@ ProcessId=5728\r assert.deepEqual(output, expectedOutput); }); - test('Python processes should be at the top of the list returned by getAttachItems', async () => { + test('Python processes should be at the top of the list returned by getAttachItems via wmic fallback', async () => { + getAllProcessesStub.callsFake((_callback: Function) => { + throw new Error('windows-process-tree unavailable'); + }); const windowsOutput = `CommandLine=\r Name=System\r ProcessId=4\r diff --git a/webpack.config.js b/webpack.config.js index 5f815e0f..5fe62a66 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -38,6 +38,7 @@ const extensionConfig = { '@opentelemetry/instrumentation': 'commonjs @opentelemetry/instrumentation', // ignored because we don't ship instrumentation '@azure/opentelemetry-instrumentation-azure-sdk': 'commonjs @azure/opentelemetry-instrumentation-azure-sdk', // ignored because we don't ship instrumentation '@azure/functions-core': '@azure/functions-core', // ignored because we don't ship instrumentation + '@vscode/windows-process-tree': 'commonjs @vscode/windows-process-tree', }, resolve: { // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader From ac58e462e7c36102392cd126eda08c36ee6ac2fd Mon Sep 17 00:00:00 2001 From: ZA139 <40553487+ZA139@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:39:27 +0800 Subject: [PATCH 2/3] Update tests for getAllProcesses signature Adjust Windows process provider unit tests to match the updated getAllProcesses API that accepts a flag parameter and uses an error-first callback. Stubs now use signatures like (_flag, callback) and call callback(null, processList); throwing stubs were updated to accept two arguments. These are test-only updates to align with the new function signature. --- .../unittest/attachQuickPick/provider.unit.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/unittest/attachQuickPick/provider.unit.test.ts b/src/test/unittest/attachQuickPick/provider.unit.test.ts index 90b5dbec..5cd4e013 100644 --- a/src/test/unittest/attachQuickPick/provider.unit.test.ts +++ b/src/test/unittest/attachQuickPick/provider.unit.test.ts @@ -169,7 +169,7 @@ suite('Attach to process - process provider', () => { }, ]; getOSTypeStub.returns(platform.OSType.Windows); - getAllProcessesStub.callsFake((callback: Function) => callback(processList)); + getAllProcessesStub.callsFake((_flag: any,callback: Function) => callback(null,processList)); const attachItems = await provider._getInternalProcessEntries(); sinon.assert.notCalled(plainExecStub); @@ -330,7 +330,7 @@ suite('Attach to process - process provider', () => { }, ]; - getAllProcessesStub.callsFake((callback: Function) => callback(processList)); + getAllProcessesStub.callsFake((_flag: any,callback: Function) => callback(null,processList)); const output = await provider.getAttachItems(); @@ -416,7 +416,7 @@ suite('Attach to process - process provider', () => { }, ]; - getAllProcessesStub.callsFake((callback: Function) => callback(processList)); + getAllProcessesStub.callsFake((_flag: any,callback: Function) => callback(null,processList)); const output = await provider.getAttachItems(); @@ -430,7 +430,7 @@ suite('Attach to process - process provider', () => { }); test('Should fall back to wmic when getAllProcesses fails', async () => { - getAllProcessesStub.callsFake((_callback: Function) => { + getAllProcessesStub.callsFake((_flag: any,_callback: Function) => { throw new Error('windows-process-tree unavailable'); }); const windowsOutput = `CommandLine=\r @@ -484,7 +484,7 @@ ProcessId=5912\r }); test('Items returned by getAttachItems via wmic fallback should be sorted alphabetically', async () => { - getAllProcessesStub.callsFake((_callback: Function) => { + getAllProcessesStub.callsFake((_flag: any,_callback: Function) => { throw new Error('windows-process-tree unavailable'); }); const windowsOutput = `CommandLine=\r @@ -538,7 +538,7 @@ ProcessId=5728\r }); test('Python processes should be at the top of the list returned by getAttachItems via wmic fallback', async () => { - getAllProcessesStub.callsFake((_callback: Function) => { + getAllProcessesStub.callsFake((_flag: any,_callback: Function) => { throw new Error('windows-process-tree unavailable'); }); const windowsOutput = `CommandLine=\r From 4a5f3d7c5e8751d478b9aa2bd1805b6b964058a4 Mon Sep 17 00:00:00 2001 From: ZA139 Date: Mon, 30 Mar 2026 20:09:39 +0800 Subject: [PATCH 3/3] Wrap wpc.getAllProcesses in a Promise Replace use of util.promisify with an explicit Promise wrapper around wpc.getAllProcesses, removing the promisify import and adapting the call site to resolve with the process list. Update unit tests to match the changed callback shape (stubs now call callback(processList) and throw without an error-first parameter). This keeps Windows process enumeration working while aligning with the windows-process-tree callback behavior. --- src/extension/debugger/attachQuickPick/provider.ts | 6 +++--- .../unittest/attachQuickPick/provider.unit.test.ts | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/extension/debugger/attachQuickPick/provider.ts b/src/extension/debugger/attachQuickPick/provider.ts index 3e768649..41f758d0 100644 --- a/src/extension/debugger/attachQuickPick/provider.ts +++ b/src/extension/debugger/attachQuickPick/provider.ts @@ -3,7 +3,6 @@ 'use strict'; -import { promisify } from 'util'; import { l10n } from 'vscode'; import * as wpc from '@vscode/windows-process-tree'; import { getOSType, OSType } from '../../common/platform'; @@ -64,8 +63,9 @@ export class AttachProcessProvider implements IAttachProcessProvider { if (osType === OSType.Windows) { try { - const getAllProcesses = promisify(wpc.getAllProcesses); - const processList = await getAllProcesses(wpc.ProcessDataFlag.CommandLine); + const processList = await new Promise((resolve) => { + wpc.getAllProcesses((processes) => resolve(processes), wpc.ProcessDataFlag.CommandLine); + }); return processList.map((p) => ({ label: p.name, description: String(p.pid), diff --git a/src/test/unittest/attachQuickPick/provider.unit.test.ts b/src/test/unittest/attachQuickPick/provider.unit.test.ts index 5cd4e013..90b5dbec 100644 --- a/src/test/unittest/attachQuickPick/provider.unit.test.ts +++ b/src/test/unittest/attachQuickPick/provider.unit.test.ts @@ -169,7 +169,7 @@ suite('Attach to process - process provider', () => { }, ]; getOSTypeStub.returns(platform.OSType.Windows); - getAllProcessesStub.callsFake((_flag: any,callback: Function) => callback(null,processList)); + getAllProcessesStub.callsFake((callback: Function) => callback(processList)); const attachItems = await provider._getInternalProcessEntries(); sinon.assert.notCalled(plainExecStub); @@ -330,7 +330,7 @@ suite('Attach to process - process provider', () => { }, ]; - getAllProcessesStub.callsFake((_flag: any,callback: Function) => callback(null,processList)); + getAllProcessesStub.callsFake((callback: Function) => callback(processList)); const output = await provider.getAttachItems(); @@ -416,7 +416,7 @@ suite('Attach to process - process provider', () => { }, ]; - getAllProcessesStub.callsFake((_flag: any,callback: Function) => callback(null,processList)); + getAllProcessesStub.callsFake((callback: Function) => callback(processList)); const output = await provider.getAttachItems(); @@ -430,7 +430,7 @@ suite('Attach to process - process provider', () => { }); test('Should fall back to wmic when getAllProcesses fails', async () => { - getAllProcessesStub.callsFake((_flag: any,_callback: Function) => { + getAllProcessesStub.callsFake((_callback: Function) => { throw new Error('windows-process-tree unavailable'); }); const windowsOutput = `CommandLine=\r @@ -484,7 +484,7 @@ ProcessId=5912\r }); test('Items returned by getAttachItems via wmic fallback should be sorted alphabetically', async () => { - getAllProcessesStub.callsFake((_flag: any,_callback: Function) => { + getAllProcessesStub.callsFake((_callback: Function) => { throw new Error('windows-process-tree unavailable'); }); const windowsOutput = `CommandLine=\r @@ -538,7 +538,7 @@ ProcessId=5728\r }); test('Python processes should be at the top of the list returned by getAttachItems via wmic fallback', async () => { - getAllProcessesStub.callsFake((_flag: any,_callback: Function) => { + getAllProcessesStub.callsFake((_callback: Function) => { throw new Error('windows-process-tree unavailable'); }); const windowsOutput = `CommandLine=\r