first commit

This commit is contained in:
Artem Anufrij
2026-10-07 18:56:27 +02:00
commit 2a8a60b725
7768 changed files with 1550851 additions and 0 deletions
Generated Vendored Executable
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env node
import os from 'node:os';
import pidtree from '../index.js';
function help() {
console.log(
' Usage\n' +
' $ pidtree <ppid>\n' +
'\n' +
'Options\n' +
' --list To print the pids as a list.\n' +
'\n' +
'Examples\n' +
' $ pidtree\n' +
' $ pidtree --list\n' +
' $ pidtree 1\n' +
' $ pidtree 1 --list\n',
);
}
function list(ppid) {
pidtree(ppid === undefined ? -1 : ppid, (error, list) => {
if (error) {
console.error(error.message);
return;
}
console.log(list.join(os.EOL));
});
}
function tree(ppid) {
pidtree(ppid, {advanced: true}, (error, list) => {
if (error) {
console.error(error.message);
return;
}
const parents = {}; // Hash Map of parents
const tree = {}; // Adjacency Hash Map
while (list.length > 0) {
const element = list.pop();
if (tree[element.ppid]) {
tree[element.ppid].push(element.pid);
} else {
tree[element.ppid] = [element.pid];
}
if (ppid === -1) {
parents[element.pid] = element.ppid;
}
}
let roots = [ppid];
if (ppid === -1) {
// Get all the roots.
roots = Object.keys(tree).filter((node) => parents[node] === undefined);
}
for (const root of roots) {
print(tree, root);
}
});
function print(tree, start) {
function printBranch(node, branch) {
const isGraphHead = branch.length === 0;
const children = tree[node] || [];
let branchHead = '';
if (!isGraphHead) {
branchHead = children.length > 0 ? '┬ ' : '─ ';
}
console.log(branch + branchHead + node);
let baseBranch = branch;
if (!isGraphHead) {
const isChildOfLastBranch = branch.slice(-2) === '└─';
baseBranch = branch.slice(0, -2) + (isChildOfLastBranch ? ' ' : '| ');
}
const nextBranch = baseBranch + '├─';
const lastBranch = baseBranch + '└─';
for (const [index, child] of children.entries()) {
printBranch(
child,
children.length - 1 === index ? lastBranch : nextBranch,
);
}
}
printBranch(start, '');
}
}
function run() {
let flag;
let ppid;
for (let i = 2; i < process.argv.length; i++) {
if (process.argv[i].startsWith('--')) {
flag = process.argv[i];
} else {
ppid = process.argv[i];
}
}
if (ppid === undefined) {
ppid = -1;
}
if (flag === '--list') {
list(ppid);
} else if (flag === undefined) {
tree(ppid);
} else {
help();
}
}
run();
+79
View File
@@ -0,0 +1,79 @@
export type Options = {
/**
* Include the provided PID in the list. Ignored if -1 is passed as PID.
* @default false
*/
root?: boolean;
};
export type AdvancedResult = {
/**
* PID of the parent.
*/
ppid: number;
/**
* PID.
*/
pid: number;
};
export type Result = number;
/**
* Get the list of children pids of the given pid.
* @param pid A PID. If -1 will return all the pids.
* @param callback Called when the list is ready.
*/
declare function pidtree(
pid: string | number,
callback: (error: Error | undefined, result: Result[]) => void,
): void;
/**
* Get the list of children pids of the given pid.
* @param pid A PID. If -1 will return all the pids.
* @param options Options object.
* @param callback Called when the list is ready.
*/
declare function pidtree(
pid: string | number,
options: Options,
callback: (error: Error | undefined, result: Result[]) => void,
): void;
/**
* Get the list of children pids of the given pid.
* @param pid A PID. If -1 will return all the pids.
* @param options Options object.
* @param callback Called when the list is ready.
*/
declare function pidtree(
pid: string | number,
options: Options & {advanced: true},
callback: (error: Error | undefined, result: AdvancedResult[]) => void,
): void;
/**
* Get the list of children pids of the given pid.
* @param pid A PID. If -1 will return all the pids.
* @param options Optional options object.
* @returns A promise containing the list.
*/
declare function pidtree(
pid: string | number,
options?: Options,
): Promise<Result[]>;
/**
* Get the list of children pids of the given pid.
* @param pid A PID. If -1 will return all the pids.
* @param options Options object.
* @returns A promise containing the list.
*/
declare function pidtree(
pid: string | number,
options: Options & {advanced: true},
): Promise<AdvancedResult[]>;
export default pidtree;
export {pidtree};
+33
View File
@@ -0,0 +1,33 @@
import {promisify} from 'node:util';
import {pidtreeCallback} from './lib/pidtree.js';
const pidtreeAsync = promisify(pidtreeCallback);
/**
* Get the list of children pids of the given pid.
* @public
* @param {number|string} pid A PID. If -1 will return all the pids.
* @param {object} [options] Optional options object.
* @param {boolean} [options.root=false] Include the provided PID in the list.
* @param {boolean} [options.advanced=false] Returns a list of objects in the
* format {ppid: X, pid: Y}.
* @param {Function} [callback] Called when the list is ready. If not provided a
* promise is returned instead.
* @returns {Promise<object[]>|void} Only when the callback is not provided.
*/
function pidtree(pid, options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
if (typeof callback === 'function') {
pidtreeCallback(pid, options, callback);
return;
}
return pidtreeAsync(pid, options);
}
export default pidtree;
export {pidtree};
+65
View File
@@ -0,0 +1,65 @@
import {spawn} from 'node:child_process';
/**
* Strips known-benign noise from a command's stderr.
* @param {string} stderr
* @returns {string|undefined}
*/
export function stripStderr(stderr) {
if (!stderr) return;
stderr = stderr.trim();
// Strip bogus screen size error.
// See https://github.com/microsoft/vscode/issues/98590
const regex = /your \d+x\d+ screen size is bogus\. expect trouble/gi;
stderr = stderr.replaceAll(regex, '');
return stderr.trim();
}
/**
* Spawn a binary and read its stdout.
* @param {string} cmd The name of the binary to spawn.
* @param {string[]} args The arguments for the binary.
* @param {object} [options] Optional options for the spawn function.
* @param {Function} done done(err, stdout, code)
*/
export function run(cmd, args, options, done) {
if (typeof options === 'function') {
done = options;
options = undefined;
}
let executed = false;
const child = spawn(cmd, args, options);
let stdout = '';
let stderr = '';
child.stdout.on('data', (data) => {
stdout += data.toString();
});
child.stderr.on('data', (data) => {
stderr += data.toString();
});
child.on('error', (error) => {
if (executed) return;
executed = true;
// Pass the original error through so callers can inspect err.code
// (e.g. 'ENOENT' when the binary is missing) to decide on a fallback.
done(error);
});
child.on('close', (code) => {
if (executed) return;
executed = true;
stderr = stripStderr(stderr);
if (stderr) {
done(new Error(stderr));
return;
}
done(null, stdout, code);
});
}
+64
View File
@@ -0,0 +1,64 @@
import os from 'node:os';
import {ps} from './ps.js';
import {wmic} from './wmic.js';
import {powershell} from './powershell.js';
const platformToMethod = {
darwin: 'ps',
sunos: 'ps',
freebsd: 'ps',
netbsd: 'ps',
win: 'win',
linux: 'ps',
aix: 'ps',
};
let platform = os.platform();
if (platform.startsWith('win')) {
platform = 'win';
}
const method = platformToMethod[platform];
/**
* Lists the system pids on Windows. wmic has been removed from recent versions
* (Windows 11 24H2, Windows Server 2025), so it is tried first (it is faster
* when present) and PowerShell is used as a fallback when it is missing.
* Exported for testing.
* @param {Function} callback callback(err, list)
* @param {Function} [wmicFn] Injectable wmic backend, used for testing.
* @param {Function} [powershellFn] Injectable PowerShell backend, for testing.
*/
export function getWindows(callback, wmicFn = wmic, powershellFn = powershell) {
wmicFn((error, list) => {
if (error && error.code === 'ENOENT') {
powershellFn(callback);
return;
}
callback(error, list);
});
}
/**
* Gets the list of all the pids of the system.
* @param {Function} callback Called when the list is ready.
*/
export function get(callback) {
if (method === undefined) {
callback(
new Error(
os.platform() +
' is not supported yet, please open an issue (https://github.com/simonepri/pidtree)',
),
);
return;
}
if (method === 'win') {
getWindows(callback);
return;
}
ps(callback);
}
+24
View File
@@ -0,0 +1,24 @@
/**
* Parses the `<ppid> <pid>` output produced by the ps/wmic/powershell backends
* into a list of `[ppid, pid]` pairs. The header row and any non-numeric lines
* are skipped, and all common line endings (\n, \r\n, \r\r\n) are handled.
* @param {string} stdout The raw command output.
* @returns {Array<[number, number]>}
*/
export function parse(stdout) {
const list = [];
for (const rawLine of stdout.split(/\r*\n/)) {
const line = rawLine.trim();
if (!line) continue;
const [rawPpid, rawPid] = line.split(/\s+/);
const ppid = Number.parseInt(rawPpid, 10);
const pid = Number.parseInt(rawPid, 10);
// Skips the header row and any stray output.
if (Number.isNaN(ppid) || Number.isNaN(pid)) continue;
list.push([ppid, pid]);
}
return list;
}
+94
View File
@@ -0,0 +1,94 @@
import {get} from './get.js';
/**
* Get the list of children and grandchildren pids of the given PID.
* @param {number|string} pid A PID. If -1 will return all the pids.
* @param {object} [options] Optional options object.
* @param {boolean} [options.root=false] Include the provided PID in the list.
* @param {boolean} [options.advanced=false] Returns a list of objects in the
* format {ppid: X, pid: Y}.
* @param {Function} callback callback(err, list) Called when the list is ready.
*/
export function pidtreeCallback(pid, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (typeof options !== 'object' || options === null) {
options = {};
}
pid = Number.parseInt(pid, 10);
if (Number.isNaN(pid) || pid < -1) {
callback(new TypeError('The pid provided is invalid'));
return;
}
get((error, list) => {
if (error) {
callback(error);
return;
}
// If the user wants the whole list just return it.
if (pid === -1) {
const all = list.map((entry) =>
options.advanced ? {ppid: entry[0], pid: entry[1]} : entry[1],
);
callback(null, all);
return;
}
let root;
for (const entry of list) {
if (entry[1] === pid) {
root = options.advanced ? {ppid: entry[0], pid} : pid;
break;
}
if (entry[0] === pid) {
// Special pids like 0 on *nix.
root = options.advanced ? {pid} : pid;
}
}
if (root === undefined) {
callback(new Error('No matching pid found'));
return;
}
// Build the adjacency Hash Map (pid -> [children of pid]).
const tree = {};
for (const [parentPid, childPid] of list) {
if (tree[parentPid]) {
tree[parentPid].push(childPid);
} else {
tree[parentPid] = [childPid];
}
}
// Starting from the PID provided by the user, traverse the tree using the
// adjacency Hash Map until the whole subtree is visited. Each pid
// encountered while visiting is added to the pids array.
const pids = [root];
let index = 0;
while (index < pids.length) {
const current = options.advanced ? pids[index].pid : pids[index];
index++;
const children = tree[current];
if (!children) continue;
for (const childPid of children) {
pids.push(options.advanced ? {ppid: current, pid: childPid} : childPid);
}
delete tree[current];
}
if (!options.root) {
pids.shift(); // Remove root.
}
callback(null, pids);
});
}
+51
View File
@@ -0,0 +1,51 @@
import {run as defaultRun} from './bin.js';
import {parse} from './parse.js';
// PowerShell command used to list every process as "<ppid> <pid>" lines.
// Get-CimInstance is the supported replacement for the removed wmic utility
// (see https://github.com/simonepri/pidtree/issues/20). $ProgressPreference is
// silenced so PowerShell does not serialize its progress stream to stderr.
const COMMAND =
"$ProgressPreference = 'SilentlyContinue'; " +
'Get-CimInstance -ClassName Win32_Process | ' +
'ForEach-Object { "$($_.ParentProcessId) $($_.ProcessId)" }';
// The command is passed through -EncodedCommand (Base64 of the UTF-16LE
// string) to avoid any cross-shell argument quoting issues on Windows.
const ENCODED = Buffer.from(COMMAND, 'utf16le').toString('base64');
/**
* Gets the list of all the pids of the system through PowerShell.
* Used as a fallback on Windows installations where wmic is not available
* (e.g. Windows 11 24H2 and Windows Server 2025).
* @param {Function} callback callback(err, list)
* @param {Function} [run] Injectable spawner, used for testing.
*/
export function powershell(callback, run = defaultRun) {
const args = ['-NoProfile', '-NonInteractive', '-EncodedCommand', ENCODED];
const options = {windowsHide: true};
// Example of stdout
//
// 0 777
// 777 778
run('powershell', args, options, (error, stdout, code) => {
if (error) {
callback(error);
return;
}
if (code !== 0) {
callback(
new Error('pidtree powershell command exited with code ' + code),
);
return;
}
try {
callback(null, parse(stdout));
} catch (error) {
callback(error);
}
});
}
+32
View File
@@ -0,0 +1,32 @@
import {run as defaultRun} from './bin.js';
import {parse} from './parse.js';
/**
* Gets the list of all the pids of the system through the ps command.
* @param {Function} callback callback(err, list)
* @param {Function} [run] Injectable spawner, used for testing.
*/
export function ps(callback, run = defaultRun) {
// Example of stdout
//
// PPID PID
// 1 430
// 430 432
run('ps', ['-A', '-o', 'ppid,pid'], (error, stdout, code) => {
if (error) {
callback(error);
return;
}
if (code !== 0) {
callback(new Error('pidtree ps command exited with code ' + code));
return;
}
try {
callback(null, parse(stdout));
} catch (error) {
callback(error);
}
});
}
+34
View File
@@ -0,0 +1,34 @@
import {run as defaultRun} from './bin.js';
import {parse} from './parse.js';
/**
* Gets the list of all the pids of the system through the wmic command.
* @param {Function} callback callback(err, list)
* @param {Function} [run] Injectable spawner, used for testing.
*/
export function wmic(callback, run = defaultRun) {
const args = ['PROCESS', 'get', 'ParentProcessId,ProcessId'];
const options = {windowsHide: true, windowsVerbatimArguments: true};
// Example of stdout
//
// ParentProcessId ProcessId
// 0 777
run('wmic', args, options, (error, stdout, code) => {
if (error) {
callback(error);
return;
}
if (code !== 0) {
callback(new Error('pidtree wmic command exited with code ' + code));
return;
}
try {
callback(null, parse(stdout));
} catch (error) {
callback(error);
}
});
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Simone Primarosa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+82
View File
@@ -0,0 +1,82 @@
{
"name": "pidtree",
"version": "1.0.0",
"description": "Cross platform children list of a PID",
"license": "MIT",
"homepage": "http://github.com/simonepri/pidtree#readme",
"repository": "github:simonepri/pidtree",
"bugs": {
"url": "https://github.com/simonepri/pidtree/issues",
"email": "simonepri@outlook.com"
},
"author": "Simone Primarosa <simonepri@outlook.com> (https://github.com/simonepri)",
"contributors": [
"Simone Primarosa <simonepri@outlook.com> (https://github.com/simonepri)"
],
"keywords": [
"ps-tree",
"ps",
"tree",
"ppid",
"pid",
"pidtree",
"pgrep",
"list",
"all",
"system",
"process",
"processes"
],
"type": "module",
"exports": {
".": {
"types": "./index.d.ts",
"default": "./index.js"
}
},
"main": "index.js",
"types": "index.d.ts",
"bin": {
"pidtree": "./bin/pidtree.js"
},
"files": [
"bin",
"lib",
"index.js",
"index.d.ts"
],
"engines": {
"node": ">=18"
},
"scripts": {
"start": "node ./bin/pidtree.js",
"lint": "xo",
"test": "c8 ava -m \"!*benchmark*\"",
"types": "tsd",
"bench": "ava -m \"*benchmark*\""
},
"devDependencies": {
"ava": "^6.4.1",
"c8": "^10.1.3",
"time-span": "^5.1.0",
"tree-kill": "^1.2.2",
"tsd": "^0.33.0",
"xo": "^2.0.2"
},
"c8": {
"reporter": [
"lcov",
"text"
]
},
"xo": {
"prettier": true,
"space": true,
"rules": {
"n/prefer-global/process": "off",
"n/prefer-global/buffer": "off",
"require-unicode-regexp": "off",
"unicorn/prefer-top-level-await": "off"
}
}
}
+203
View File
@@ -0,0 +1,203 @@
<h1 align="center">
<b>pidtree</b>
</h1>
<p align="center">
<!-- Version - npm -->
<a href="https://www.npmjs.com/package/pidtree">
<img src="https://img.shields.io/npm/v/pidtree.svg" alt="Latest version on npm" />
</a>
<!-- Downloads - npm -->
<a href="https://npm-stat.com/charts.html?package=pidtree">
<img src="https://img.shields.io/npm/dt/pidtree.svg" alt="Downloads on npm" />
</a>
<!-- License - MIT -->
<a href="https://github.com/simonepri/pidtree/tree/master/license">
<img src="https://img.shields.io/github/license/simonepri/pidtree.svg" alt="Project license" />
</a>
<br/>
<!-- Lint -->
<a href="https://github.com/simonepri/pidtree/actions?query=workflow:lint+branch:master">
<img src="https://github.com/simonepri/pidtree/workflows/lint/badge.svg?branch=master" alt="Lint status" />
</a>
<!-- Test - macOS -->
<a href="https://github.com/simonepri/pidtree/actions?query=workflow:test-macos+branch:master">
<img src="https://github.com/simonepri/pidtree/workflows/test-macos/badge.svg?branch=master" alt="Test macOS status" />
</a>
<!-- Test - Ubuntu -->
<a href="https://github.com/simonepri/pidtree/actions?query=workflow:test-ubuntu+branch:master">
<img src="https://github.com/simonepri/pidtree/workflows/test-ubuntu/badge.svg?branch=master" alt="Test Ubuntu status" />
</a>
<!-- Test - Windows -->
<a href="https://github.com/simonepri/pidtree/actions?query=workflow:test-windows+branch:master">
<img src="https://github.com/simonepri/pidtree/workflows/test-windows/badge.svg?branch=master" alt="Test Windows status" />
</a>
<!-- Coverage - Codecov -->
<a href="https://codecov.io/gh/simonepri/pidtree">
<img src="https://img.shields.io/codecov/c/github/simonepri/pidtree/master.svg" alt="Codecov Coverage report" />
</a>
<!-- DM - Snyk -->
<a href="https://snyk.io/test/github/simonepri/pidtree?targetFile=package.json">
<img src="https://snyk.io/test/github/simonepri/pidtree/badge.svg?targetFile=package.json" alt="Known Vulnerabilities" />
</a>
<br/>
<!-- Code Style - XO-Prettier -->
<a href="https://github.com/xojs/xo">
<img src="https://img.shields.io/badge/code_style-XO+Prettier-5ed9c7.svg" alt="XO Code Style used" />
</a>
<!-- Test Runner - AVA -->
<a href="https://github.com/avajs/ava">
<img src="https://img.shields.io/badge/test_runner-AVA-fb3170.svg" alt="AVA Test Runner used" />
</a>
<!-- Test Coverage - c8 -->
<a href="https://github.com/bcoe/c8">
<img src="https://img.shields.io/badge/test_coverage-c8-fec606.svg" alt="c8 Test Coverage used" />
</a>
<!-- Init - ni -->
<a href="https://github.com/simonepri/ni">
<img src="https://img.shields.io/badge/initialized_with-ni-e74c3c.svg" alt="NI Scaffolding System used" />
</a>
<!-- Release - release-please -->
<a href="https://github.com/googleapis/release-please">
<img src="https://img.shields.io/badge/released_with-release--please-6c8784.svg" alt="release-please Release System used" />
</a>
</p>
<p align="center">
🚸 Cross platform children list of a PID.
<br/>
<sub>
Coded with ❤️ by <a href="#authors">Simone Primarosa</a>.
</sub>
</p>
## Synopsis
This package is really similar to [ps-tree][gh:ps-tree] but is faster, safer and
provides sub-children results.
Furthermore ps-tree is [unmaintained][gh:ps-tree-um].
Uuh, and a fancy [CLI](#cli) is also available!
## Install
```bash
npm install pidtree
```
> **Requirements:** pidtree is an [ESM-only][gh:esm] package and requires
> **Node.js >= 18**. If you need CommonJS (`require`) or support for older
> Node.js versions, stay on [`pidtree@0.6`](https://www.npmjs.com/package/pidtree/v/0.6.1).
## Usage
```js
import pidtree from 'pidtree'
// The named import works too: import {pidtree} from 'pidtree'
// Get children of the current process (a promise is returned)
const pids = await pidtree(process.pid)
console.log(pids)
// => []
// Include the given pid in the result array
console.log(await pidtree(process.pid, {root: true}))
// => [727]
// Get all the processes of the System (-1 is a special value of this package)
console.log(await pidtree(-1))
// => [530, 42, ..., 41241]
// Include the PPID in the results
console.log(await pidtree(1, {advanced: true}))
// => [{ppid: 1, pid: 530}, {ppid: 1, pid: 42}, ..., {ppid: 1, pid: 41241}]
// A Node-style callback is also supported instead of a promise
pidtree(1, function (err, pids) {
console.log(pids)
// => [141, 42, ..., 15242]
})
```
## Compatibility
| Linux | FreeBSD | NetBSD | SunOS | macOS | Win | AIX |
| --- | --- | --- | --- | --- | --- | --- |
| ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ |
✅ = Working
❓ = Not tested but should work
Please if your platform is not supported [file an issue][new issue].
## CLI
<img src="https://github.com/simonepri/pidtree/raw/master/media/cli.gif" alt="pidtree cli" width="300" align="right"/>
Show a tree of the processes inside your system inside your terminal.
```bash
npx pidtree $PPID
```
Just replace `$PPID` with one of the pids inside your system.
Or don't pass anything if you want all the pids inside your system.
```bash
npx pidtree
```
To display the output as a list, similar to the one produced from `pgrep -P $PID`,
pass the `--list` flag.
```bash
npx pidtree --list
```
## API
<a name="pidtree"></a>
## pidtree(pid, [options], [callback]) ⇒ <code>[Promise.&lt;Array.&lt;Object&gt;&gt;]</code>
Get the list of children pids of the given pid.
**Kind**: global function
**Returns**: <code>Promise.&lt;Array.&lt;Object&gt;&gt;</code> - Only when the callback is not provided.
**Access**: public
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| pid | <code>Number</code> \| <code>String</code> | | A pid. If -1 will return all the pids. |
| [options] | <code>Object</code> | | Optional options object. |
| [options.root] | <code>Boolean</code> | <code>false</code> | Include the provided pid in the list. Ignored if -1 is passed as pid. |
| [callback] | <code>function</code> | | Called when the list is ready. If not provided a promise is returned instead. |
## Related
- [pidusage][gh:pidusage] -
Cross-platform process cpu % and memory usage of a PID
## Authors
- **Simone Primarosa** - [simonepri][github:simonepri]
See also the list of [contributors][contributors] who participated in this project.
## License
This project is licensed under the MIT License - see the [license][license] file for details.
<!-- Links -->
[new issue]: https://github.com/simonepri/pidtree/issues/new
[license]: https://github.com/simonepri/pidtree/tree/master/license
[contributors]: https://github.com/simonepri/pidtree/contributors
[github:simonepri]: https://github.com/simonepri
[gh:esm]: https://nodejs.org/api/esm.html
[gh:pidusage]: https://github.com/soyuka/pidusage
[gh:ps-tree]: https://github.com/indexzero/ps-tree
[gh:ps-tree-um]: https://github.com/indexzero/ps-tree/issues/30