Commit 4894841

Anton Golub <antongolub@antongolub.com>
2025-09-26 13:28:08
feat: update `ps` utils to support Windows kernel >= 26000 (#1344)
* ci: add windows-2025 to test matrix * chore: update @webpod/ps to v1.0.0
1 parent bf1d703
.github/workflows/test.yml
@@ -138,7 +138,10 @@ jobs:
           npm run test:dcr
 
   smoke-win32-node16:
-    runs-on: windows-2022
+    strategy:
+      matrix:
+        os: [windows-2022, windows-2025]
+    runs-on: ${{ matrix.os }}
     needs: build
     steps:
       - uses: actions/checkout@v5
build/3rd-party-licenses
@@ -20,7 +20,7 @@ THIRD PARTY LICENSES
   sindresorhus/merge-streams
   MIT
 
-@webpod/ps@0.1.4
+@webpod/ps@1.0.0
   <unknown>
   git://github.com/webpod/ps.git
   MIT
build/index.cjs
@@ -62,7 +62,7 @@ var versions = {
   fs: "11.3.2",
   glob: "14.1.0",
   minimist: "1.2.8",
-  ps: "0.1.4",
+  ps: "1.0.0",
   which: "5.0.0",
   yaml: "2.8.1"
 };
build/vendor-core.cjs
@@ -773,7 +773,7 @@ var import_which = __toESM(require_lib(), 1);
 // node_modules/@webpod/ps/target/esm/index.mjs
 var import_node_process4 = __toESM(require("process"), 1);
 var import_node_fs = __toESM(require("fs"), 1);
-var import_node_os2 = require("os");
+var import_node_os2 = __toESM(require("os"), 1);
 
 // node_modules/@webpod/ingrid/target/esm/index.mjs
 var EOL = /\r?\n|\r|\n/;
@@ -1196,7 +1196,40 @@ var exec = (ctx) => invoke(normalizeCtx(ctx));
 
 // node_modules/@webpod/ps/target/esm/index.mjs
 var IS_WIN = import_node_process4.default.platform === "win32";
-var WMIC_INPUT = "wmic process get ProcessId,ParentProcessId,CommandLine";
+var IS_WIN2025_PLUS = IS_WIN && Number.parseInt(import_node_os2.default.release().split(".")[2], 10) >= 26e3;
+var LOOKUPS = {
+  wmic: {
+    cmd: "wmic process get ProcessId,ParentProcessId,CommandLine",
+    args: [],
+    parse(stdout) {
+      return parse(removeWmicPrefix(stdout), { format: "win" });
+    }
+  },
+  ps: {
+    cmd: "ps",
+    args: ["-lx"],
+    parse(stdout) {
+      return parse(stdout, { format: "unix" });
+    }
+  },
+  pwsh: {
+    cmd: "pwsh",
+    args: ["-NoProfile", "-Command", '"Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine | ConvertTo-Json -Compress"'],
+    parse(stdout) {
+      let arr = [];
+      try {
+        arr = JSON.parse(stdout);
+      } catch (e) {
+        return [];
+      }
+      return arr.map((p) => ({
+        ProcessId: [p.ProcessId + ""],
+        ParentProcessId: [p.ParentProcessId + ""],
+        CommandLine: p.CommandLine ? [p.CommandLine] : []
+      }));
+    }
+  }
+};
 var isBin = (f) => {
   if (f === "") return false;
   if (!f.includes("/") && !f.includes("\\")) return true;
@@ -1220,42 +1253,35 @@ var _lookup = ({
 }) => {
   const pFactory = sync ? makePseudoDeferred.bind(null, []) : makeDeferred;
   const { promise, resolve, reject } = pFactory();
-  const { psargs = ["-lx"] } = query;
-  const args = Array.isArray(psargs) ? psargs : psargs.split(/\s+/);
   const result = [];
-  const extract = IS_WIN ? removeWmicPrefix : identity;
+  const lookupFlow = IS_WIN ? IS_WIN2025_PLUS ? "pwsh" : "wmic" : "ps";
+  const {
+    parse: parse2,
+    cmd,
+    args
+  } = LOOKUPS[lookupFlow];
   const callback = (err, { stdout }) => {
     if (err) {
       reject(err);
       cb(err);
       return;
     }
-    result.push(...parseProcessList(extract(stdout), query));
+    result.push(...filterProcessList(normalizeOutput(parse2(stdout)), query));
     resolve(result);
     cb(null, result);
   };
-  const ctx = IS_WIN ? {
-    cmd: WMIC_INPUT,
-    args: [],
-    callback,
-    sync,
-    run(cb2) {
-      cb2();
-    }
-  } : {
-    cmd: "ps",
+  exec({
+    cmd,
     args,
     callback,
     sync,
     run(cb2) {
       cb2();
     }
-  };
-  exec(ctx);
+  });
   return Object.assign(promise, result);
 };
-var parseProcessList = (output, query = {}) => {
-  const processList = parseGrid(output);
+var filterProcessList = (processList, query = {}) => {
   const pidList = (query.pid === void 0 ? [] : [query.pid].flat(1)).map((v) => v + "");
   const filters = [
     (p) => query.command ? new RegExp(query.command, "i").test(p.command) : true,
@@ -1267,9 +1293,9 @@ var parseProcessList = (output, query = {}) => {
   );
 };
 var removeWmicPrefix = (stdout) => {
-  const s = stdout.indexOf(WMIC_INPUT + import_node_os2.EOL);
-  const e = stdout.includes(">") ? stdout.trimEnd().lastIndexOf(import_node_os2.EOL) : stdout.length;
-  return (s > 0 ? stdout.slice(s + WMIC_INPUT.length, e) : stdout.slice(0, e)).trimStart();
+  const s = stdout.indexOf(LOOKUPS.wmic.cmd + import_node_os2.default.EOL);
+  const e = stdout.includes(">") ? stdout.trimEnd().lastIndexOf(import_node_os2.default.EOL) : stdout.length;
+  return (s > 0 ? stdout.slice(s + LOOKUPS.wmic.cmd.length, e) : stdout.slice(0, e)).trimStart();
 };
 var pickTree = (list, pid, recursive = false) => {
   const children = list.filter((p) => p.ppid === pid + "");
@@ -1363,11 +1389,10 @@ var kill = (pid, opts, next) => {
   }
   return promise;
 };
-var parseGrid = (output) => output ? formatOutput(parse(output, { format: IS_WIN ? "win" : "unix" })) : [];
-var formatOutput = (data) => data.reduce((m, d) => {
-  var _a, _b, _c, _d;
-  const pid = ((_a = d.PID) == null ? void 0 : _a[0]) || ((_b = d.ProcessId) == null ? void 0 : _b[0]);
-  const ppid = ((_c = d.PPID) == null ? void 0 : _c[0]) || ((_d = d.ParentProcessId) == null ? void 0 : _d[0]);
+var normalizeOutput = (data) => data.reduce((m, d) => {
+  var _a, _b;
+  const pid = (_a = d.PID || d.ProcessId) == null ? void 0 : _a[0];
+  const ppid = (_b = d.PPID || d.ParentProcessId) == null ? void 0 : _b[0];
   const _cmd = d.CMD || d.CommandLine || d.COMMAND || [];
   const cmd = _cmd.length === 1 ? _cmd[0].split(/\s+/) : _cmd;
   if (pid && cmd.length > 0) {
build/vendor-core.d.ts
@@ -224,7 +224,6 @@ type TPsLookupQuery = {
 	command?: string;
 	arguments?: string;
 	ppid?: number | string;
-	psargs?: string | string[];
 };
 type TPsKillOptions = {
 	timeout?: number;
src/versions.ts
@@ -21,7 +21,7 @@ export const versions: Record<string, string> = {
   fs: '11.3.2',
   glob: '14.1.0',
   minimist: '1.2.8',
-  ps: '0.1.4',
+  ps: '1.0.0',
   which: '5.0.0',
   yaml: '2.8.1',
 }
.size-limit.json
@@ -19,7 +19,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "128.30 kB",
+    "limit": "128.85 kB",
     "brotli": false,
     "gzip": false
   },
@@ -33,7 +33,7 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "816.10 kB",
+    "limit": "816.65 kB",
     "brotli": false,
     "gzip": false
   },
@@ -47,7 +47,7 @@
   {
     "name": "vendor",
     "path": "build/vendor-*.{cjs,d.ts}",
-    "limit": "767.20 kB",
+    "limit": "767.75 kB",
     "brotli": false,
     "gzip": false
   },
@@ -66,7 +66,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "873.65 kB",
+    "limit": "874.15 kB",
     "brotli": false,
     "gzip": false
   }
package-lock.json
@@ -20,7 +20,7 @@
         "@types/node": "24.5.2",
         "@types/which": "3.0.4",
         "@webpod/ingrid": "1.1.1",
-        "@webpod/ps": "0.1.4",
+        "@webpod/ps": "1.0.0",
         "c8": "10.1.3",
         "chalk": "5.6.2",
         "create-require": "1.1.1",
@@ -2475,14 +2475,14 @@
       "license": "MIT"
     },
     "node_modules/@webpod/ps": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@webpod/ps/-/ps-0.1.4.tgz",
-      "integrity": "sha512-Mq62ZvqAD2uF+b+MjGua7K1lkARk6vzYJTfZDe6h8lYbIXYticPpP+FWA3SPzjKlQQl7EJRdcoB4Xst3IOKz4g==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@webpod/ps/-/ps-1.0.0.tgz",
+      "integrity": "sha512-jF9WpjVPsCUO4GnoCo5ngbV7szcYwZ+SzgcHtIXOJokx9SBJt8ADXtsgpnnB/UjBZTXUNPb8aXnCcJrv2TxGWQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
         "@webpod/ingrid": "^1.1.1",
-        "zurk": "^0.11.4"
+        "zurk": "^0.11.5"
       }
     },
     "node_modules/acorn": {
package.json
@@ -117,7 +117,7 @@
     "@types/node": "24.5.2",
     "@types/which": "3.0.4",
     "@webpod/ingrid": "1.1.1",
-    "@webpod/ps": "0.1.4",
+    "@webpod/ps": "1.0.0",
     "c8": "10.1.3",
     "chalk": "5.6.2",
     "create-require": "1.1.1",