Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
100 lines
3.1 KiB
JavaScript
100 lines
3.1 KiB
JavaScript
const { execFile } = require("node:child_process");
|
|
|
|
const POSIX_PROCESS_LIST_TIMEOUT_MS = 3_000;
|
|
const POSIX_PROCESS_LIST_MAX_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
|
|
function createProcessTree({ platform, listPosix, listWindows } = {}) {
|
|
const sessionPidMap = new Map();
|
|
|
|
function registerPid(sessionId, pid) {
|
|
if (!sessionId || typeof pid !== "number") return;
|
|
if (sessionPidMap.has(sessionId) && sessionPidMap.get(sessionId) !== pid) {
|
|
console.warn(
|
|
`[ptyProcessTree] sessionId "${sessionId}" already registered with pid ${sessionPidMap.get(sessionId)}; overwriting with ${pid}.`,
|
|
);
|
|
}
|
|
sessionPidMap.set(sessionId, pid);
|
|
}
|
|
|
|
function unregisterPid(sessionId) {
|
|
sessionPidMap.delete(sessionId);
|
|
}
|
|
|
|
async function getChildProcesses(sessionId) {
|
|
const pid = sessionPidMap.get(sessionId);
|
|
if (!pid) return [];
|
|
if (platform === "win32") {
|
|
return listWindows ? listWindows(pid) : [];
|
|
}
|
|
return listPosix ? listPosix(pid) : [];
|
|
}
|
|
|
|
return { registerPid, unregisterPid, getChildProcesses };
|
|
}
|
|
|
|
function defaultListPosix(ppid, { execFileFn = execFile } = {}) {
|
|
return new Promise((resolve) => {
|
|
// `ps -A -o pid=,ppid=,args=` works on both BSD (macOS) and GNU (Linux).
|
|
// `args=` shows the full command line (not truncated like `comm=`).
|
|
// The trailing `=` on each column suppresses the header row.
|
|
execFileFn("ps", ["-A", "-o", "pid=,ppid=,args="], {
|
|
timeout: POSIX_PROCESS_LIST_TIMEOUT_MS,
|
|
maxBuffer: POSIX_PROCESS_LIST_MAX_BUFFER_BYTES,
|
|
windowsHide: true,
|
|
}, (err, stdout) => {
|
|
if (err || typeof stdout !== "string") return resolve([]);
|
|
const out = [];
|
|
for (const line of stdout.split("\n")) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed) continue;
|
|
const m = trimmed.match(/^(\d+)\s+(\d+)\s+(.+)$/);
|
|
if (!m) continue;
|
|
if (Number(m[2]) !== ppid) continue;
|
|
out.push({ pid: Number(m[1]), command: m[3].trim() });
|
|
}
|
|
resolve(out);
|
|
});
|
|
});
|
|
}
|
|
|
|
function defaultListWindows(ppid) {
|
|
return new Promise((resolve) => {
|
|
let wpt;
|
|
try {
|
|
wpt = require("@vscode/windows-process-tree");
|
|
} catch {
|
|
return resolve([]);
|
|
}
|
|
try {
|
|
wpt.getProcessTree(ppid, (tree) => {
|
|
if (!tree || !Array.isArray(tree.children)) return resolve([]);
|
|
resolve(tree.children.map((c) => ({ pid: c.pid, command: c.name })));
|
|
});
|
|
} catch {
|
|
resolve([]);
|
|
}
|
|
});
|
|
}
|
|
|
|
function createDefaultProcessTree() {
|
|
const platform = process.platform;
|
|
return createProcessTree({
|
|
platform,
|
|
listPosix: platform === "win32" ? undefined : defaultListPosix,
|
|
listWindows: platform === "win32" ? defaultListWindows : undefined,
|
|
});
|
|
}
|
|
|
|
const defaultTree = createDefaultProcessTree();
|
|
|
|
module.exports = {
|
|
POSIX_PROCESS_LIST_TIMEOUT_MS,
|
|
POSIX_PROCESS_LIST_MAX_BUFFER_BYTES,
|
|
createProcessTree,
|
|
defaultListPosix,
|
|
processTree: defaultTree,
|
|
registerPid: (id, pid) => defaultTree.registerPid(id, pid),
|
|
unregisterPid: (id) => defaultTree.unregisterPid(id),
|
|
getChildProcesses: (id) => defaultTree.getChildProcesses(id),
|
|
};
|