Commit e3f043a

Anton Golub <antongolub@antongolub.com>
2025-07-21 17:01:23
refactor: simplify `ProcessPromise._snapshot` inners (#1281)
* chore: bump version to v8.7.2 * refactor: separate snapshot builder * refactor: simplify `ProcessPromise.timeout()` inners * chore: internal types imprs * refactor: make public `ProcessPromise.sync` getter
1 parent 3ca9cd8
build/cli.cjs
@@ -294,7 +294,7 @@ function readScript() {
 }
 function readScriptFromStdin() {
   return __async(this, null, function* () {
-    return !import_node_process2.default.stdin.isTTY ? (0, import_index.stdin)() : "";
+    return import_node_process2.default.stdin.isTTY ? "" : (0, import_index.stdin)();
   });
 }
 function readScriptFromHttp(remote) {
build/cli.d.ts
@@ -1,10 +1,9 @@
 #!/usr/bin/env node
-import { transformMarkdown } from './md.js';
 import { type minimist } from './vendor.js';
+export { transformMarkdown } from './md.js';
 export declare const argv: minimist.ParsedArgs;
 export declare function printUsage(): void;
 export declare function main(): Promise<void>;
-export { transformMarkdown };
 export declare function injectGlobalRequire(origin: string): void;
 export declare function isMain(metaurl?: string, scriptpath?: string): boolean;
 export declare function normalizeExt(ext?: string): string | undefined;
build/core.cjs
@@ -1,6 +1,7 @@
 "use strict";
 const {
   __spreadValues,
+  __spreadProps,
   __export,
   __toESM,
   __toCommonJS,
@@ -432,8 +433,14 @@ var defaults = resolveDefaults({
   killSignal: SIGTERM,
   timeoutSignal: SIGTERM
 });
-var boundCtxs = [];
+var snapshots = [];
 var delimiters = [];
+var getSnapshot = (snapshot, from, cmd) => __spreadProps(__spreadValues({}, snapshot), {
+  ac: snapshot.ac || new AbortController(),
+  ee: new import_node_events.EventEmitter(),
+  from,
+  cmd
+});
 var $ = new Proxy(
   function(pieces, ...args) {
     const snapshot = getStore();
@@ -445,7 +452,7 @@ var $ = new Proxy(
       };
     }
     const from = getCallerLocation();
-    if (pieces.some((p) => p == void 0))
+    if (pieces.some((p) => p == null))
       throw new Error(`Malformed command at ${from}`);
     checkShell();
     checkQuote();
@@ -454,10 +461,10 @@ var $ = new Proxy(
       pieces,
       args
     );
-    boundCtxs.push([cmd, from, snapshot]);
-    const process3 = new ProcessPromise(import_util.noop);
-    if (!process3.isHalted()) process3.run();
-    return process3.output || process3;
+    snapshots.push(getSnapshot(snapshot, from, cmd));
+    const pp = new ProcessPromise(import_util.noop);
+    if (!pp.isHalted()) pp.run();
+    return pp.sync ? pp.output : pp;
   },
   {
     set(_, key, value) {
@@ -483,12 +490,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
     });
     this._stage = "initial";
     this._id = (0, import_util.randomId)();
-    this._cmd = "";
-    this._from = "";
-    this._snapshot = getStore();
     this._piped = false;
-    this._ee = new import_node_events.EventEmitter();
-    this._ac = new AbortController();
     this._stdin = new import_vendor_core2.VoidStream();
     this._zurk = null;
     this._output = null;
@@ -496,55 +498,50 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
     this._resolve = import_util.noop;
     // Stream-like API
     this.writable = true;
-    if (boundCtxs.length) {
-      const [cmd, from, snapshot] = boundCtxs.pop();
-      this._cmd = cmd;
-      this._from = from;
-      this._snapshot = __spreadValues({}, snapshot);
+    if (snapshots.length) {
+      this._snapshot = snapshots.pop();
       this._resolve = resolve;
       this._reject = (v) => {
         reject(v);
-        if (this.isSync()) throw v;
+        if (this.sync) throw v;
       };
-      if (snapshot.halt) this._stage = "halted";
+      if (this._snapshot.halt) this._stage = "halted";
     } else _ProcessPromise.disarm(this);
   }
   run() {
-    var _a, _b, _c, _d, _e, _f, _g;
+    var _a, _b, _c, _d;
     if (this.isRunning() || this.isSettled()) return this;
     this._stage = "running";
     (_a = this._pipedFrom) == null ? void 0 : _a.run();
     const self = this;
     const $2 = self._snapshot;
     const id = self.id;
-    const timeout = (_b = self._timeout) != null ? _b : $2.timeout;
-    const timeoutSignal = (_c = self._timeoutSignal) != null ? _c : $2.timeoutSignal;
     if ($2.preferLocal) {
       const dirs = $2.preferLocal === true ? [$2.cwd, $2[CWD]] : [$2.preferLocal].flat();
       $2.env = (0, import_util.preferLocalBin)($2.env, ...dirs);
     }
     this._zurk = (0, import_vendor_core2.exec)({
-      id,
-      sync: self.isSync(),
       cmd: self.fullCmd,
-      cwd: (_d = $2.cwd) != null ? _d : $2[CWD],
-      input: (_f = (_e = $2.input) == null ? void 0 : _e.stdout) != null ? _f : $2.input,
+      cwd: (_b = $2.cwd) != null ? _b : $2[CWD],
+      input: (_d = (_c = $2.input) == null ? void 0 : _c.stdout) != null ? _d : $2.input,
+      stdin: self._stdin,
+      sync: self.sync,
       signal: self.signal,
       shell: (0, import_util.isString)($2.shell) ? $2.shell : true,
+      id,
       env: $2.env,
       spawn: $2.spawn,
       spawnSync: $2.spawnSync,
       store: $2.store,
-      stdin: self._stdin,
-      stdio: (_g = self._stdio) != null ? _g : $2.stdio,
+      stdio: $2.stdio,
       detached: $2.detached,
-      ee: self._ee,
+      ee: $2.ee,
       run(cb, ctx) {
         var _a2, _b2;
         ((_b2 = (_a2 = self.cmd).then) == null ? void 0 : _b2.call(
           _a2,
-          (_cmd) => {
-            self._cmd = _cmd;
+          (cmd) => {
+            $2.cmd = cmd;
             ctx.cmd = self.fullCmd;
             cb();
           },
@@ -554,7 +551,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
       on: {
         start: () => {
           $2.log({ kind: "cmd", cmd: self.cmd, verbose: self.isVerbose(), id });
-          self.timeout(timeout, timeoutSignal);
+          self.timeout($2.timeout, $2.timeoutSignal);
         },
         stdout: (data) => {
           if (self._piped) return;
@@ -572,7 +569,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
             error,
             duration,
             store,
-            from: self._from
+            from: $2.from
           });
           $2.log({ kind: "end", signal, exitCode: status, duration, error, verbose: self.isVerbose(), id });
           if (stdout.length && (0, import_util.getLast)((0, import_util.getLast)(stdout)) !== BR_CC) c.on.stdout(EOL, c);
@@ -598,7 +595,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
         })(dest, ...args)
       );
     this._piped = true;
-    const ee = this._ee;
+    const { ee } = this._snapshot;
     const from = new import_vendor_core2.VoidStream();
     const fill = () => {
       for (const chunk of this._zurk.store[source]) from.write(chunk);
@@ -661,10 +658,11 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
     return (_a = this.child) == null ? void 0 : _a.pid;
   }
   get cmd() {
-    return this._cmd;
+    return this._snapshot.cmd;
   }
   get fullCmd() {
-    return (this._snapshot.prefix || "") + this.cmd + (this._snapshot.postfix || "");
+    const { prefix = "", postfix = "", cmd } = this._snapshot;
+    return prefix + cmd + postfix;
   }
   get child() {
     var _a;
@@ -692,7 +690,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
     return this._snapshot.signal || this.ac.signal;
   }
   get ac() {
-    return this._snapshot.ac || this._ac;
+    return this._snapshot.ac;
   }
   get output() {
     return this._output;
@@ -700,6 +698,9 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
   get stage() {
     return this._stage;
   }
+  get sync() {
+    return this._snapshot[SYNC];
+  }
   get [Symbol.toStringTag]() {
     return "ProcessPromise";
   }
@@ -708,31 +709,29 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
   }
   // Configurators
   stdio(stdin, stdout = "pipe", stderr = "pipe") {
-    this._stdio = [stdin, stdout, stderr];
+    this._snapshot.stdio = [stdin, stdout, stderr];
     return this;
   }
   nothrow(v = true) {
-    this._nothrow = v;
+    this._snapshot.nothrow = v;
     return this;
   }
   quiet(v = true) {
-    this._quiet = v;
+    this._snapshot.quiet = v;
     return this;
   }
   verbose(v = true) {
-    this._verbose = v;
+    this._snapshot.verbose = v;
     return this;
   }
-  timeout(d = 0, signal = this._timeoutSignal || $.timeoutSignal) {
+  timeout(d = 0, signal = $.timeoutSignal) {
     if (this.isSettled()) return this;
-    this._timeout = (0, import_util.parseDuration)(d);
-    this._timeoutSignal = signal;
+    const $2 = this._snapshot;
+    $2.timeout = (0, import_util.parseDuration)(d);
+    $2.timeoutSignal = signal;
     if (this._timeoutId) clearTimeout(this._timeoutId);
-    if (this._timeout && this.isRunning()) {
-      this._timeoutId = setTimeout(
-        () => this.kill(this._timeoutSignal),
-        this._timeout
-      );
+    if ($2.timeout && this.isRunning()) {
+      this._timeoutId = setTimeout(() => this.kill($2.timeoutSignal), $2.timeout);
       this.finally(() => clearTimeout(this._timeoutId)).catch(import_util.noop);
     }
     return this;
@@ -755,22 +754,16 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
   }
   // Status checkers
   isQuiet() {
-    var _a;
-    return (_a = this._quiet) != null ? _a : this._snapshot.quiet;
+    return this._snapshot.quiet;
   }
   isVerbose() {
-    var _a;
-    return ((_a = this._verbose) != null ? _a : this._snapshot.verbose) && !this.isQuiet();
+    return this._snapshot.verbose && !this.isQuiet();
   }
   isNothrow() {
-    var _a;
-    return (_a = this._nothrow) != null ? _a : this._snapshot.nothrow;
+    return this._snapshot.nothrow;
   }
   isHalted() {
-    return this.stage === "halted" && !this.isSync();
-  }
-  isSync() {
-    return this._snapshot[SYNC];
+    return this.stage === "halted" && !this.sync;
   }
   isSettled() {
     return !!this.output;
build/core.d.ts
@@ -71,20 +71,10 @@ type PipeMethod = {
 export declare class ProcessPromise extends Promise<ProcessOutput> {
     private _stage;
     private _id;
-    private _cmd;
-    private _from;
     private _snapshot;
-    private _stdio?;
-    private _nothrow?;
-    private _quiet?;
-    private _verbose?;
-    private _timeout?;
-    private _timeoutSignal?;
     private _timeoutId?;
     private _piped;
     private _pipedFrom?;
-    private _ee;
-    private _ac;
     private _stdin;
     private _zurk;
     private _output;
@@ -115,6 +105,7 @@ export declare class ProcessPromise extends Promise<ProcessOutput> {
     get ac(): AbortController;
     get output(): ProcessOutput | null;
     get stage(): ProcessStage;
+    get sync(): boolean;
     get [Symbol.toStringTag](): string;
     [Symbol.toPrimitive](): string;
     stdio(stdin: IOType, stdout?: IOType, stderr?: IOType): ProcessPromise;
@@ -124,14 +115,13 @@ export declare class ProcessPromise extends Promise<ProcessOutput> {
     timeout(d?: Duration, signal?: NodeJS.Signals | undefined): ProcessPromise;
     json<T = any>(): Promise<T>;
     text(encoding?: Encoding): Promise<string>;
-    lines(delimiter?: string | RegExp): Promise<string[]>;
+    lines(delimiter?: Options['delimiter']): Promise<string[]>;
     buffer(): Promise<Buffer>;
     blob(type?: string): Promise<Blob>;
     isQuiet(): boolean;
     isVerbose(): boolean;
     isNothrow(): boolean;
     isHalted(): boolean;
-    private isSync;
     private isSettled;
     private isRunning;
     then<R = ProcessOutput, E = ProcessOutput>(onfulfilled?: ((value: ProcessOutput) => PromiseLike<R> | R) | undefined | null, onrejected?: ((reason: ProcessOutput) => PromiseLike<E> | E) | undefined | null): Promise<R | E>;
build/esblib.cjs
@@ -57,6 +57,10 @@ var __async = (__this, __arguments, generator) => {
   });
 };
 
+var __defProps = Object.defineProperties;
+
+var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
+
 var __getOwnPropSymbols = Object.getOwnPropertySymbols;
 
 var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -81,6 +85,8 @@ var __spreadValues = (a, b) => {
   return a;
 };
 
+var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
+
 var __await = function(promise, isYieldStar) {
   this[0] = promise;
   this[1] = isYieldStar;
@@ -133,12 +139,6 @@ var __pow = Math.pow;
 
 var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
 
-var __defProps = Object.defineProperties;
-
-var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
-
-var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
-
 var __commonJS = (cb, mod) => function __require() {
   return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
 };
@@ -167,21 +167,21 @@ module.exports = {
   __toESM,
   __toCommonJS,
   __async,
+  __defProps,
+  __getOwnPropDescs,
   __getOwnPropSymbols,
   __propIsEnum,
   __knownSymbol,
   __typeError,
   __defNormalProp,
   __spreadValues,
+  __spreadProps,
   __await,
   __asyncGenerator,
   __yieldStar,
   __forAwait,
   __pow,
   __reExport,
-  __defProps,
-  __getOwnPropDescs,
-  __spreadProps,
   __commonJS,
   __esm,
   __accessCheck,
src/cli.ts
@@ -36,6 +36,8 @@ import { randomId } from './util.ts'
 import { transformMarkdown } from './md.ts'
 import { createRequire, type minimist } from './vendor.ts'
 
+export { transformMarkdown } from './md.ts'
+
 const EXT = '.mjs'
 const EXT_RE = /^\.[mc]?[jt]sx?$/
 
@@ -217,7 +219,7 @@ async function readScript() {
 }
 
 async function readScriptFromStdin(): Promise<string> {
-  return !process.stdin.isTTY ? stdin() : ''
+  return process.stdin.isTTY ? '' : stdin()
 }
 
 async function readScriptFromHttp(remote: string): Promise<string> {
@@ -229,8 +231,6 @@ async function readScriptFromHttp(remote: string): Promise<string> {
   return res.text()
 }
 
-export { transformMarkdown }
-
 export function injectGlobalRequire(origin: string): void {
   const __filename = path.resolve(origin)
   const __dirname = path.dirname(__filename)
src/core.ts
@@ -167,8 +167,27 @@ export interface Shell<
     (opts: Partial<Omit<Options, 'sync'>>): Shell<true>
   }
 }
-const boundCtxs: [string, string, Options][] = []
-const delimiters: Array<string | RegExp | undefined> = []
+const snapshots: Snapshot[] = []
+const delimiters: Options['delimiter'][] = []
+
+type Snapshot = Options & {
+  from: string
+  cmd: string
+  ee: EventEmitter
+  ac: AbortController
+}
+
+const getSnapshot = (
+  snapshot: Options,
+  from: string,
+  cmd: string
+): Snapshot => ({
+  ...snapshot,
+  ac: snapshot.ac || new AbortController(),
+  ee: new EventEmitter(),
+  from,
+  cmd,
+})
 
 export const $: Shell & Options = new Proxy<Shell & Options>(
   function (pieces: TemplateStringsArray | Partial<Options>, ...args: any[]) {
@@ -181,7 +200,7 @@ export const $: Shell & Options = new Proxy<Shell & Options>(
       }
     }
     const from = getCallerLocation()
-    if (pieces.some((p) => p == undefined))
+    if (pieces.some((p) => p == null))
       throw new Error(`Malformed command at ${from}`)
 
     checkShell()
@@ -192,12 +211,12 @@ export const $: Shell & Options = new Proxy<Shell & Options>(
       pieces as TemplateStringsArray,
       args
     ) as string
-    boundCtxs.push([cmd, from, snapshot])
-    const process = new ProcessPromise(noop)
+    snapshots.push(getSnapshot(snapshot, from, cmd))
+    const pp = new ProcessPromise(noop)
 
-    if (!process.isHalted()) process.run()
+    if (!pp.isHalted()) pp.run()
 
-    return process.output || process
+    return pp.sync ? pp.output : pp
   } as Shell & Options,
   {
     set(_, key, value) {
@@ -232,20 +251,10 @@ type PipeMethod = {
 export class ProcessPromise extends Promise<ProcessOutput> {
   private _stage: ProcessStage = 'initial'
   private _id = randomId()
-  private _cmd = ''
-  private _from = ''
-  private _snapshot = getStore()
-  private _stdio?: StdioOptions
-  private _nothrow?: boolean
-  private _quiet?: boolean
-  private _verbose?: boolean
-  private _timeout?: number
-  private _timeoutSignal?: NodeJS.Signals
+  private _snapshot!: Snapshot
   private _timeoutId?: ReturnType<typeof setTimeout>
   private _piped = false
   private _pipedFrom?: ProcessPromise
-  private _ee = new EventEmitter()
-  private _ac = new AbortController()
   private _stdin = new VoidStream()
   private _zurk: ReturnType<typeof exec> | null = null
   private _output: ProcessOutput | null = null
@@ -260,17 +269,14 @@ export class ProcessPromise extends Promise<ProcessOutput> {
       executor(...args)
     })
 
-    if (boundCtxs.length) {
-      const [cmd, from, snapshot] = boundCtxs.pop()!
-      this._cmd = cmd
-      this._from = from
-      this._snapshot = { ...snapshot }
+    if (snapshots.length) {
+      this._snapshot = snapshots.pop()!
       this._resolve = resolve!
       this._reject = (v: ProcessOutput) => {
         reject!(v)
-        if (this.isSync()) throw v
+        if (this.sync) throw v
       }
-      if (snapshot.halt) this._stage = 'halted'
+      if (this._snapshot.halt) this._stage = 'halted'
     } else ProcessPromise.disarm(this)
   }
 
@@ -282,8 +288,6 @@ export class ProcessPromise extends Promise<ProcessOutput> {
     const self = this
     const $ = self._snapshot
     const id = self.id
-    const timeout = self._timeout ?? $.timeout
-    const timeoutSignal = self._timeoutSignal ?? $.timeoutSignal
 
     if ($.preferLocal) {
       const dirs =
@@ -293,25 +297,25 @@ export class ProcessPromise extends Promise<ProcessOutput> {
 
     // prettier-ignore
     this._zurk = exec({
-      id,
-      sync:     self.isSync(),
       cmd:      self.fullCmd,
       cwd:      $.cwd ?? $[CWD],
       input:    ($.input as ProcessPromise | ProcessOutput)?.stdout ?? $.input,
+      stdin:    self._stdin,
+      sync:     self.sync,
       signal:   self.signal,
       shell:    isString($.shell) ? $.shell : true,
+      id,
       env:      $.env,
       spawn:    $.spawn,
       spawnSync:$.spawnSync,
       store:    $.store,
-      stdin:    self._stdin,
-      stdio:    self._stdio ?? $.stdio,
+      stdio:    $.stdio,
       detached: $.detached,
-      ee:       self._ee,
+      ee:       $.ee,
       run(cb, ctx){
         (self.cmd as unknown as Promise<string>).then?.(
-          _cmd => {
-            self._cmd = _cmd
+          cmd => {
+            $.cmd = cmd
             ctx.cmd = self.fullCmd
             cb()
           },
@@ -321,7 +325,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
       on: {
         start: () => {
           $.log({ kind: 'cmd', cmd: self.cmd, verbose: self.isVerbose(), id })
-          self.timeout(timeout, timeoutSignal)
+          self.timeout($.timeout, $.timeoutSignal)
         },
         stdout: (data) => {
           // If the process is piped, don't print its output.
@@ -341,7 +345,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
             error,
             duration,
             store,
-            from: self._from,
+            from: $.from,
           })
 
           $.log({ kind: 'end', signal, exitCode: status, duration, error, verbose: self.isVerbose(), id })
@@ -393,7 +397,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
       )
 
     this._piped = true
-    const ee = this._ee
+    const { ee } = this._snapshot
     const from = new VoidStream()
     const fill = () => {
       for (const chunk of this._zurk!.store[source]) from.write(chunk)
@@ -469,13 +473,12 @@ export class ProcessPromise extends Promise<ProcessOutput> {
   }
 
   get cmd(): string {
-    return this._cmd
+    return this._snapshot.cmd
   }
 
   get fullCmd(): string {
-    return (
-      (this._snapshot.prefix || '') + this.cmd + (this._snapshot.postfix || '')
-    )
+    const { prefix = '', postfix = '', cmd } = this._snapshot
+    return prefix + cmd + postfix
   }
 
   get child(): ChildProcess | undefined {
@@ -506,7 +509,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
   }
 
   get ac(): AbortController {
-    return this._snapshot.ac || this._ac
+    return this._snapshot.ac
   }
 
   get output(): ProcessOutput | null {
@@ -517,6 +520,10 @@ export class ProcessPromise extends Promise<ProcessOutput> {
     return this._stage
   }
 
+  get sync(): boolean {
+    return this._snapshot[SYNC]
+  }
+
   override get [Symbol.toStringTag](): string {
     return 'ProcessPromise'
   }
@@ -531,40 +538,35 @@ export class ProcessPromise extends Promise<ProcessOutput> {
     stdout: IOType = 'pipe',
     stderr: IOType = 'pipe'
   ): ProcessPromise {
-    this._stdio = [stdin, stdout, stderr]
+    this._snapshot.stdio = [stdin, stdout, stderr]
     return this
   }
 
   nothrow(v = true): ProcessPromise {
-    this._nothrow = v
+    this._snapshot.nothrow = v
     return this
   }
 
   quiet(v = true): ProcessPromise {
-    this._quiet = v
+    this._snapshot.quiet = v
     return this
   }
 
   verbose(v = true): ProcessPromise {
-    this._verbose = v
+    this._snapshot.verbose = v
     return this
   }
 
-  timeout(
-    d: Duration = 0,
-    signal = this._timeoutSignal || $.timeoutSignal
-  ): ProcessPromise {
+  timeout(d: Duration = 0, signal = $.timeoutSignal): ProcessPromise {
     if (this.isSettled()) return this
 
-    this._timeout = parseDuration(d)
-    this._timeoutSignal = signal
+    const $ = this._snapshot
+    $.timeout = parseDuration(d)
+    $.timeoutSignal = signal
 
     if (this._timeoutId) clearTimeout(this._timeoutId)
-    if (this._timeout && this.isRunning()) {
-      this._timeoutId = setTimeout(
-        () => this.kill(this._timeoutSignal),
-        this._timeout
-      )
+    if ($.timeout && this.isRunning()) {
+      this._timeoutId = setTimeout(() => this.kill($.timeoutSignal), $.timeout)
       this.finally(() => clearTimeout(this._timeoutId)).catch(noop)
     }
     return this
@@ -579,7 +581,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
     return this.then((o) => o.text(encoding))
   }
 
-  lines(delimiter?: string | RegExp): Promise<string[]> {
+  lines(delimiter?: Options['delimiter']): Promise<string[]> {
     return this.then((o) => o.lines(delimiter))
   }
 
@@ -593,23 +595,19 @@ export class ProcessPromise extends Promise<ProcessOutput> {
 
   // Status checkers
   isQuiet(): boolean {
-    return this._quiet ?? this._snapshot.quiet
+    return this._snapshot.quiet
   }
 
   isVerbose(): boolean {
-    return (this._verbose ?? this._snapshot.verbose) && !this.isQuiet()
+    return this._snapshot.verbose && !this.isQuiet()
   }
 
   isNothrow(): boolean {
-    return this._nothrow ?? this._snapshot.nothrow
+    return this._snapshot.nothrow
   }
 
   isHalted(): boolean {
-    return this.stage === 'halted' && !this.isSync()
-  }
-
-  private isSync(): boolean {
-    return this._snapshot[SYNC]
+    return this.stage === 'halted' && !this.sync
   }
 
   private isSettled(): boolean {
test/core.test.js
@@ -46,6 +46,7 @@ import {
   fetch,
 } from '../build/index.js'
 import { noop } from '../build/util.js'
+import { EventEmitter } from 'node:events'
 
 describe('core', () => {
   describe('resolveDefaults()', () => {
@@ -530,12 +531,16 @@ describe('core', () => {
         ProcessPromise.disarm(p, false)
         assert.equal(p.stage, 'initial')
 
-        p._cmd = 'echo foo'
-        p._from = 'test'
         p._resolve = resolve
         p._reject = reject
-        p._snapshot = { ...defaults }
         p._stage = 'halted'
+        p._snapshot = {
+          ...defaults,
+          ac: new AbortController(),
+          from: 'test',
+          cmd: 'echo foo',
+          ee: new EventEmitter(),
+        }
 
         assert.equal(p.stage, 'halted')
         p.run()
@@ -1021,6 +1026,16 @@ describe('core', () => {
           /Trying to kill a process without creating one/
         )
       })
+
+      test('throws if pid is empty', async () => {
+        const p = $({
+          spawn() {
+            return new EventEmitter()
+          },
+        })`echo foo`
+
+        assert.throws(() => p.kill(), /The process pid is undefined/)
+      })
     })
 
     describe('[Symbol.asyncIterator]', () => {
.size-limit.json
@@ -15,7 +15,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "121.801 kB",
+    "limit": "121.20 kB",
     "brotli": false,
     "gzip": false
   },
@@ -29,14 +29,14 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "812.60 kB",
+    "limit": "812.20 kB",
     "brotli": false,
     "gzip": false
   },
   {
     "name": "libdefs",
     "path": "build/*.d.ts",
-    "limit": "39.20 kB",
+    "limit": "39.00 kB",
     "brotli": false,
     "gzip": false
   },
@@ -62,7 +62,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "868.65 kB",
+    "limit": "868.002 kB",
     "brotli": false,
     "gzip": false
   }
package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "zx",
-  "version": "8.7.1",
+  "version": "8.7.2",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "zx",
-      "version": "8.7.1",
+      "version": "8.7.2",
       "license": "Apache-2.0",
       "bin": {
         "zx": "build/cli.js"
@@ -28,7 +28,7 @@
         "depseek": "0.4.1",
         "dts-bundle-generator": "9.5.1",
         "envapi": "0.2.3",
-        "esbuild": "0.25.7",
+        "esbuild": "0.25.8",
         "esbuild-node-externals": "1.18.0",
         "esbuild-plugin-entry-chunks": "0.1.15",
         "esbuild-plugin-extract-helpers": "0.0.6",
@@ -821,9 +821,9 @@
       }
     },
     "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.7.tgz",
-      "integrity": "sha512-uD0kKFHh6ETr8TqEtaAcV+dn/2qnYbH/+8wGEdY70Qf7l1l/jmBUbrmQqwiPKAQE6cOQ7dTj6Xr0HzQDGHyceQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
+      "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
       "cpu": [
         "ppc64"
       ],
@@ -838,9 +838,9 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.7.tgz",
-      "integrity": "sha512-Jhuet0g1k9rAJHrXGIh7sFknFuT4sfytYZpZpuZl7YKDhnPByVAm5oy2LEBmMbuYf3ejWVYCc2seX81Mk+madA==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
+      "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
       "cpu": [
         "arm"
       ],
@@ -855,9 +855,9 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.7.tgz",
-      "integrity": "sha512-p0ohDnwyIbAtztHTNUTzN5EGD/HJLs1bwysrOPgSdlIA6NDnReoVfoCyxG6W1d85jr2X80Uq5KHftyYgaK9LPQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
+      "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
       "cpu": [
         "arm64"
       ],
@@ -872,9 +872,9 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.7.tgz",
-      "integrity": "sha512-mMxIJFlSgVK23HSsII3ZX9T2xKrBCDGyk0qiZnIW10LLFFtZLkFD6imZHu7gUo2wkNZwS9Yj3mOtZD3ZPcjCcw==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
+      "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
       "cpu": [
         "x64"
       ],
@@ -889,9 +889,9 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.7.tgz",
-      "integrity": "sha512-jyOFLGP2WwRwxM8F1VpP6gcdIJc8jq2CUrURbbTouJoRO7XCkU8GdnTDFIHdcifVBT45cJlOYsZ1kSlfbKjYUQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
+      "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
       "cpu": [
         "arm64"
       ],
@@ -906,9 +906,9 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.7.tgz",
-      "integrity": "sha512-m9bVWqZCwQ1BthruifvG64hG03zzz9gE2r/vYAhztBna1/+qXiHyP9WgnyZqHgGeXoimJPhAmxfbeU+nMng6ZA==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
+      "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
       "cpu": [
         "x64"
       ],
@@ -923,9 +923,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.7.tgz",
-      "integrity": "sha512-Bss7P4r6uhr3kDzRjPNEnTm/oIBdTPRNQuwaEFWT/uvt6A1YzK/yn5kcx5ZxZ9swOga7LqeYlu7bDIpDoS01bA==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
+      "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
       "cpu": [
         "arm64"
       ],
@@ -940,9 +940,9 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.7.tgz",
-      "integrity": "sha512-S3BFyjW81LXG7Vqmr37ddbThrm3A84yE7ey/ERBlK9dIiaWgrjRlre3pbG7txh1Uaxz8N7wGGQXmC9zV+LIpBQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
+      "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
       "cpu": [
         "x64"
       ],
@@ -957,9 +957,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.7.tgz",
-      "integrity": "sha512-JZMIci/1m5vfQuhKoFXogCKVYVfYQmoZJg8vSIMR4TUXbF+0aNlfXH3DGFEFMElT8hOTUF5hisdZhnrZO/bkDw==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
+      "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
       "cpu": [
         "arm"
       ],
@@ -974,9 +974,9 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.7.tgz",
-      "integrity": "sha512-HfQZQqrNOfS1Okn7PcsGUqHymL1cWGBslf78dGvtrj8q7cN3FkapFgNA4l/a5lXDwr7BqP2BSO6mz9UremNPbg==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
+      "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
       "cpu": [
         "arm64"
       ],
@@ -991,9 +991,9 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.7.tgz",
-      "integrity": "sha512-9Jex4uVpdeofiDxnwHRgen+j6398JlX4/6SCbbEFEXN7oMO2p0ueLN+e+9DdsdPLUdqns607HmzEFnxwr7+5wQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
+      "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
       "cpu": [
         "ia32"
       ],
@@ -1008,9 +1008,9 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.7.tgz",
-      "integrity": "sha512-TG1KJqjBlN9IHQjKVUYDB0/mUGgokfhhatlay8aZ/MSORMubEvj/J1CL8YGY4EBcln4z7rKFbsH+HeAv0d471w==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
+      "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
       "cpu": [
         "loong64"
       ],
@@ -1025,9 +1025,9 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.7.tgz",
-      "integrity": "sha512-Ty9Hj/lx7ikTnhOfaP7ipEm/ICcBv94i/6/WDg0OZ3BPBHhChsUbQancoWYSO0WNkEiSW5Do4febTTy4x1qYQQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
+      "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
       "cpu": [
         "mips64el"
       ],
@@ -1042,9 +1042,9 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.7.tgz",
-      "integrity": "sha512-MrOjirGQWGReJl3BNQ58BLhUBPpWABnKrnq8Q/vZWWwAB1wuLXOIxS2JQ1LT3+5T+3jfPh0tyf5CpbyQHqnWIQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
+      "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
       "cpu": [
         "ppc64"
       ],
@@ -1059,9 +1059,9 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.7.tgz",
-      "integrity": "sha512-9pr23/pqzyqIZEZmQXnFyqp3vpa+KBk5TotfkzGMqpw089PGm0AIowkUppHB9derQzqniGn3wVXgck19+oqiOw==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
+      "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
       "cpu": [
         "riscv64"
       ],
@@ -1076,9 +1076,9 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.7.tgz",
-      "integrity": "sha512-4dP11UVGh9O6Y47m8YvW8eoA3r8qL2toVZUbBKyGta8j6zdw1cn9F/Rt59/Mhv0OgY68pHIMjGXWOUaykCnx+w==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
+      "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
       "cpu": [
         "s390x"
       ],
@@ -1093,9 +1093,9 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.7.tgz",
-      "integrity": "sha512-ghJMAJTdw/0uhz7e7YnpdX1xVn7VqA0GrWrAO2qKMuqbvgHT2VZiBv1BQ//VcHsPir4wsL3P2oPggfKPzTKoCA==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
+      "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
       "cpu": [
         "x64"
       ],
@@ -1110,9 +1110,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.7.tgz",
-      "integrity": "sha512-bwXGEU4ua45+u5Ci/a55B85KWaDSRS8NPOHtxy2e3etDjbz23wlry37Ffzapz69JAGGc4089TBo+dGzydQmydg==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
+      "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
       "cpu": [
         "arm64"
       ],
@@ -1127,9 +1127,9 @@
       }
     },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.7.tgz",
-      "integrity": "sha512-tUZRvLtgLE5OyN46sPSYlgmHoBS5bx2URSrgZdW1L1teWPYVmXh+QN/sKDqkzBo/IHGcKcHLKDhBeVVkO7teEA==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
+      "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
       "cpu": [
         "x64"
       ],
@@ -1144,9 +1144,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.7.tgz",
-      "integrity": "sha512-bTJ50aoC+WDlDGBReWYiObpYvQfMjBNlKztqoNUL0iUkYtwLkBQQeEsTq/I1KyjsKA5tyov6VZaPb8UdD6ci6Q==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
+      "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
       "cpu": [
         "arm64"
       ],
@@ -1161,9 +1161,9 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.7.tgz",
-      "integrity": "sha512-TA9XfJrgzAipFUU895jd9j2SyDh9bbNkK2I0gHcvqb/o84UeQkBpi/XmYX3cO1q/9hZokdcDqQxIi6uLVrikxg==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
+      "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
       "cpu": [
         "x64"
       ],
@@ -1178,9 +1178,9 @@
       }
     },
     "node_modules/@esbuild/openharmony-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.7.tgz",
-      "integrity": "sha512-5VTtExUrWwHHEUZ/N+rPlHDwVFQ5aME7vRJES8+iQ0xC/bMYckfJ0l2n3yGIfRoXcK/wq4oXSItZAz5wslTKGw==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
+      "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
       "cpu": [
         "arm64"
       ],
@@ -1195,9 +1195,9 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.7.tgz",
-      "integrity": "sha512-umkbn7KTxsexhv2vuuJmj9kggd4AEtL32KodkJgfhNOHMPtQ55RexsaSrMb+0+jp9XL4I4o2y91PZauVN4cH3A==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
+      "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
       "cpu": [
         "x64"
       ],
@@ -1212,9 +1212,9 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.7.tgz",
-      "integrity": "sha512-j20JQGP/gz8QDgzl5No5Gr4F6hurAZvtkFxAKhiv2X49yi/ih8ECK4Y35YnjlMogSKJk931iNMcd35BtZ4ghfw==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
+      "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
       "cpu": [
         "arm64"
       ],
@@ -1229,9 +1229,9 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.7.tgz",
-      "integrity": "sha512-4qZ6NUfoiiKZfLAXRsvFkA0hoWVM+1y2bSHXHkpdLAs/+r0LgwqYohmfZCi985c6JWHhiXP30mgZawn/XrqAkQ==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
+      "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
       "cpu": [
         "ia32"
       ],
@@ -1246,9 +1246,9 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.7.tgz",
-      "integrity": "sha512-FaPsAHTwm+1Gfvn37Eg3E5HIpfR3i6x1AIcla/MkqAIupD4BW3MrSeUqfoTzwwJhk3WE2/KqUn4/eenEJC76VA==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
+      "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
       "cpu": [
         "x64"
       ],
@@ -3778,9 +3778,9 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.25.7",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.7.tgz",
-      "integrity": "sha512-daJB0q2dmTzo90L9NjRaohhRWrCzYxWNFTjEi72/h+p5DcY3yn4MacWfDakHmaBaDzDiuLJsCh0+6LK/iX+c+Q==",
+      "version": "0.25.8",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
+      "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
       "dev": true,
       "hasInstallScript": true,
       "license": "MIT",
@@ -3791,32 +3791,32 @@
         "node": ">=18"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.25.7",
-        "@esbuild/android-arm": "0.25.7",
-        "@esbuild/android-arm64": "0.25.7",
-        "@esbuild/android-x64": "0.25.7",
-        "@esbuild/darwin-arm64": "0.25.7",
-        "@esbuild/darwin-x64": "0.25.7",
-        "@esbuild/freebsd-arm64": "0.25.7",
-        "@esbuild/freebsd-x64": "0.25.7",
-        "@esbuild/linux-arm": "0.25.7",
-        "@esbuild/linux-arm64": "0.25.7",
-        "@esbuild/linux-ia32": "0.25.7",
-        "@esbuild/linux-loong64": "0.25.7",
-        "@esbuild/linux-mips64el": "0.25.7",
-        "@esbuild/linux-ppc64": "0.25.7",
-        "@esbuild/linux-riscv64": "0.25.7",
-        "@esbuild/linux-s390x": "0.25.7",
-        "@esbuild/linux-x64": "0.25.7",
-        "@esbuild/netbsd-arm64": "0.25.7",
-        "@esbuild/netbsd-x64": "0.25.7",
-        "@esbuild/openbsd-arm64": "0.25.7",
-        "@esbuild/openbsd-x64": "0.25.7",
-        "@esbuild/openharmony-arm64": "0.25.7",
-        "@esbuild/sunos-x64": "0.25.7",
-        "@esbuild/win32-arm64": "0.25.7",
-        "@esbuild/win32-ia32": "0.25.7",
-        "@esbuild/win32-x64": "0.25.7"
+        "@esbuild/aix-ppc64": "0.25.8",
+        "@esbuild/android-arm": "0.25.8",
+        "@esbuild/android-arm64": "0.25.8",
+        "@esbuild/android-x64": "0.25.8",
+        "@esbuild/darwin-arm64": "0.25.8",
+        "@esbuild/darwin-x64": "0.25.8",
+        "@esbuild/freebsd-arm64": "0.25.8",
+        "@esbuild/freebsd-x64": "0.25.8",
+        "@esbuild/linux-arm": "0.25.8",
+        "@esbuild/linux-arm64": "0.25.8",
+        "@esbuild/linux-ia32": "0.25.8",
+        "@esbuild/linux-loong64": "0.25.8",
+        "@esbuild/linux-mips64el": "0.25.8",
+        "@esbuild/linux-ppc64": "0.25.8",
+        "@esbuild/linux-riscv64": "0.25.8",
+        "@esbuild/linux-s390x": "0.25.8",
+        "@esbuild/linux-x64": "0.25.8",
+        "@esbuild/netbsd-arm64": "0.25.8",
+        "@esbuild/netbsd-x64": "0.25.8",
+        "@esbuild/openbsd-arm64": "0.25.8",
+        "@esbuild/openbsd-x64": "0.25.8",
+        "@esbuild/openharmony-arm64": "0.25.8",
+        "@esbuild/sunos-x64": "0.25.8",
+        "@esbuild/win32-arm64": "0.25.8",
+        "@esbuild/win32-ia32": "0.25.8",
+        "@esbuild/win32-x64": "0.25.8"
       }
     },
     "node_modules/esbuild-node-externals": {
package.json
@@ -1,6 +1,6 @@
 {
   "name": "zx",
-  "version": "8.7.1",
+  "version": "8.7.2",
   "description": "A tool for writing better scripts",
   "type": "module",
   "main": "./build/index.cjs",
@@ -120,7 +120,7 @@
     "depseek": "0.4.1",
     "dts-bundle-generator": "9.5.1",
     "envapi": "0.2.3",
-    "esbuild": "0.25.7",
+    "esbuild": "0.25.8",
     "esbuild-node-externals": "1.18.0",
     "esbuild-plugin-entry-chunks": "0.1.15",
     "esbuild-plugin-extract-helpers": "0.0.6",