Skip to content

Commit 0d9050d

Browse files
committed
Use windows-process-tree for Windows process list
Add support for @vscode/windows-process-tree to obtain process lists on Windows by promisifying getAllProcesses and mapping results to attach items, with a fallback to WMIC if the native module fails. Add unit tests covering successful retrieval, fallback behavior, sorting and Python-priority ordering. Update package.json and package-lock to include the new dependency and adjust webpack.config.js to exclude the native module from the bundle. Include a local .claude settings file for development permissions.
1 parent 4d84261 commit 0d9050d

File tree

5 files changed

+293
-28
lines changed

5 files changed

+293
-28
lines changed

package-lock.json

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@
682682
"@vscode/debugprotocol": "^1.65.0",
683683
"@vscode/extension-telemetry": "^0.8.4",
684684
"@vscode/python-extension": "^1.0.6",
685+
"@vscode/windows-process-tree": "^0.7.0",
685686
"fs-extra": "^11.2.0",
686687
"iconv-lite": "^0.6.3",
687688
"jsonc-parser": "^3.0.0",

src/extension/debugger/attachQuickPick/provider.ts

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import { getEnvironmentVariables } from '../../common/python';
1212
import { plainExec } from '../../common/process/rawProcessApis';
1313
import { logProcess } from '../../common/process/logger';
1414
import { WmicProcessParser } from './wmicProcessParser';
15+
import { promisify } from 'util';
16+
import * as wpc from '@vscode/windows-process-tree';
17+
import { ProcessDataFlag } from '@vscode/windows-process-tree';
1518

1619
export class AttachProcessProvider implements IAttachProcessProvider {
1720
constructor() {}
@@ -58,46 +61,71 @@ export class AttachProcessProvider implements IAttachProcessProvider {
5861
});
5962
}
6063

64+
/**
65+
* Get processes via wmic (fallback)
66+
*/
67+
private async _getProcessesViaWmic(): Promise<IAttachItem[]> {
68+
const customEnvVars = await getEnvironmentVariables();
69+
const output = await plainExec(
70+
WmicProcessParser.wmicCommand.command,
71+
WmicProcessParser.wmicCommand.args,
72+
{ throwOnStdErr: true },
73+
customEnvVars,
74+
);
75+
logProcess(WmicProcessParser.wmicCommand.command, WmicProcessParser.wmicCommand.args, { throwOnStdErr: true });
76+
return WmicProcessParser.parseProcesses(output.stdout);
77+
}
78+
79+
/**
80+
* Get processes via Ps parser (Linux/macOS)
81+
*/
82+
private async _getProcessesViaPsParser(cmd: ProcessListCommand): Promise<IAttachItem[]> {
83+
const customEnvVars = await getEnvironmentVariables();
84+
const output = await plainExec(cmd.command, cmd.args, { throwOnStdErr: true }, customEnvVars);
85+
logProcess(cmd.command, cmd.args, { throwOnStdErr: true });
86+
return PsProcessParser.parseProcesses(output.stdout);
87+
}
88+
6189
public async _getInternalProcessEntries(specCommand?: ProcessListCommand): Promise<IAttachItem[]> {
62-
let processCmd: ProcessListCommand;
6390
if (specCommand === undefined) {
6491
const osType = getOSType();
6592
if (osType === OSType.OSX) {
66-
processCmd = PsProcessParser.psDarwinCommand;
93+
return this._getProcessesViaPsParser(PsProcessParser.psDarwinCommand);
6794
} else if (osType === OSType.Linux) {
68-
processCmd = PsProcessParser.psLinuxCommand;
95+
return this._getProcessesViaPsParser(PsProcessParser.psLinuxCommand);
6996
} else if (osType === OSType.Windows) {
70-
processCmd = PowerShellProcessParser.powerShellCommand;
97+
try {
98+
const getAllProcesses = promisify(wpc.getAllProcesses) as (flags?: ProcessDataFlag) => Promise<wpc.IProcessInfo[]>;
99+
const processList = await getAllProcesses(ProcessDataFlag.CommandLine);
100+
101+
return processList.map((p) => ({
102+
label: p.name,
103+
description: String(p.pid),
104+
detail: p.commandLine || '',
105+
id: String(p.pid),
106+
processName: p.name,
107+
commandLine: p.commandLine || '',
108+
}));
109+
} catch (error) {
110+
console.error('Failed to get processes via windows-process-tree:', error);
111+
// 降级到 wmic
112+
return this._getProcessesViaWmic();
113+
}
71114
} else {
72115
throw new Error(l10n.t("Operating system '{0}' not supported.", osType));
73116
}
74-
} else {
75-
processCmd = specCommand;
76117
}
118+
119+
const processCmd = specCommand;
77120
const customEnvVars = await getEnvironmentVariables();
78-
if (processCmd === PowerShellProcessParser.powerShellCommand) {
79-
try {
80-
const checkPowerShell = await plainExec(
81-
'where',
82-
['powershell'],
83-
{ throwOnStdErr: false },
84-
customEnvVars,
85-
);
86-
if (checkPowerShell.stdout.length === 0) {
87-
processCmd = WmicProcessParser.wmicCommand;
88-
}
89-
} catch (error) {
90-
// If 'where' fails, fall back to wmic (most likely powershell is not available).(Windows Xp or below?
91-
console.log('PowerShell check failed, using WMIC fallback');
92-
processCmd = WmicProcessParser.wmicCommand;
93-
}
94-
}
95121
const output = await plainExec(processCmd.command, processCmd.args, { throwOnStdErr: true }, customEnvVars);
96122
logProcess(processCmd.command, processCmd.args, { throwOnStdErr: true });
97123
if (processCmd === WmicProcessParser.wmicCommand) {
98124
return WmicProcessParser.parseProcesses(output.stdout);
99-
} else if (processCmd === PowerShellProcessParser.powerShellCommand ||
100-
processCmd === PowerShellProcessParser.powerShellWithoutCimCommand) {
125+
} else if (
126+
processCmd === PowerShellProcessParser.powerShellCommand ||
127+
processCmd === PowerShellProcessParser.powerShellWithoutCimCommand
128+
) {
101129
return PowerShellProcessParser.parseProcesses(output.stdout);
102130
}
103131
return PsProcessParser.parseProcesses(output.stdout);

0 commit comments

Comments
 (0)